# HG changeset patch # User Aurelien Campeas # Date 1322047805 -3600 # Node ID 3efb83e4e8f36f10561e5c712797914882a1f0bb # Parent bc2a7c9fe266923ccb795febf967cbb31108ea40 [facets] do no stretch to the right when there are many facets; instead use a floating layout (closes #2093160) diff -r bc2a7c9fe266 -r 3efb83e4e8f3 uilib.py --- a/uilib.py Wed Nov 23 11:46:30 2011 +0100 +++ b/uilib.py Wed Nov 23 12:30:05 2011 +0100 @@ -144,6 +144,22 @@ def printable_value(req, attrtype, value, props=None, displaytime=True): return req.printable_value(attrtype, value, props, displaytime) +def css_em_num_value(vreg, propname, default): + """ we try to read an 'em' css property + if we get another unit we're out of luck and resort to the given default + (hence, it is strongly advised not to specify but ems for this css prop) + """ + propvalue = vreg.config.uiprops[propname].lower().strip() + if propvalue.endswith('em'): + try: + return float(propvalue[:-2]) + except Exception: + vreg.warning('css property %s looks malformed (%r)', + propname, propvalue) + else: + vreg.warning('css property %s should use em (currently is %r)', + propname, propvalue) + return default # text publishing ############################################################# diff -r bc2a7c9fe266 -r 3efb83e4e8f3 web/data/cubicweb.facets.css --- a/web/data/cubicweb.facets.css Wed Nov 23 11:46:30 2011 +0100 +++ b/web/data/cubicweb.facets.css Wed Nov 23 12:30:05 2011 +0100 @@ -3,15 +3,22 @@ padding: 0px; } -div.facet { - background: #fff; - padding: 5px; - margin: .3em!important; +.facet { + border: 1px solid chocolate; + background: #fff; + padding: %(facet_Padding)s; + margin-bottom: %(facet_MarginBottom)s; +} + +.facetGroup { + margin: .3em; + float: left; + max-height: %(facet_Height)s; } div.facetTitle, div.bkSearch { color: #000; - margin-bottom: 2px; + margin: 2px; cursor: pointer; font-weight: bold; font: %(facet_titleFont)s; @@ -26,15 +33,19 @@ color: #000 !important; } -div.vocabularyFacetBody { - height: %(facet_overflowedHeight)s; +.facetGroup div.rangeFacet { + width: 13em; } -div.vocabularyFacetBodyWithLogicalSelector { - height: %(facet_overflowedHeightWithLogicalSelector)s; +.facetGroup div.vocabularyFacet { + /* when facets spread on several lines, it can relieve the eye + to have them vertically aligned; these properties should + be used then */ + /* width: 13em; */ } div.vocabularyFacet { + max-height: %(facet_vocabMaxHeight)s; overflow-y: auto; overflow-x: hidden; } @@ -72,10 +83,10 @@ border: none; } -.facet input{ - margin-top:3px; - border:1px solid #ccc; - font-size:11px; +.facet input { + margin-top: .2em; + border: 1px solid #ccc; + font-size: small; } .facetValueDisabled span { @@ -108,7 +119,8 @@ background: url("required.png") no-repeat right top; } -table.filter { +.filter { background-color: #EBE8D9; border: dotted grey 1px; + display: inline-block; } diff -r bc2a7c9fe266 -r 3efb83e4e8f3 web/data/uiprops.py --- a/web/data/uiprops.py Wed Nov 23 11:46:30 2011 +0100 +++ b/web/data/uiprops.py Wed Nov 23 12:30:05 2011 +0100 @@ -168,6 +168,7 @@ # facets facet_titleFont = 'bold SansSerif' -facet_overflowedHeight = '12em' -# the above minus 1 -facet_overflowedHeightWithLogicalSelector = '11em' +facet_Height = '15em' +facet_Padding = '.4em' +facet_MarginBottom = '.4em' +facet_vocabMaxHeight = '12em' # ensure << facet_Height diff -r bc2a7c9fe266 -r 3efb83e4e8f3 web/facet.py --- a/web/facet.py Wed Nov 23 11:46:30 2011 +0100 +++ b/web/facet.py Wed Nov 23 12:30:05 2011 +0100 @@ -55,7 +55,7 @@ from logilab.mtconverter import xml_escape from logilab.common.graph import has_path -from logilab.common.decorators import cached +from logilab.common.decorators import cached, cachedproperty from logilab.common.date import datetime2ticks, ustrftime, ticks2datetime from logilab.common.compat import all from logilab.common.deprecation import deprecated @@ -64,6 +64,7 @@ from cubicweb import Unauthorized, typed_eid from cubicweb.schema import display_name +from cubicweb.uilib import css_em_num_value from cubicweb.utils import make_uid from cubicweb.selectors import match_context_prop, partial_relation_possible, yes from cubicweb.appobject import AppObject @@ -1406,7 +1407,7 @@ ## html widets ################################################################ -_DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT = 12 +_DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT = 14 class FacetVocabularyWidget(htmlwidgets.HTMLWidget): @@ -1414,28 +1415,21 @@ self.facet = facet self.items = [] - @property - @cached + @cachedproperty def css_overflow_limit(self): """ we try to deduce a number of displayed lines from a css property if we get another unit we're out of luck and resort to one constant hence, it is strongly advised not to specify but ems for this css prop """ - vreg = self.facet._cw.vreg - cssprop = vreg.config.uiprops['facet_overflowedHeight'].lower().strip() - if cssprop.endswith('em'): - try: - return int(cssprop[:-2]) - except Exception: - vreg.warning('css property facet_overflowedHeight looks malformed (%r)', - cssprop) - return _DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT + return css_em_num_value(self.facet._cw.vreg, 'facet_vocabMaxHeight', + _DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT) - @property - @cached + @cachedproperty def height(self): - return 1 + min(len(self.items), - self.css_overflow_limit + int(self.facet._support_and_compat())) + """ title, optional and/or dropdown, len(items) or upper limit """ + return (1.5 + # title + small magic constant + int(self.facet._support_and_compat() + + min(len(self.items), self.css_overflow_limit))) @property @cached @@ -1499,7 +1493,7 @@ @property def height(self): - return 3 + return 2.5 def _render(self): w = self.w @@ -1544,7 +1538,7 @@ @property def height(self): - return 3 + return 2.5 def _render(self): w = self.w @@ -1564,7 +1558,7 @@ }) title = xml_escape(self.facet.title) facetname = xml_escape(facetname) - w(u'
\n' % facetid) + w(u'
\n' % facetid) w(u'
%s
\n' % (facetname, title)) cssclass = 'facetBody' @@ -1615,7 +1609,7 @@ @property def height(self): - return 2 + return 1.5 def _render(self): w = self.w @@ -1641,13 +1635,6 @@ w(u'
\n') -class FacetSeparator(htmlwidgets.HTMLWidget): - def __init__(self, label=None): - self.label = label or u' ' - - def _render(self): - pass - # other classes ################################################################ class FilterRQLBuilder(object): diff -r bc2a7c9fe266 -r 3efb83e4e8f3 web/views/facets.py --- a/web/views/facets.py Wed Nov 23 11:46:30 2011 +0100 +++ b/web/views/facets.py Wed Nov 23 12:30:05 2011 +0100 @@ -23,11 +23,14 @@ from warnings import warn from logilab.mtconverter import xml_escape +from logilab.common.decorators import cachedproperty from cubicweb.appobject import objectify_selector from cubicweb.selectors import (non_final_entity, multi_lines_rset, match_context_prop, yes, relation_possible) from cubicweb.utils import json_dumps +from cubicweb.uilib import css_em_num_value +from cubicweb.view import AnyRsetView from cubicweb.web import component, facet as facetbase def facets(req, rset, context, mainvar=None, **kwargs): @@ -199,7 +202,7 @@ """sort widgets: by default sort by widget height, then according to widget.order (the original widgets order) """ - return sorted(wdgs, key=lambda x: x.height) + return sorted(wdgs, key=lambda x: 99 * (not x.facet.start_unfolded) or x.height ) def layout_widgets(self, w, wdgs): """layout widgets: by default simply render each of them @@ -266,12 +269,10 @@ return self.bk_linkbox_template % bk_link -from cubicweb.view import AnyRsetView - class FilterTable(FacetFilterMixIn, AnyRsetView): __regid__ = 'facet.filtertable' __select__ = has_facets() - compact_layout_threshold = 5 + average_perfacet_uncomputable_overhead = .3 def call(self, vid, divid, vidargs=None, cssclass=''): hiddens = self.cw_extra_kwargs.setdefault('hiddens', {}) @@ -279,47 +280,39 @@ self.generate_form(self.w, self.cw_rset, divid, vid, vidargs=vidargs, cssclass=cssclass, **self.cw_extra_kwargs) - def _simple_horizontal_layout(self, w, wdgs): - w(u'\n') - w(u'\n') - for wdg in wdgs: - w(u'') - w(u'\n') - w(u'
') - wdg.render(w=w) - w(u'
\n') + @cachedproperty + def per_facet_height_overhead(self): + return (css_em_num_value(self._cw.vreg, 'facet_MarginBottom', .2) + + css_em_num_value(self._cw.vreg, 'facet_Padding', .2) + + self.average_perfacet_uncomputable_overhead) def layout_widgets(self, w, wdgs): """layout widgets: put them in a table where each column should have sum(wdg.height) < wdg_stack_size. """ - if len(wdgs) < self.compact_layout_threshold: - self._simple_horizontal_layout(w, wdgs) - return - w(u'\n') + w(u'
\n') widget_queue = [] queue_height = 0 - wdg_stack_size = max(wdgs, key=lambda wdg:wdg.height).height - w(u'
\n') + wdg_stack_size = css_em_num_value(self._cw.vreg, 'facet_Height', + facetbase._DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT) for wdg in wdgs: - height = wdg.height + height = wdg.height + self.per_facet_height_overhead if queue_height + height <= wdg_stack_size: widget_queue.append(wdg) queue_height += height continue - w(u'') + w(u'') widget_queue = [wdg] queue_height = height if widget_queue: - w(u'') - w(u'\n') - w(u'
') + w(u'
') for queued in widget_queue: queued.render(w=w) - w(u'
') + w(u'
') for queued in widget_queue: queued.render(w=w) - w(u'
\n') + w(u'
') + w(u'\n') # facets ######################################################################