web/views/facets.py
changeset 0 b97547f5f1fa
child 5 64072193bd48
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """the facets box and some basic facets
       
     2 
       
     3 :organization: Logilab
       
     4 :copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     6 """
       
     7 __docformat__ = "restructuredtext en"
       
     8 
       
     9 from simplejson import dumps
       
    10 
       
    11 from logilab.mtconverter import html_escape
       
    12 
       
    13 from cubicweb.common.selectors import (chainfirst, chainall, nfentity_selector,
       
    14                                     twolinerset_selector, contextprop_selector,
       
    15                                     yes_selector, one_has_relation_selector)
       
    16 from cubicweb.web.box import BoxTemplate
       
    17 from cubicweb.web.facet import (AbstractFacet, VocabularyFacet, FacetStringWidget,
       
    18                              RelationFacet, prepare_facets_rqlst, filter_hiddens)
       
    19 
       
    20 def contextview_selector(cls, req, rset, row=None, col=None, view=None,
       
    21                          **kwargs):
       
    22     if view and getattr(view, 'filter_box_context_info', lambda: None)():
       
    23         return 1
       
    24     return 0    
       
    25 
       
    26 
       
    27 class FilterBox(BoxTemplate):
       
    28     """filter results of a query"""
       
    29     id = 'filter_box'
       
    30     __selectors__ = (chainfirst(contextview_selector,
       
    31                                 chainall(nfentity_selector, twolinerset_selector)),
       
    32                      contextprop_selector)
       
    33     context = 'left'
       
    34     title = _('boxes_filter_box')
       
    35     visible = True # functionality provided by the search box by default
       
    36     order = 1
       
    37 
       
    38     def facetargs(self):
       
    39         """this method returns the list of extra arguments that should
       
    40         be used by the facet
       
    41         """
       
    42         return {}
       
    43         
       
    44     def _get_context(self, view):
       
    45         context = getattr(view, 'filter_box_context_info', lambda: None)()
       
    46         if context:
       
    47             rset, vid, divid, paginate = context
       
    48         else:
       
    49             rset = self.rset
       
    50             vid, divid = None, 'pageContent'
       
    51             paginate = view.need_navigation
       
    52         return rset, vid, divid, paginate
       
    53         
       
    54     def call(self, view=None):
       
    55         self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.formfilter.js') )
       
    56         rset, vid, divid, paginate = self._get_context(view)
       
    57         if rset.rowcount < 2: # XXX done by selectors, though maybe necessary when rset has been hijacked
       
    58             return
       
    59         if vid is None:
       
    60             vid = self.req.form.get('vid')
       
    61         rqlst = rset.syntax_tree()
       
    62         rqlst.save_state()
       
    63         try:
       
    64             mainvar, baserql = prepare_facets_rqlst(rqlst, rset.args)
       
    65             widgets = []
       
    66             for facet in self.get_facets(rset, mainvar):
       
    67                 if facet.propval('visible'):
       
    68                     wdg = facet.get_widget()
       
    69                     if wdg is not None:
       
    70                         widgets.append(wdg)
       
    71             if not widgets:
       
    72                 return
       
    73             w = self.w
       
    74             w(u'<form method="post" id="%sForm" cubicweb:facetargs="%s" action="">'  % (
       
    75                 divid, html_escape(dumps([divid, vid, paginate, self.facetargs()]))))
       
    76             w(u'<fieldset>')
       
    77             hiddens = {'facets': ','.join(wdg.facet.id for wdg in widgets),
       
    78                        'baserql': baserql}
       
    79             for param in ('subvid', 'vtitle'):
       
    80                 if param in self.req.form:
       
    81                     hiddens[param] = self.req.form[param]
       
    82             filter_hiddens(w, **hiddens)
       
    83             for wdg in widgets:
       
    84                 wdg.render(w=self.w)
       
    85             w(u'</fieldset>\n</form>\n')
       
    86         finally:
       
    87             rqlst.recover()
       
    88             print 'after facets', rqlst
       
    89 
       
    90     def get_facets(self, rset, mainvar):
       
    91         return self.vreg.possible_vobjects('facets', self.req, rset,
       
    92                                            context='facetbox',
       
    93                                            filtered_variable=mainvar)
       
    94         
       
    95 # facets ######################################################################
       
    96 
       
    97 class CreatedByFacet(RelationFacet):
       
    98     id = 'created_by-facet'
       
    99     rtype = 'created_by'
       
   100     target_attr = 'login'
       
   101 
       
   102 class InGroupFacet(RelationFacet):
       
   103     id = 'in_group-facet'
       
   104     rtype = 'in_group'
       
   105     target_attr = 'name'
       
   106 
       
   107 class InStateFacet(RelationFacet):
       
   108     id = 'in_state-facet'
       
   109     rtype = 'in_state'
       
   110     target_attr = 'name'
       
   111 
       
   112 # inherit from RelationFacet to benefit from its possible_values implementation
       
   113 class ETypeFacet(RelationFacet):
       
   114     id = 'etype-facet'
       
   115     __selectors__ = (yes_selector,)
       
   116     order = 1
       
   117     rtype = 'is'
       
   118     target_attr = 'name'
       
   119 
       
   120     @property
       
   121     def title(self):
       
   122         return self.req._('entity type')
       
   123 
       
   124     def vocabulary(self):
       
   125         """return vocabulary for this facet, eg a list of 2-uple (label, value)
       
   126         """
       
   127         etypes = self.rset.column_types(0)
       
   128         return sorted((self.req._(etype), etype) for etype in etypes)
       
   129     
       
   130     def add_rql_restrictions(self):
       
   131         """add restriction for this facet into the rql syntax tree"""
       
   132         value = self.req.form.get(self.id)
       
   133         if not value:
       
   134             return
       
   135         self.rqlst.add_type_restriction(self.filtered_variable, value)
       
   136 
       
   137 
       
   138 class HasTextFacet(AbstractFacet):
       
   139     __selectors__ = (one_has_relation_selector, contextprop_selector)
       
   140     id = 'has_text-facet'
       
   141     rtype = 'has_text'
       
   142     role = 'subject'
       
   143     order = 0
       
   144     @property
       
   145     def title(self):
       
   146         return self.req._('has_text')
       
   147     
       
   148     def get_widget(self):
       
   149         """return the widget instance to use to display this facet
       
   150 
       
   151         default implentation expects a .vocabulary method on the facet and
       
   152         return a combobox displaying this vocabulary
       
   153         """
       
   154         return FacetStringWidget(self)
       
   155 
       
   156     def add_rql_restrictions(self):
       
   157         """add restriction for this facet into the rql syntax tree"""
       
   158         value = self.req.form.get(self.id)
       
   159         if not value:
       
   160             return
       
   161         self.rqlst.add_constant_restriction(self.filtered_variable, 'has_text', value, 'String')