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 |
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' |
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' ' |
|
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 |