nulib/web: ajout de redirect() et set_profile(). améliorer la lisibilité des arguments

This commit is contained in:
Jephté Clain 2018-05-07 10:49:00 +04:00
parent c58a6ccaf7
commit 1a3550ed9a
4 changed files with 174 additions and 96 deletions

View File

@ -46,14 +46,20 @@ def load(prefix=None, icons=True, charset="utf-8"):
################################################################################ ################################################################################
# Menu # Menu
NAVBAR_TYPE_MAP = {
'fixed': 'fixed-top',
'static': 'static-top',
}
class Menu(ui.Menu): class Menu(ui.Menu):
"""Un menu""" """Un menu"""
def __init__(self, title, mitems=None, profiles=None, def __init__(self, title, mitems=None, profiles=None,
id=None, p=None, c=None, t=None, **kw): id=None, in_profiles=None, css=None, navbar_type=None, **kw):
super(Menu, self).__init__(title, mitems, profiles, id, p, c, **kw) if navbar_type is None: navbar_type = kw.pop('t', None)
if t is None: t = 'static' super(Menu, self).__init__(title, mitems, profiles, id, in_profiles, css, **kw)
self.navbar_type = t if navbar_type is None: navbar_type = 'static'
self.navbar_type = navbar_type
def __mitem(self, mitem, sel_profile): def __mitem(self, mitem, sel_profile):
# ne pas afficher un menu qui n'est pas dans le bon profil # ne pas afficher un menu qui n'est pas dans le bon profil
@ -87,16 +93,20 @@ class Menu(ui.Menu):
lines.append(u"""</ul>""") lines.append(u"""</ul>""")
return lines return lines
def __call__(self, s=None, p=None, t=None): def render(self, select=None, profile=None, navbar_type=None, **kw):
if t is None: t = self.navbar_type if select is None: select = kw.pop('s', None)
if s is not None: self.select(s, p) if profile is None: profile = kw.pop('p', None)
if navbar_type is None: navbar_type = kw.pop('t', None)
if navbar_type is None: navbar_type = self.navbar_type
if select is not None: self.select(select, profile)
selection = self.get_mitem() selection = self.get_mitem()
lines = [] lines = []
if t == 'fixed' or t == 'fixed-top': if navbar_type == 'fixed' or navbar_type == 'fixed-top':
lines.append(u"""<style type="text/css">body { margin-top: 50px; }</style>""") lines.append(u"""<style type="text/css">body { margin-top: 50px; }</style>""")
css = u'' css = u''
css = ui.addclassif('navbar-fixed-top', t == 'fixed' or t == 'fixed-top', css) css = ui.addclassif('navbar-fixed-top', navbar_type == 'fixed' or navbar_type == 'fixed-top', css)
css = ui.addclassif('navbar-static-top', t == 'static' or t == 'static-top', css) css = ui.addclassif('navbar-static-top', navbar_type == 'static' or navbar_type == 'static-top', css)
if self.profiles is not None and self.sel_profile is not None: if self.profiles is not None and self.sel_profile is not None:
css = ui.addclassif('%s-profile' % self.sel_profile, None, css) css = ui.addclassif('%s-profile' % self.sel_profile, None, css)
css = ui.addclassif(self.css, None, css) css = ui.addclassif(self.css, None, css)
@ -145,10 +155,9 @@ class Menu(ui.Menu):
</div> </div>
</div>""") </div>""")
return u"\n".join(lines) return u"\n".join(lines)
def __unicode__(self): return self.render()
def __unicode__(self): return self() def set_menu(menu, **params):
def set_menu(menu):
"""Décorateur qui permet d'initialiser une instance de menu dans la session """Décorateur qui permet d'initialiser une instance de menu dans la session
""" """
def decorator(method): def decorator(method):
@ -159,16 +168,24 @@ def set_menu(menu):
return wrapper return wrapper
return decorator return decorator
def menu(id=None, p=None): def menu(id=None, profile=None, **params):
"""Décorateur qui permet de mettre à jour la sélection et le profil dans le menu """Décorateur qui permet de mettre à jour la sélection et le profil dans
le menu
par défaut, prendre le profil courant dans la session. le profil courant
est initialisé par le décorateur @set_profile
""" """
if profile is None: profile = params.pop('p', None)
def decorator(method): def decorator(method):
def wrapper(self, *args, **kw): def wrapper(self, *args, **kw):
session = _ensure_session(self) session = _ensure_session(self)
if 'menu' not in session: if 'menu' not in session:
raise ValueError("menu is required") raise ValueError("menu est requis")
sel_profile = profile
if sel_profile is None and 'profile' in session:
sel_profile = session.profile
if id is not None: if id is not None:
session.menu.select(id, p) session.menu.select(id, sel_profile)
return method(self, *args, **kw) return method(self, *args, **kw)
return wrapper return wrapper
return decorator return decorator
@ -229,64 +246,74 @@ class Alert(object):
action = None action = None
showtb = None showtb = None
def __init__(self, msg=None, e=Undef, t="error", c=False, x=None, action=None, showtb=True): def __init__(self, msg=None, exc_info=Undef, type="error", closeable=False, escape=None, action=None, showtb=True, **kw):
self(msg, e, t, c, x, action, showtb) self(msg, exc_info, type, closeable, escape, action, showtb, **kw)
def __call__(self, msg=Undef, exc_info=Undef, type=Undef, closeable=Undef, escape=Undef, action=Undef, showtb=Undef, **kw):
if exc_info is Undef: exc_info = kw.pop('e', Undef)
if type is Undef: type = kw.pop('t', Undef)
if closeable is Undef: closeable = kw.pop('c', Undef)
if escape is Undef: escape = kw.pop('x', Undef)
def __call__(self, msg=Undef, e=Undef, t=Undef, c=Undef, x=Undef, action=Undef, showtb=Undef):
if msg is Undef: if msg is Undef:
# si on ne spécifie pas de message, alors prendre la valeur actuelle # si on ne spécifie pas de message, alors prendre la valeur actuelle
msg = self.msg msg = self.msg
if e is Undef: e = self.exc_info if exc_info is Undef: exc_info = self.exc_info
else: else:
# si on spécifie un message, alors prendre aussi l'exception courante # si on spécifie un message, alors prendre aussi l'exception courante
if e is Undef: e = sys.exc_info() if exc_info is Undef: exc_info = sys.exc_info()
if e == (None, None, None): e = None if exc_info == (None, None, None): exc_info = None
if t is Undef: t = self.type if type is Undef: type = self.type
if c is Undef: c = self.closeable if closeable is Undef: closeable = self.closeable
if x is Undef: x = self.escape if escape is Undef: escape = self.escape
if action is Undef: action = self.action if action is Undef: action = self.action
if showtb is Undef: showtb = self.showtb if showtb is Undef: showtb = self.showtb
self.msg = msg self.msg = msg
self.exc_info = e self.exc_info = exc_info
self.type = ALERT_TYPE_MAP.get(t, t) self.type = ALERT_TYPE_MAP.get(type, type)
self.closeable = c self.closeable = closeable
self.escape = x self.escape = escape
self.action = action self.action = action
self.showtb = showtb self.showtb = showtb
return self return self
def render(self, msg=Undef, e=Undef, t=Undef, c=Undef, x=Undef, action=Undef, showtb=Undef): def render(self, msg=Undef, exc_info=Undef, type=Undef, closeable=Undef, escape=Undef, action=Undef, showtb=Undef, **kw):
if exc_info is Undef: exc_info = kw.pop('e', Undef)
if type is Undef: type = kw.pop('t', Undef)
if closeable is Undef: closeable = kw.pop('c', Undef)
if escape is Undef: escape = kw.pop('x', Undef)
if msg is Undef: if msg is Undef:
# si on ne spécifie pas de message, alors prendre la valeur initiale # si on ne spécifie pas de message, alors prendre la valeur initiale
msg = self.msg msg = self.msg
if e is Undef: e = self.exc_info if exc_info is Undef: exc_info = self.exc_info
else: else:
# si on spécifie un message, alors prendre aussi l'exception courante # si on spécifie un message, alors prendre aussi l'exception courante
if e is Undef: e = sys.exc_info() if exc_info is Undef: exc_info = sys.exc_info()
if t is Undef: t = self.type if type is Undef: type = self.type
if c is Undef: c = self.closeable if closeable is Undef: closeable = self.closeable
if x is Undef: x = self.escape if escape is Undef: escape = self.escape
if action is Undef: action = self.action if action is Undef: action = self.action
if showtb is Undef: showtb = self.showtb if showtb is Undef: showtb = self.showtb
if callable(msg): if callable(msg):
# si msg est callable, par défaut ne pas mettre le résultat en # si msg est callable, par défaut ne pas mettre le résultat en
# échappement # échappement
if x is None: x = False if escape is None: escape = False
msg = msg() msg = msg()
if x is None: x = True if escape is None: escape = True
if msg is None and e is not None: if msg is None and exc_info is not None:
msg = u"Une erreur inattendue s'est produite" msg = u"Une erreur inattendue s'est produite"
if msg is None: return u"" if msg is None: return u""
if x: msg = web.websafe(msg) if escape: msg = web.websafe(msg)
lines = [] lines = []
css = u"alert alert-%s" % t css = u"alert alert-%s" % ALERT_TYPE_MAP.get(type, type)
css = ui.addclassif("alert-dismissible", c, css) css = ui.addclassif("alert-dismissible", closeable, css)
lines.append(u"""<div class="%s" role="alert">""" % css) lines.append(u"""<div class="%s" role="alert">""" % css)
if c: if closeable:
lines.append(u"""<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>""") lines.append(u"""<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>""")
lines.append(p(msg)) lines.append(p(msg))
if action is not None: if action is not None:
@ -296,19 +323,19 @@ class Alert(object):
title = web.websafe(action.title or u"Cliquez ici pour continuer") title = web.websafe(action.title or u"Cliquez ici pour continuer")
action = u"""<p><a href="%s" accesskey="r">%s</a></p>""" % (url, title) action = u"""<p><a href="%s" accesskey="r">%s</a></p>""" % (url, title)
lines.append(p(action)) lines.append(p(action))
if e is not None: if exc_info is not None:
lines.append(u"""<div class="small" style="margin-top: 3em; color: gray;">Pour information, le message d'erreur technique est&nbsp;&nbsp;&nbsp;""") lines.append(u"""<div class="small" style="margin-top: 3em; color: gray;">Pour information, le message d'erreur technique est&nbsp;&nbsp;&nbsp;""")
lines.extend(traceback.format_exception_only(*e[:2])) lines.extend(traceback.format_exception_only(*exc_info[:2]))
if showtb: if showtb:
lines.append(u"<!--") lines.append(u"<!--")
lines.append("".join(traceback.format_exception(*e))) lines.append("".join(traceback.format_exception(*exc_info)))
lines.append(u"-->") lines.append(u"-->")
lines.append(u"""</div>""") lines.append(u"""</div>""")
lines.append(u"""</div>""") lines.append(u"""</div>""")
return u"\n".join([u(line) for line in lines]) return u"\n".join([u(line) for line in lines])
def __unicode__(self): return self.render() def __unicode__(self): return self.render()
def set_alert(template=None, action=Undef, delay=None): def set_alert(template=None, action=Undef, delay=None, **params):
"""Décorateur qui permet de gérer automatiquement une instance de Alert dans la """Décorateur qui permet de gérer automatiquement une instance de Alert dans la
page. page.
@ -357,10 +384,14 @@ def set_alert(template=None, action=Undef, delay=None):
lines.append(u"""\ lines.append(u"""\
<title>%(title)s</title> <title>%(title)s</title>
</head> </head>
<body> <body>""" % locals())
if web.config.have_session:
session = web.config._session
if 'menu' in session: lines.append(session.menu.render())
lines.append(u"""\
<div class="container"> <div class="container">
<h1>%(title)s</h1>""" % locals()) <h1>%(title)s</h1>""" % locals())
lines.append(alert()) lines.append(alert.render())
lines.append(u"""\ lines.append(u"""\
</div> </div>
</body> </body>

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 # -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
__all__ = ( __all__ = (
'nocache', 'auth', 'defaults', 'nocache', 'auth', 'defaults', 'redirect',
'reset_session', 'set_session', 'session', 'check_session', 'reset_session', 'set_session', 'session', 'check_session',
'set_profile',
'Page', 'Application', 'Page', 'Application',
) )
@ -45,7 +46,7 @@ class MetaPage(type):
_fix_PATH(cls, name) _fix_PATH(cls, name)
HANDLER_CLASSES.append(cls) HANDLER_CLASSES.append(cls)
def nocache(method): def nocache(method, **params):
"""Décorateur pour s'assurer que le résultat de la méthode web n'est pas mis en cache """Décorateur pour s'assurer que le résultat de la méthode web n'est pas mis en cache
""" """
def wrapper(self, *args, **kw): def wrapper(self, *args, **kw):
@ -55,7 +56,7 @@ def nocache(method):
return method(self, *args, **kw) return method(self, *args, **kw)
return wrapper return wrapper
def auth(authenticator=None, realm='nulib'): def auth(authenticator=None, realm='nulib', **params):
"""Décorateur pour s'assurer que la méthode web est authentifiée. """Décorateur pour s'assurer que la méthode web est authentifiée.
La fonction authenticator avec la signature (username, password) permet La fonction authenticator avec la signature (username, password) permet
@ -75,6 +76,22 @@ def auth(authenticator=None, realm='nulib'):
return wrapper return wrapper
return decorator return decorator
def redirect(desturl, **params):
"""rediriger vers l'url spécifiée si la méthode retourne None.
L'url est enregistrée dans l'objet avec le nom desturl au cas on
voudrait s'en servir dans la page retournée.
"""
def decorator(method):
def wrapper(self, *args, **kw):
self.desturl = desturl
self.desturl_params = params
result = method(self, *args, **kw)
if result is not None: return result
else: return web.redirect(web.url(desturl, **params))
return wrapper
return decorator
def defaults(*required, **defaults): def defaults(*required, **defaults):
"""Initialiser dans l'objet courant des variables à des valeurs par """Initialiser dans l'objet courant des variables à des valeurs par
défaut, ou en les prenant parmi les paramètres de la requête. défaut, ou en les prenant parmi les paramètres de la requête.
@ -207,6 +224,22 @@ def check_session(_onerror=None, **validators):
return wrapper return wrapper
return decorator return decorator
def set_profile(profile=None, **params):
"""mettre à jour la valeur du profil courant
s'assurer que l'objet courant contient la variable session. si les sessions
n'ont pas été configurées au niveau de l'application, une exception est
levée
"""
if profile is None: profile = params.pop('p', None)
def decorator(method):
def wrapper(self, *args, **kw):
session = _ensure_session(self)
session.profile = profile
return method(self, *args, **kw)
return wrapper
return decorator
def _fix_PATH(cls, name): def _fix_PATH(cls, name):
if cls.PATH is None: if cls.PATH is None:
if cls.PREFIX is None: if cls.PREFIX is None:
@ -491,6 +524,8 @@ class Application(object):
session = web.session.Session(self.webapp, store, initializer=initializer) session = web.session.Session(self.webapp, store, initializer=initializer)
self.session = web.config._session = session self.session = web.config._session = session
web.config.have_session = session is not None
tg = self.template_globals tg = self.template_globals
# session et application comme variables globales du template # session et application comme variables globales du template
tg.setdefault("S", session) tg.setdefault("S", session)
@ -529,7 +564,7 @@ class Application(object):
if args is None: args = [] if args is None: args = []
options, args = get_args(map(_u, args), options, args = get_args(map(_u, args),
'S:s:H:P:Dp:' + (self.OPTIONS or ''), 'S:s:H:P:Dp:' + (self.OPTIONS or ''),
['server-type=', 'server-socket=', 'host=', 'port=', 'debug', 'profile='] + list(self.LONG_OPTIONS or ())) ['server-type=', 'server-socket=', 'host=', 'port=', 'debug', 'no-debug', 'profile='] + list(self.LONG_OPTIONS or ()))
server_type = None server_type = None
server_socket = None server_socket = None
for option, value in options: for option, value in options:
@ -542,6 +577,8 @@ class Application(object):
elif option in ('-D', '--debug'): elif option in ('-D', '--debug'):
self.DEBUG = True self.DEBUG = True
set_verbosity('--debug') set_verbosity('--debug')
elif option in ('--no-debug',):
self.DEBUG = False
elif option in ('-p', '--profile'): self.PROFILE = value elif option in ('-p', '--profile'): self.PROFILE = value
self.args = args self.args = args
self.process_args(args) self.process_args(args)

View File

@ -82,11 +82,11 @@ class Action(odict):
url: cible de l'action ou du lien (avec querystring) url: cible de l'action ou du lien (avec querystring)
title: titre du lien ou de l'élément de menu title: titre du lien ou de l'élément de menu
id: identifiant dans un menu id: identifiant dans un menu
p (in_profiles): profils dans lequel l'action est valide. le premier profil in_profiles (p): profils dans lequel l'action est valide. le premier profil
est le profil par défaut est le profil par défaut
c (css): classe css à appliquer au lien css (c): classe css à appliquer au lien
ak (accesskey): accesskey à installer sur le lien accesskey (ak): accesskey à installer sur le lien
q (query): paramètres de la requête, sous forme de dictionnaire ou de chaine query (q): paramètres de la requête, sous forme de dictionnaire ou de chaine
method: type de requête, get ou post method: type de requête, get ou post
PROFILE_url, PROFILE_query: valeurs spécifiques à certains profils, PROFILE PROFILE_url, PROFILE_query: valeurs spécifiques à certains profils, PROFILE
étant une valeur de in_profiles étant une valeur de in_profiles
@ -121,74 +121,79 @@ class Action(odict):
self[querykey] = query self[querykey] = query
self[urlkey] = url self[urlkey] = url
def __init__(self, url, title=None, id=None, p=None, c=None, ak=None, q=None, method=None, **kw): def __init__(self, url, title=None, id=None, in_profiles=None, css=None, accesskey=None, query=None, method=None, **kw):
super(Action, self).__init__(**kw) super(Action, self).__init__(**kw)
if isseq(url): if isseq(url):
if url[1:2]: title = url[1] if url[1:2]: title = url[1]
if url[2:3]: id = url[2] if url[2:3]: id = url[2]
if url[3:4]: p = url[3] if url[3:4]: in_profiles = url[3]
if url[4:5]: c = url[4] if url[4:5]: css = url[4]
if url[5:6]: ak = url[5] if url[5:6]: accesskey = url[5]
if url[6:7]: method = url[6] if url[6:7]: method = url[6]
url = url[0] if url[0:1] else None url = url[0] if url[0:1] else None
if url is None: raise ValueError("url is required") if url is None: raise ValueError("url is required")
if title is None: title = url if title is None: title = url
if p is None: p = kw.get('in_profiles', None) if in_profiles is None: in_profiles = kw.pop('p', None)
if c is None: c = kw.get('css', None) if css is None: css = kw.pop('c', None)
if ak is None: ak = kw.get('accesskey', None) if accesskey is None: accesskey = kw.pop('ak', None)
if q is None: q = kw.get('query', None) if query is None: query = kw.pop('q', None)
if method is None: method = 'get' if method is None: method = 'get'
self.title = title self.title = title
self.id = id self.id = id
self.css = c self.css = css
self.accesskey = ak self.accesskey = accesskey
self.method = method self.method = method
self.url = url self.url = url
self.query = q self.query = query
self.__update_url('url', 'query', 'baseurl') self.__update_url('url', 'query', 'baseurl')
self.in_profiles = seqof(p, None) self.in_profiles = seqof(in_profiles, None)
if self.in_profiles is None: return if self.in_profiles is None: return
for p in self.in_profiles: for profile in self.in_profiles:
self.__update_url(*['%s_%s' % (p, key) for key in ('url', 'query', 'baseurl')]) self.__update_url(*['%s_%s' % (profile, key) for key in ('url', 'query', 'baseurl')])
self.__update_url(*['to_%s_%s' % (p, key) for key in ('url', 'query', 'baseurl')]) self.__update_url(*['to_%s_%s' % (profile, key) for key in ('url', 'query', 'baseurl')])
def __get_key(self, key, p=None, to=False): def __get_key(self, key, profile=None, to=False):
if p is not None: if profile is not None:
pkey = '%s%s_%s' % ('to_' if to else '', p, key) pkey = '%s%s_%s' % ('to_' if to else '', profile, key)
value = self.get(pkey, None) value = self.get(pkey, None)
if value is not None: return value if value is not None: return value
return self[key] return self[key]
def get_baseurl(self, p=None, to=False): def get_baseurl(self, profile=None, to=False, **kw):
"""obtenir l'url de base """obtenir l'url de base
""" """
return self.__get_key('baseurl', p, to) if profile is None: profile = kw.pop('p', None)
def get_query(self, p=None, to=False): return self.__get_key('baseurl', profile, to)
def get_query(self, profile=None, to=False, **kw):
"""obtenir les paramètres de la requête sous forme de dictionnaire """obtenir les paramètres de la requête sous forme de dictionnaire
""" """
return self.__get_key('query', p, to) if profile is None: profile = kw.pop('p', None)
def get_url(self, p=None, to=False): return self.__get_key('query', profile, to)
def get_url(self, profile=None, to=False, **kw):
"""obtenir l'url """obtenir l'url
""" """
return self.__get_key('url', p, to) if profile is None: profile = kw.pop('p', None)
return self.__get_key('url', profile, to)
def get_qs(self, p=None, to=False, sep=None): def get_qs(self, profile=None, to=False, sep=None, **kw):
"""obtenir les paramètres de la requête sous forme de query-string """obtenir les paramètres de la requête sous forme de query-string
sep vaut par défaut '?' mais peut valoir '&' sep vaut par défaut '?' mais peut valoir '&'
""" """
query = self.get_query(p, to) if profile is None: profile = kw.pop('p', None)
query = self.get_query(profile, to)
if sep is None: sep = '?' if sep is None: sep = '?'
return '%s%s' % (sep, urllib.urlencode(query, True)) return '%s%s' % (sep, urllib.urlencode(query, True))
qs = property(get_qs) qs = property(get_qs)
get_querystring = get_qs; querystring = property(get_qs) get_querystring = get_qs; querystring = property(get_qs)
def get_inputs(self, p=None, to=False): def get_inputs(self, profile=None, to=False, **kw):
"""obtenir les paramètres de la requête sous forme d'une liste de définitions """obtenir les paramètres de la requête sous forme d'une liste de définitions
d'éléments de formulaire de type hidden d'éléments de formulaire de type hidden
""" """
query = self.get_query(p, to) if profile is None: profile = kw.pop('p', None)
query = self.get_query(profile, to)
Hidden = web.form.Hidden Hidden = web.form.Hidden
inputs = [] inputs = []
for name, value in query.items(): for name, value in query.items():
@ -212,7 +217,9 @@ class Menu(odict):
return nextid return nextid
def __init__(self, title, mitems=None, profiles=None, def __init__(self, title, mitems=None, profiles=None,
id=None, p=None, c=None, **kw): id=None, in_profiles=None, css=None, **kw):
if in_profiles is None: in_profiles = kw.pop('p', None)
if css is None: css = kw.pop('c', None)
super(Menu, self).__init__(**kw) super(Menu, self).__init__(**kw)
self.__dict__['nextid'] = 0 self.__dict__['nextid'] = 0
self.__dict__['idmap'] = {} self.__dict__['idmap'] = {}
@ -225,7 +232,7 @@ class Menu(odict):
self.default_profile = profiles[0] if profiles is not None else None self.default_profile = profiles[0] if profiles is not None else None
self.id = str(id) self.id = str(id)
self.in_profiles = seqof(p, None) self.in_profiles = seqof(p, None)
self.css = c self.css = css
self.sel_id = None self.sel_id = None
self.sel_profile = None self.sel_profile = None
self.active = False self.active = False
@ -244,7 +251,7 @@ class Menu(odict):
self.mitems.append(mitem) self.mitems.append(mitem)
self.idmap[mitem.id] = mitem self.idmap[mitem.id] = mitem
def reset_selection(self): def reset_selection(self, **kw):
self.sel_id = None self.sel_id = None
self.sel_profile = self.default_profile self.sel_profile = self.default_profile
self.active = False self.active = False
@ -254,7 +261,8 @@ class Menu(odict):
else: else:
mitem.active = False mitem.active = False
def select(self, id, p=None): def select(self, id, profile=None, **kw):
if profile is None: profile = kw.pop('p', None)
# d'abord déselectionner tout le monde # d'abord déselectionner tout le monde
self.reset_selection() self.reset_selection()
# ensuite chercher le mitem à sélectionner # ensuite chercher le mitem à sélectionner
@ -262,10 +270,10 @@ class Menu(odict):
mitem = self.idmap.get(id, None) mitem = self.idmap.get(id, None)
if mitem is not None: if mitem is not None:
self.sel_id = id self.sel_id = id
if p is None and mitem.in_profiles: if profile is None and mitem.in_profiles:
p = mitem.in_profiles[0] profile = mitem.in_profiles[0]
if p is None: p = self.default_profile if profile is None: profile = self.default_profile
self.sel_profile = p self.sel_profile = profile
mitem.active = self.active = True mitem.active = self.active = True
return True return True
else: else:
@ -278,7 +286,7 @@ class Menu(odict):
return True return True
return False return False
def get_mitem(self, id=None): def get_mitem(self, id=None, **kw):
"""retourner l'élément de menu correspondant à la sélection courante """retourner l'élément de menu correspondant à la sélection courante
""" """
if id is None: id = self.sel_id if id is None: id = self.sel_id

View File

@ -2,11 +2,13 @@
__all__ = ( __all__ = (
'web', 'Page', 'bs', 'web', 'Page', 'bs',
'nocache', 'auth', 'defaults', 'nocache', 'auth', 'defaults', 'redirect',
'reset_session', 'set_session', 'session', 'check_session', 'reset_session', 'set_session', 'session', 'check_session',
'set_profile',
'config', 'config',
) )
from nulib.web import web, Page, bs, nocache, auth, defaults from nulib.web import web, Page, bs, nocache, auth, defaults, redirect
from nulib.web import reset_session, set_session, session, check_session from nulib.web import reset_session, set_session, session, check_session
from nulib.web import set_profile
from nulib.web.config_loader import config from nulib.web.config_loader import config