[facets] do no stretch to the right when there are many facets; instead use a floating layout (closes #2093160)
--- 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 #############################################################
--- 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;
}
--- 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
--- 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'<div id="%s" class="facet">\n' % facetid)
+ w(u'<div id="%s" class="facet rangeFacet">\n' % facetid)
w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\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'</div>\n')
-class FacetSeparator(htmlwidgets.HTMLWidget):
- def __init__(self, label=None):
- self.label = label or u' '
-
- def _render(self):
- pass
-
# other classes ################################################################
class FilterRQLBuilder(object):
--- 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'<table class="filter">\n')
- w(u'<tr>\n')
- for wdg in wdgs:
- w(u'<td>')
- wdg.render(w=w)
- w(u'</td>')
- w(u'</tr>\n')
- w(u'</table>\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'<table class="filter">\n')
+ w(u'<div class="filter">\n')
widget_queue = []
queue_height = 0
- wdg_stack_size = max(wdgs, key=lambda wdg:wdg.height).height
- w(u'<tr>\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'<td>')
+ w(u'<div class="facetGroup">')
for queued in widget_queue:
queued.render(w=w)
- w(u'</td>')
+ w(u'</div>')
widget_queue = [wdg]
queue_height = height
if widget_queue:
- w(u'<td>')
+ w(u'<div class="facetGroup">')
for queued in widget_queue:
queued.render(w=w)
- w(u'</td>')
- w(u'</tr>\n')
- w(u'</table>\n')
+ w(u'</div>')
+ w(u'</div>\n')
# facets ######################################################################