web/views/treeview.py
branchtreeview-tabs
changeset 916 968f00dd9a24
parent 472 958805c342b6
child 918 19862a0e55a5
equal deleted inserted replaced
915:d7f85fd197df 916:968f00dd9a24
     1 from logilab.mtconverter import html_escape
     1 from logilab.mtconverter import html_escape
     2 
       
     3 from cubicweb.interfaces import ITree
     2 from cubicweb.interfaces import ITree
     4 from cubicweb.common.selectors import implement_interface, yes
     3 from cubicweb.common.selectors import implement_interface, yes
     5 from cubicweb.common.view import EntityView
     4 from cubicweb.common.view import EntityView
     6 
       
     7 from cubicweb.web.views.baseviews import OneLineView
       
     8 
     5 
     9 class TreeView(EntityView):
     6 class TreeView(EntityView):
    10     id = 'treeview'
     7     id = 'treeview'
    11     accepts = ('Any',)
     8     accepts = ('Any',)
    12     itemvid = 'treeitemview'
     9     itemvid = 'treeitemview'
    13     css_classes = 'treeview widget'
    10     css_classes = 'treeview widget'
    14     title = _('tree view')
    11     title = _('tree view')
    15     
    12 
    16     def call(self, subvid=None):
    13     def call(self, subvid=None, treeid=None):
    17         if subvid is None and 'subvid' in self.req.form:
    14         if subvid is None and 'subvid' in self.req.form:
    18             subvid = self.req.form.pop('subvid') # consume it
    15             subvid = self.req.form.pop('subvid') # consume it
    19         if subvid is None:
    16         if subvid is None:
    20             subvid = 'oneline'
    17             subvid = 'oneline'
    21         self.req.add_css('jquery.treeview.css')
    18         self.req.add_css('jquery.treeview.css')
    22         self.req.add_js(('cubicweb.ajax.js', 'jquery.treeview.js', 'cubicweb.widgets.js'))
    19         self.req.add_js(('cubicweb.ajax.js', 'jquery.treeview.js'))
    23         # XXX noautoload is a quick hack to avoid treeview to be rebuilt
    20         # XXX find a way, an id is MANDATORY
    24         #     after a json query and avoid double toggling bugs.
    21         treeid = 'TREE' #treeid or self.rset.rows[0][0]
    25         #     Need to find a way to do that cleanly.
    22         self.req.html_headers.add_onload(u"""
    26         if 'noautoload' in self.req.form:
    23              $("#tree-%s").treeview({toggle: toggleTree,
    27             self.w(u'<ul class="%s" cubicweb:wdgtype="TreeView">' % self.css_classes)
    24 		                     prerendered: true});""" % treeid)
    28         else:
    25         self.w(u'<ul id="tree-%s" class="%s">' % (treeid, self.css_classes))
    29             self.w(u'<ul class="%s" cubicweb:loadtype="auto" cubicweb:wdgtype="TreeView">'
       
    30                    % self.css_classes)
       
    31         for rowidx in xrange(len(self.rset)):
    26         for rowidx in xrange(len(self.rset)):
    32             self.wview(self.itemvid, self.rset, row=rowidx, col=0,
    27             self.wview(self.itemvid, self.rset, row=rowidx, col=0,
    33                        vid=subvid, parentvid=self.id)
    28                        vid=subvid, parentvid=self.id)
    34         self.w(u'</ul>')
    29         self.w(u'</ul>')
    35         
       
    36 
    30 
    37 class FileTreeView(TreeView):
    31 class FileTreeView(TreeView):
    38     """specific version of the treeview to display file trees
    32     """specific version of the treeview to display file trees
    39     """
    33     """
    40     id = 'filetree'
    34     id = 'filetree'
    41     css_classes = 'treeview widget filetree'
    35     css_classes = 'treeview widget filetree'
    42     title = _('file tree view')
    36     title = _('file tree view')
    43 
    37 
    44     def call(self, subvid=None):
    38     def call(self, subvid=None):
    45         super(FileTreeView, self).call(subvid='filetree-oneline')
    39         super(FileTreeView, self).call(subvid='filetree-oneline')
    46 
       
    47 
       
    48 
    40 
    49 class FileItemInnerView(EntityView):
    41 class FileItemInnerView(EntityView):
    50     """inner view used by the TreeItemView instead of oneline view
    42     """inner view used by the TreeItemView instead of oneline view
    51 
    43 
    52     This view adds an enclosing <span> with some specific CSS classes
    44     This view adds an enclosing <span> with some specific CSS classes
    55     id = 'filetree-oneline'
    47     id = 'filetree-oneline'
    56 
    48 
    57     def cell_call(self, row, col):
    49     def cell_call(self, row, col):
    58         entity = self.entity(row, col)
    50         entity = self.entity(row, col)
    59         if ITree.is_implemented_by(entity.__class__) and not entity.is_leaf():
    51         if ITree.is_implemented_by(entity.__class__) and not entity.is_leaf():
    60             self.w(u'<div class="folder">%s</div>' % entity.view('oneline'))
    52             self.w(u'<div class="folder">%s</div>\n' % entity.view('oneline'))
    61         else:
    53         else:
    62             # XXX define specific CSS classes according to mime types
    54             # XXX define specific CSS classes according to mime types
    63             self.w(u'<div class="file">%s</div>' % entity.view('oneline'))
    55             self.w(u'<div class="file">%s</div>\n' % entity.view('oneline'))
    64 
    56 
    65 
    57 
    66 class DefaultTreeViewItemView(EntityView):
    58 class DefaultTreeViewItemView(EntityView):
    67     """default treeitem view for entities which don't implement ITree
    59     """default treeitem view for entities which don't implement ITree
    68     """
    60     """
    69     id = 'treeitemview'
    61     id = 'treeitemview'
    70     accepts = ('Any',)
    62     accepts = ('Any',)
    71     
    63 
    72     def cell_call(self, row, col, vid='oneline', parentvid='treeview'):
    64     def cell_call(self, row, col, vid='oneline', parentvid='treeview'):
    73         entity = self.entity(row, col)
    65         entity = self.entity(row, col)
    74         itemview = self.view(vid, self.rset, row=row, col=col)
    66         itemview = self.view(vid, self.rset, row=row, col=col)
    75         if row == len(self.rset) - 1:
    67         if row == len(self.rset) - 1:
    76             self.w(u'<li class="last">%s</li>' % itemview)
    68             self.w(u'<li class="last">%s</li>' % itemview)
    78             self.w(u'<li>%s</li>' % itemview)
    70             self.w(u'<li>%s</li>' % itemview)
    79 
    71 
    80 
    72 
    81 class TreeViewItemView(EntityView):
    73 class TreeViewItemView(EntityView):
    82     """specific treeitem view for entities which implement ITree
    74     """specific treeitem view for entities which implement ITree
    83     
    75 
    84     (each item should be exandable if it's not a tree leaf)
    76     (each item should be exandable if it's not a tree leaf)
    85     """
    77     """
    86     id = 'treeitemview'
    78     id = 'treeitemview'
    87     # XXX append yes to make sure we get an higher score than
    79     # XXX append yes to make sure we get an higher score than
    88     #     the default treeitem view
    80     #     the default treeitem view
    89     __selectors__ = (implement_interface, yes)
    81     __selectors__ = (implement_interface, yes)
    90     accepts_interfaces = (ITree,)
    82     accepts_interfaces = (ITree,)
    91     
    83     opening = 'man_a/a1'.split('/')
       
    84 
    92     def cell_call(self, row, col, vid='oneline', parentvid='treeview'):
    85     def cell_call(self, row, col, vid='oneline', parentvid='treeview'):
       
    86         w = self.w
    93         entity = self.entity(row, col)
    87         entity = self.entity(row, col)
    94         cssclasses = []
    88         liclasses = []
    95         is_leaf = False
    89         is_leaf = False
       
    90         is_open = entity.name in self.opening
    96         if row == len(self.rset) - 1:
    91         if row == len(self.rset) - 1:
    97             is_leaf = True
    92             is_leaf = True
    98         if not hasattr(entity, 'is_leaf') or entity.is_leaf():
    93         if not hasattr(entity, 'is_leaf') or entity.is_leaf():
    99             if is_leaf : cssclasses.append('last')
    94             if is_leaf : liclasses.append('last')
   100             self.w(u'<li class="%s">' % u' '.join(cssclasses))
    95             w(u'<li class="%s">' % u' '.join(liclasses))
   101         else:
    96         else:
   102             rql = entity.children_rql() % {'x': entity.eid}
    97             rql = entity.children_rql() % {'x': entity.eid}
   103             url = html_escape(self.build_url('json', rql=rql, vid=parentvid,
    98             url = html_escape(self.build_url('json', rql=rql, vid=parentvid,
   104                                              pageid=self.req.pageid,
    99                                              pageid=self.req.pageid,
   105                                              subvid=vid,
   100                                              subvid=vid,
   106                                              noautoload=True))
   101                                              noautoload=True))
   107             cssclasses.append('expandable')
   102             if is_open:
   108             divclasses = ['hitarea expandable-hitarea']
   103                 liclasses.append('collapsable')
   109             if is_leaf :
   104             else:
   110                 cssclasses.append('lastExpandable')
   105                 liclasses.append('expandable')
   111                 divclasses.append('lastExpandable-hitarea')
   106             divclasses = ['hitarea']
   112             self.w(u'<li cubicweb:loadurl="%s" class="%s">' % (url, u' '.join(cssclasses)))
   107             if is_open:
   113             self.w(u'<div class="%s"> </div>' % u' '.join(divclasses))
   108                 divclasses.append('collapsable-hitarea')
   114                 
   109             else:
       
   110                 divclasses.append('expandable-hitarea')
       
   111             if is_leaf:
       
   112                 liclasses.append('lastExpandable')
       
   113                 if not is_open:
       
   114                     divclasses.append('lastExpandable-hitarea')
       
   115             if is_open:
       
   116                 w(u'<li class="%s">' % u' '.join(liclasses))
       
   117             else:
       
   118                 w(u'<li cubicweb:loadurl="%s" class="%s">' % (url, u' '.join(liclasses)))
       
   119             w(u'<div class="%s"> </div>' % u' '.join(divclasses))
       
   120 
   115             # add empty <ul> because jquery's treeview plugin checks for
   121             # add empty <ul> because jquery's treeview plugin checks for
   116             # sublists presence
   122             # sublists presence
   117             self.w(u'<ul class="placeholder"><li>place holder</li></ul>')
   123             if not is_open:
       
   124                 w(u'<ul class="placeholder"><li>place holder</li></ul>')
       
   125         # the local node info
   118         self.wview(vid, self.rset, row=row, col=col)
   126         self.wview(vid, self.rset, row=row, col=col)
   119         self.w(u'</li>')
   127         if is_open: # recurse if needed
   120 
   128             self.wview(parentvid, self.req.execute(rql))
       
   129         w(u'</li>')