diff -r 000000000000 -r b97547f5f1fa web/views/facets.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/views/facets.py Wed Nov 05 15:52:50 2008 +0100 @@ -0,0 +1,161 @@ +"""the facets box and some basic facets + +:organization: Logilab +:copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" + +from simplejson import dumps + +from logilab.mtconverter import html_escape + +from cubicweb.common.selectors import (chainfirst, chainall, nfentity_selector, + twolinerset_selector, contextprop_selector, + yes_selector, one_has_relation_selector) +from cubicweb.web.box import BoxTemplate +from cubicweb.web.facet import (AbstractFacet, VocabularyFacet, FacetStringWidget, + RelationFacet, prepare_facets_rqlst, filter_hiddens) + +def contextview_selector(cls, req, rset, row=None, col=None, view=None, + **kwargs): + if view and getattr(view, 'filter_box_context_info', lambda: None)(): + return 1 + return 0 + + +class FilterBox(BoxTemplate): + """filter results of a query""" + id = 'filter_box' + __selectors__ = (chainfirst(contextview_selector, + chainall(nfentity_selector, twolinerset_selector)), + contextprop_selector) + context = 'left' + title = _('boxes_filter_box') + visible = True # functionality provided by the search box by default + order = 1 + + def facetargs(self): + """this method returns the list of extra arguments that should + be used by the facet + """ + return {} + + def _get_context(self, view): + context = getattr(view, 'filter_box_context_info', lambda: None)() + if context: + rset, vid, divid, paginate = context + else: + rset = self.rset + vid, divid = None, 'pageContent' + paginate = view.need_navigation + return rset, vid, divid, paginate + + def call(self, view=None): + self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.formfilter.js') ) + rset, vid, divid, paginate = self._get_context(view) + if rset.rowcount < 2: # XXX done by selectors, though maybe necessary when rset has been hijacked + return + if vid is None: + vid = self.req.form.get('vid') + rqlst = rset.syntax_tree() + rqlst.save_state() + try: + mainvar, baserql = prepare_facets_rqlst(rqlst, rset.args) + widgets = [] + for facet in self.get_facets(rset, mainvar): + if facet.propval('visible'): + wdg = facet.get_widget() + if wdg is not None: + widgets.append(wdg) + if not widgets: + return + w = self.w + w(u'
' % ( + divid, html_escape(dumps([divid, vid, paginate, self.facetargs()])))) + w(u'
') + hiddens = {'facets': ','.join(wdg.facet.id for wdg in widgets), + 'baserql': baserql} + for param in ('subvid', 'vtitle'): + if param in self.req.form: + hiddens[param] = self.req.form[param] + filter_hiddens(w, **hiddens) + for wdg in widgets: + wdg.render(w=self.w) + w(u'
\n
\n') + finally: + rqlst.recover() + print 'after facets', rqlst + + def get_facets(self, rset, mainvar): + return self.vreg.possible_vobjects('facets', self.req, rset, + context='facetbox', + filtered_variable=mainvar) + +# facets ###################################################################### + +class CreatedByFacet(RelationFacet): + id = 'created_by-facet' + rtype = 'created_by' + target_attr = 'login' + +class InGroupFacet(RelationFacet): + id = 'in_group-facet' + rtype = 'in_group' + target_attr = 'name' + +class InStateFacet(RelationFacet): + id = 'in_state-facet' + rtype = 'in_state' + target_attr = 'name' + +# inherit from RelationFacet to benefit from its possible_values implementation +class ETypeFacet(RelationFacet): + id = 'etype-facet' + __selectors__ = (yes_selector,) + order = 1 + rtype = 'is' + target_attr = 'name' + + @property + def title(self): + return self.req._('entity type') + + def vocabulary(self): + """return vocabulary for this facet, eg a list of 2-uple (label, value) + """ + etypes = self.rset.column_types(0) + return sorted((self.req._(etype), etype) for etype in etypes) + + def add_rql_restrictions(self): + """add restriction for this facet into the rql syntax tree""" + value = self.req.form.get(self.id) + if not value: + return + self.rqlst.add_type_restriction(self.filtered_variable, value) + + +class HasTextFacet(AbstractFacet): + __selectors__ = (one_has_relation_selector, contextprop_selector) + id = 'has_text-facet' + rtype = 'has_text' + role = 'subject' + order = 0 + @property + def title(self): + return self.req._('has_text') + + def get_widget(self): + """return the widget instance to use to display this facet + + default implentation expects a .vocabulary method on the facet and + return a combobox displaying this vocabulary + """ + return FacetStringWidget(self) + + def add_rql_restrictions(self): + """add restriction for this facet into the rql syntax tree""" + value = self.req.form.get(self.id) + if not value: + return + self.rqlst.add_constant_restriction(self.filtered_variable, 'has_text', value, 'String')