web/facet.py
changeset 8093 3efb83e4e8f3
parent 8067 3841d8793efb
child 8104 71d9fb78b772
equal deleted inserted replaced
8092:bc2a7c9fe266 8093:3efb83e4e8f3
    53 from copy import deepcopy
    53 from copy import deepcopy
    54 from datetime import datetime, timedelta
    54 from datetime import datetime, timedelta
    55 
    55 
    56 from logilab.mtconverter import xml_escape
    56 from logilab.mtconverter import xml_escape
    57 from logilab.common.graph import has_path
    57 from logilab.common.graph import has_path
    58 from logilab.common.decorators import cached
    58 from logilab.common.decorators import cached, cachedproperty
    59 from logilab.common.date import datetime2ticks, ustrftime, ticks2datetime
    59 from logilab.common.date import datetime2ticks, ustrftime, ticks2datetime
    60 from logilab.common.compat import all
    60 from logilab.common.compat import all
    61 from logilab.common.deprecation import deprecated
    61 from logilab.common.deprecation import deprecated
    62 
    62 
    63 from rql import nodes, utils
    63 from rql import nodes, utils
    64 
    64 
    65 from cubicweb import Unauthorized, typed_eid
    65 from cubicweb import Unauthorized, typed_eid
    66 from cubicweb.schema import display_name
    66 from cubicweb.schema import display_name
       
    67 from cubicweb.uilib import css_em_num_value
    67 from cubicweb.utils import make_uid
    68 from cubicweb.utils import make_uid
    68 from cubicweb.selectors import match_context_prop, partial_relation_possible, yes
    69 from cubicweb.selectors import match_context_prop, partial_relation_possible, yes
    69 from cubicweb.appobject import AppObject
    70 from cubicweb.appobject import AppObject
    70 from cubicweb.web import RequestError, htmlwidgets
    71 from cubicweb.web import RequestError, htmlwidgets
    71 
    72 
  1404     def possible_values(self):
  1405     def possible_values(self):
  1405         return [unicode(val) for label, val in self.vocabulary()]
  1406         return [unicode(val) for label, val in self.vocabulary()]
  1406 
  1407 
  1407 
  1408 
  1408 ## html widets ################################################################
  1409 ## html widets ################################################################
  1409 _DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT = 12
  1410 _DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT = 14
  1410 
  1411 
  1411 class FacetVocabularyWidget(htmlwidgets.HTMLWidget):
  1412 class FacetVocabularyWidget(htmlwidgets.HTMLWidget):
  1412 
  1413 
  1413     def __init__(self, facet):
  1414     def __init__(self, facet):
  1414         self.facet = facet
  1415         self.facet = facet
  1415         self.items = []
  1416         self.items = []
  1416 
  1417 
  1417     @property
  1418     @cachedproperty
  1418     @cached
       
  1419     def css_overflow_limit(self):
  1419     def css_overflow_limit(self):
  1420         """ we try to deduce a number of displayed lines from a css property
  1420         """ we try to deduce a number of displayed lines from a css property
  1421         if we get another unit we're out of luck and resort to one constant
  1421         if we get another unit we're out of luck and resort to one constant
  1422         hence, it is strongly advised not to specify but ems for this css prop
  1422         hence, it is strongly advised not to specify but ems for this css prop
  1423         """
  1423         """
  1424         vreg = self.facet._cw.vreg
  1424         return css_em_num_value(self.facet._cw.vreg, 'facet_vocabMaxHeight',
  1425         cssprop = vreg.config.uiprops['facet_overflowedHeight'].lower().strip()
  1425                                 _DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT)
  1426         if cssprop.endswith('em'):
  1426 
  1427             try:
  1427     @cachedproperty
  1428                 return int(cssprop[:-2])
       
  1429             except Exception:
       
  1430                 vreg.warning('css property facet_overflowedHeight looks malformed (%r)',
       
  1431                              cssprop)
       
  1432         return _DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT
       
  1433 
       
  1434     @property
       
  1435     @cached
       
  1436     def height(self):
  1428     def height(self):
  1437         return 1 + min(len(self.items),
  1429         """ title, optional and/or dropdown, len(items) or upper limit """
  1438                        self.css_overflow_limit + int(self.facet._support_and_compat()))
  1430         return (1.5 + # title + small magic constant
       
  1431                 int(self.facet._support_and_compat() +
       
  1432                     min(len(self.items), self.css_overflow_limit)))
  1439 
  1433 
  1440     @property
  1434     @property
  1441     @cached
  1435     @cached
  1442     def overflows(self):
  1436     def overflows(self):
  1443         return len(self.items) >= self.css_overflow_limit
  1437         return len(self.items) >= self.css_overflow_limit
  1497         self.facet = facet
  1491         self.facet = facet
  1498         self.value = None
  1492         self.value = None
  1499 
  1493 
  1500     @property
  1494     @property
  1501     def height(self):
  1495     def height(self):
  1502         return 3
  1496         return 2.5
  1503 
  1497 
  1504     def _render(self):
  1498     def _render(self):
  1505         w = self.w
  1499         w = self.w
  1506         title = xml_escape(self.facet.title)
  1500         title = xml_escape(self.facet.title)
  1507         facetid = make_uid(self.facet.__regid__)
  1501         facetid = make_uid(self.facet.__regid__)
  1542         self.minvalue = minvalue
  1536         self.minvalue = minvalue
  1543         self.maxvalue = maxvalue
  1537         self.maxvalue = maxvalue
  1544 
  1538 
  1545     @property
  1539     @property
  1546     def height(self):
  1540     def height(self):
  1547         return 3
  1541         return 2.5
  1548 
  1542 
  1549     def _render(self):
  1543     def _render(self):
  1550         w = self.w
  1544         w = self.w
  1551         facet = self.facet
  1545         facet = self.facet
  1552         facet._cw.add_js('jquery.ui.js')
  1546         facet._cw.add_js('jquery.ui.js')
  1562             'maxvalue': self.maxvalue,
  1556             'maxvalue': self.maxvalue,
  1563             'formatter': self.formatter,
  1557             'formatter': self.formatter,
  1564             })
  1558             })
  1565         title = xml_escape(self.facet.title)
  1559         title = xml_escape(self.facet.title)
  1566         facetname = xml_escape(facetname)
  1560         facetname = xml_escape(facetname)
  1567         w(u'<div id="%s" class="facet">\n' % facetid)
  1561         w(u'<div id="%s" class="facet rangeFacet">\n' % facetid)
  1568         w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\n' %
  1562         w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\n' %
  1569           (facetname, title))
  1563           (facetname, title))
  1570         cssclass = 'facetBody'
  1564         cssclass = 'facetBody'
  1571         if not self.facet.start_unfolded:
  1565         if not self.facet.start_unfolded:
  1572             cssclass += ' hidden'
  1566             cssclass += ' hidden'
  1613         self.value = value
  1607         self.value = value
  1614         self.selected = selected
  1608         self.selected = selected
  1615 
  1609 
  1616     @property
  1610     @property
  1617     def height(self):
  1611     def height(self):
  1618         return 2
  1612         return 1.5
  1619 
  1613 
  1620     def _render(self):
  1614     def _render(self):
  1621         w = self.w
  1615         w = self.w
  1622         title = xml_escape(self.facet.title)
  1616         title = xml_escape(self.facet.title)
  1623         facetid = make_uid(self.facet.__regid__)
  1617         facetid = make_uid(self.facet.__regid__)
  1639         w(u'</div>\n')
  1633         w(u'</div>\n')
  1640         w(u'</div>\n')
  1634         w(u'</div>\n')
  1641         w(u'</div>\n')
  1635         w(u'</div>\n')
  1642 
  1636 
  1643 
  1637 
  1644 class FacetSeparator(htmlwidgets.HTMLWidget):
       
  1645     def __init__(self, label=None):
       
  1646         self.label = label or u'&#160;'
       
  1647 
       
  1648     def _render(self):
       
  1649         pass
       
  1650 
       
  1651 # other classes ################################################################
  1638 # other classes ################################################################
  1652 
  1639 
  1653 class FilterRQLBuilder(object):
  1640 class FilterRQLBuilder(object):
  1654     """called by javascript to get a rql string from filter form"""
  1641     """called by javascript to get a rql string from filter form"""
  1655 
  1642