web/views/tabs.py
changeset 3589 a5432f99f2d9
parent 3460 e4843535db25
parent 3576 a9ed6f7cf2c2
child 3645 7272b793d7c9
equal deleted inserted replaced
3536:f6c9a5df80fb 3589:a5432f99f2d9
    13 from cubicweb import NoSelectableObject, role
    13 from cubicweb import NoSelectableObject, role
    14 from cubicweb.selectors import partial_has_related_entities
    14 from cubicweb.selectors import partial_has_related_entities
    15 from cubicweb.view import EntityView
    15 from cubicweb.view import EntityView
    16 from cubicweb.common import tags, uilib
    16 from cubicweb.common import tags, uilib
    17 from cubicweb.utils import make_uid
    17 from cubicweb.utils import make_uid
       
    18 from cubicweb.web.views import primary
    18 
    19 
    19 class LazyViewMixin(object):
    20 class LazyViewMixin(object):
    20     """provides two convenience methods for the tab machinery
    21     """provides two convenience methods for the tab machinery
    21     can also be used to lazy-load arbitrary views
    22     can also be used to lazy-load arbitrary views
    22     caveat : lazyview is not recursive, i.e : you can't (successfully)
    23     caveat : lazyview is not recursive, i.e : you can't (successfully)
    28   jQuery('#lazy-%(vid)s').bind('%(event)s', function(event) {
    29   jQuery('#lazy-%(vid)s').bind('%(event)s', function(event) {
    29      load_now('#lazy-%(vid)s', '#%(vid)s-hole', %(reloadable)s);
    30      load_now('#lazy-%(vid)s', '#%(vid)s-hole', %(reloadable)s);
    30   });""" % {'event': 'load_%s' % vid, 'vid': vid,
    31   });""" % {'event': 'load_%s' % vid, 'vid': vid,
    31             'reloadable' : str(reloadable).lower()})
    32             'reloadable' : str(reloadable).lower()})
    32 
    33 
    33     def lazyview(self, vid, rql=None, eid=None, rset=None, static=False,
    34     def lazyview(self, vid, rql=None, eid=None, rset=None, tabid=None,
    34                  reloadable=False, show_spinbox=True, w=None):
    35                  reloadable=False, show_spinbox=True, w=None):
    35         """a lazy version of wview
    36         """a lazy version of wview
    36         first version only support lazy viewing for an entity at a time
    37         first version only support lazy viewing for an entity at a time
    37         """
    38         """
    38         assert rql or eid or rset or static, \
       
    39             'lazyview wants at least : rql, or an eid, or an rset -- or call it with static=True'
       
    40         w = w or self.w
    39         w = w or self.w
    41         self._cw.add_js('cubicweb.lazy.js')
    40         self._cw.add_js('cubicweb.lazy.js')
    42         urlparams = {'vid' : vid, 'fname' : 'view'}
    41         urlparams = {'vid' : vid, 'fname' : 'view'}
    43         if rql:
    42         if rql:
    44             urlparams['rql'] = rql
    43             urlparams['rql'] = rql
    45         elif eid:
    44         elif eid:
    46             urlparams['rql'] = uilib.rql_for_eid(eid)
    45             urlparams['rql'] = uilib.rql_for_eid(eid)
    47         elif rset:
    46         elif rset:
    48             urlparams['rql'] = rset.printable_rql()
    47             urlparams['rql'] = rset.printable_rql()
    49         w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
    48         w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
    50             vid, xml_escape(self._cw.build_url('json', **urlparams))))
    49             tabid or vid, xml_escape(self._cw.build_url('json', **urlparams))))
    51         if show_spinbox:
    50         if show_spinbox:
    52             w(u'<img src="data/loading.gif" id="%s-hole" alt="%s"/>'
    51             w(u'<img src="data/loading.gif" id="%s-hole" alt="%s"/>'
    53               % (vid, self._cw._('loading')))
    52               % (tabid or vid, self._cw._('loading')))
    54         w(u'</div>')
    53         w(u'</div>')
    55         self._prepare_bindings(vid, reloadable)
    54         self._prepare_bindings(tabid or vid, reloadable)
    56 
    55 
    57     def forceview(self, vid):
    56     def forceview(self, vid):
    58         """trigger an event that will force immediate loading of the view
    57         """trigger an event that will force immediate loading of the view
    59         on dom readyness
    58         on dom readyness
    60         """
    59         """
    68 
    67 
    69     @property
    68     @property
    70     def cookie_name(self):
    69     def cookie_name(self):
    71         return str('%s_active_tab' % self._cw.config.appid)
    70         return str('%s_active_tab' % self._cw.config.appid)
    72 
    71 
    73     def active_tab(self, tabs, default):
    72     def active_tab(self, default):
    74         formtab = self._cw.form.get('tab')
    73         if 'tab' in self._cw.form:
    75         if formtab in tabs:
    74             return self._cw.form['tab']
    76             return formtab
       
    77         cookies = self._cw.get_cookie()
    75         cookies = self._cw.get_cookie()
    78         cookiename = self.cookie_name
    76         cookiename = self.cookie_name
    79         activetab = cookies.get(cookiename)
    77         activetab = cookies.get(cookiename)
    80         if activetab is None:
    78         if activetab is None:
    81             cookies[cookiename] = default
    79             cookies[cookiename] = default
    82             self._cw.set_cookie(cookies, cookiename)
    80             self._cw.set_cookie(cookies, cookiename)
    83             tab = default
    81             return default
    84         else:
    82         return activetab.value
    85             tab = activetab.value
    83 
    86         return tab in tabs and tab or default
    84     def prune_tabs(self, tabs, default_tab):
    87 
       
    88     def prune_tabs(self, tabs):
       
    89         selected_tabs = []
    85         selected_tabs = []
       
    86         may_be_active_tab = self.active_tab(default_tab)
       
    87         active_tab = default_tab
       
    88         viewsvreg = self._cw.vreg['views']
    90         for tab in tabs:
    89         for tab in tabs:
    91             try:
    90             try:
    92                 self._cw.vreg['views'].select(tab, self._cw, rset=self.cw_rset)
    91                 tabid, tabkwargs = tab
    93                 selected_tabs.append(tab)
    92                 tabkwargs = tabkwargs.copy()
       
    93             except ValueError:
       
    94                 tabid, tabkwargs = tab, {}
       
    95             tabkwargs.setdefault('rset', self.rset)
       
    96             vid = tabkwargs.get('vid', tabid)
       
    97             try:
       
    98                 viewsvreg.select(vid, self._cw, **tabkwargs)
       
    99                 selected_tabs.append((tabid, tabkwargs))
    94             except NoSelectableObject:
   100             except NoSelectableObject:
    95                 continue
   101                 continue
    96         return selected_tabs
   102             if tabid == may_be_active_tab:
       
   103                 active_tab = tabid
       
   104         return selected_tabs, active_tab
    97 
   105 
    98     def render_tabs(self, tabs, default, entity=None):
   106     def render_tabs(self, tabs, default, entity=None):
    99         # delegate to the default tab if there is more than one entity
   107         # delegate to the default tab if there is more than one entity
   100         # in the result set (tabs are pretty useless there)
   108         # in the result set (tabs are pretty useless there)
   101         if entity and len(self.cw_rset) > 1:
   109         if entity and len(self.cw_rset) > 1:
   103             return
   111             return
   104         self._cw.add_css('ui.tabs.css')
   112         self._cw.add_css('ui.tabs.css')
   105         self._cw.add_js(('ui.core.js', 'ui.tabs.js',
   113         self._cw.add_js(('ui.core.js', 'ui.tabs.js',
   106                          'cubicweb.ajax.js', 'cubicweb.tabs.js', 'cubicweb.lazy.js'))
   114                          'cubicweb.ajax.js', 'cubicweb.tabs.js', 'cubicweb.lazy.js'))
   107         # prune tabs : not all are to be shown
   115         # prune tabs : not all are to be shown
   108         tabs = self.prune_tabs(tabs)
   116         tabs, active_tab = self.prune_tabs(tabs, default)
   109         # select a tab
       
   110         active_tab = self.active_tab(tabs, default)
       
   111         # build the html structure
   117         # build the html structure
   112         w = self.w
   118         w = self.w
   113         uid = entity and entity.eid or make_uid('tab')
   119         uid = entity and entity.eid or make_uid('tab')
   114         w(u'<div id="entity-tabs-%s">' % uid)
   120         w(u'<div id="entity-tabs-%s">' % uid)
   115         w(u'<ul>')
   121         w(u'<ul>')
   116         for tab in tabs:
   122         active_tab_idx = None
       
   123         for i, (tabid, tabkwargs) in enumerate(tabs):
   117             w(u'<li>')
   124             w(u'<li>')
   118             w(u'<a href="#%s">' % tab)
   125             w(u'<a href="#%s">' % tabid)
   119             w(u'<span onclick="set_tab(\'%s\', \'%s\')">' % (tab, self.cookie_name))
   126             w(u'<span onclick="set_tab(\'%s\', \'%s\')">' % (tabid, self.cookie_name))
   120             w(self._cw._(tab))
   127             w(tabkwargs.pop('label', self._cw._(tabid)))
   121             w(u'</span>')
   128             w(u'</span>')
   122             w(u'</a>')
   129             w(u'</a>')
   123             w(u'</li>')
   130             w(u'</li>')
       
   131             if tabid == active_tab:
       
   132                 active_tab_idx = i
   124         w(u'</ul>')
   133         w(u'</ul>')
   125         w(u'</div>')
   134         w(u'</div>')
   126         for tab in tabs:
   135         for tabid, tabkwargs in tabs:
   127             w(u'<div id="%s">' % tab)
   136             w(u'<div id="%s">' % tabid)
   128             if entity:
   137             tabkwargs.setdefault('tabid', tabid)
   129                 self.lazyview(tab, eid=entity.eid)
   138             tabkwargs.setdefault('vid', tabid)
   130             else:
   139             tabkwargs.setdefault('rset', self.rset)
   131                 self.lazyview(tab, static=True)
   140             self.lazyview(**tabkwargs)
   132             w(u'</div>')
   141             w(u'</div>')
   133         # call the set_tab() JS function *after* each tab is generated
   142         # call the set_tab() JS function *after* each tab is generated
   134         # because the callback binding needs to be done before
   143         # because the callback binding needs to be done before
   135         # XXX make work history: true
   144         # XXX make work history: true
   136         self._cw.add_onload(u"""
   145         self._cw.add_onload(u"""
   137   jQuery('#entity-tabs-%(eeid)s > ul').tabs( { selected: %(tabindex)s });
   146   jQuery('#entity-tabs-%(eeid)s > ul').tabs( { selected: %(tabindex)s });
   138   set_tab('%(vid)s', '%(cookiename)s');
   147   set_tab('%(vid)s', '%(cookiename)s');
   139 """ % {'tabindex'   : tabs.index(active_tab),
   148 """ % {'tabindex'   : active_tab_idx,
   140        'vid'        : active_tab,
   149        'vid'        : active_tab,
   141        'eeid'       : (entity and entity.eid or uid),
   150        'eeid'       : (entity and entity.eid or uid),
   142        'cookiename' : self.cookie_name})
   151        'cookiename' : self.cookie_name})
   143 
   152 
   144 
   153 
   168         self.w(u'<div class="mainInfo">')
   177         self.w(u'<div class="mainInfo">')
   169         if self.title:
   178         if self.title:
   170             self.w(tags.h1(self._cw._(self.title)))
   179             self.w(tags.h1(self._cw._(self.title)))
   171         self.wview(self.vid, rset, 'noresult')
   180         self.wview(self.vid, rset, 'noresult')
   172         self.w(u'</div>')
   181         self.w(u'</div>')
       
   182 
       
   183 
       
   184 class TabedPrimaryView(TabsMixin, primary.PrimaryView):
       
   185     __abstract__ = True # don't register
       
   186 
       
   187     tabs = ['main_tab']
       
   188     default_tab = 'main_tab'
       
   189 
       
   190     def cell_call(self, row, col):
       
   191         entity = self.complete_entity(row, col)
       
   192         self.render_entity_title(entity)
       
   193         self.render_entity_metadata(entity)
       
   194         self.render_tabs(self.tabs, self.default_tab, entity)
       
   195 
       
   196 
       
   197 class PrimaryTab(primary.PrimaryView):
       
   198     id = 'main_tab'
       
   199     title = None
       
   200 
       
   201     def is_primary(self):
       
   202         return True
       
   203 
       
   204     def render_entity_title(self, entity):
       
   205         pass
       
   206 
       
   207     def render_entity_metadata(self, entity):
       
   208         pass
       
   209