More grid filter improvements; add choice/enum/date value renderers.

This commit is contained in:
Lance Edgar 2015-08-20 21:17:48 -05:00
parent 226ca01720
commit c9b01f6061
2 changed files with 64 additions and 9 deletions

View file

@ -43,9 +43,6 @@ class FilterValueRenderer(object):
Base class for all filter renderers. Base class for all filter renderers.
""" """
def __init__(self, filter=None):
self.filter = filter
@property @property
def name(self): def name(self):
return self.filter.key return self.filter.key
@ -69,12 +66,40 @@ class NumericValueRenderer(FilterValueRenderer):
Input renderer for numeric values. Input renderer for numeric values.
""" """
def render(self, value=None, **kwargs):
return tags.text(self.name, value=value, type='number', **kwargs)
class DateValueRenderer(FilterValueRenderer): class DateValueRenderer(FilterValueRenderer):
""" """
Input renderer for date values. Input renderer for date values.
""" """
def render(self, value=None, **kwargs):
return tags.text(self.name, value=value, type='date', **kwargs)
class ChoiceValueRenderer(FilterValueRenderer):
"""
Renders value input as a dropdown/selectmenu of available choices.
"""
def __init__(self, choices):
self.choices = choices
def render(self, value=None, **kwargs):
return tags.select(self.name, [value], self.choices, **kwargs)
class EnumValueRenderer(ChoiceValueRenderer):
"""
Renders value input as a dropdown/selectmenu of available choices.
"""
def __init__(self, enum):
sorted_keys = sorted(enum, key=lambda k: enum[k].lower())
self.choices = [(k, enum[k]) for k in sorted_keys]
class GridFilter(object): class GridFilter(object):
""" """
@ -106,11 +131,7 @@ class GridFilter(object):
self.key = key self.key = key
self.label = label or prettify(key) self.label = label or prettify(key)
self.verbs = verbs or self.get_default_verbs() self.verbs = verbs or self.get_default_verbs()
if value_renderer is not None: self.set_value_renderer(value_renderer or self.value_renderer_factory)
value_renderer.filter = self
self.value_renderer = value_renderer
else:
self.value_renderer = self.value_renderer_factory(self)
self.default_active = default_active self.default_active = default_active
self.default_verb = default_verb self.default_verb = default_verb
self.default_value = default_value self.default_value = default_value
@ -130,6 +151,15 @@ class GridFilter(object):
return verbs return verbs
return ['equal', 'not_equal', 'is_null', 'is_not_null'] return ['equal', 'not_equal', 'is_null', 'is_not_null']
def set_value_renderer(self, renderer):
"""
Set the value renderer for the filter, post-construction.
"""
if not isinstance(renderer, FilterValueRenderer):
renderer = renderer()
renderer.filter = self
self.value_renderer = renderer
def filter(self, data, verb=None, value=UNSPECIFIED): def filter(self, data, verb=None, value=UNSPECIFIED):
""" """
Filter the given data set according to a verb/value pair. If no verb Filter the given data set according to a verb/value pair. If no verb
@ -278,6 +308,7 @@ class AlchemyNumericFilter(AlchemyGridFilter):
""" """
Numeric filter for SQLAlchemy. Numeric filter for SQLAlchemy.
""" """
value_renderer_factory = NumericValueRenderer
def default_verbs(self): def default_verbs(self):
""" """
@ -314,6 +345,13 @@ class AlchemyDateFilter(AlchemyGridFilter):
""" """
value_renderer_factory = DateValueRenderer value_renderer_factory = DateValueRenderer
def default_verbs(self):
"""
Expose greater-than / less-than verbs in addition to core.
"""
return ['equal', 'not_equal', 'greater_than', 'greater_equal',
'less_than', 'less_equal', 'is_null', 'is_not_null']
def filter_is_true(self, query, value): def filter_is_true(self, query, value):
""" """
Filter data with an "is true" query (alias for "is not null"). Filter data with an "is true" query (alias for "is not null").

View file

@ -250,6 +250,18 @@
} }
}); });
// Enhance any date values with datepicker widget.
this.inputs.find('.value input[type="date"]').datepicker({
dateFormat: 'yy-mm-dd',
changeYear: true,
changeMonth: true
});
// Enhance any choice/dropdown values with selectmenu.
this.inputs.find('.value select').selectmenu({
width: '15em'
});
// Listen for button click, to keep checkbox in sync. // Listen for button click, to keep checkbox in sync.
this._on(this.activebutton, { this._on(this.activebutton, {
click: function(e) { click: function(e) {
@ -269,6 +281,11 @@
refresh: function() { refresh: function() {
if (this.checkbox.is(':checked')) { if (this.checkbox.is(':checked')) {
this.activebutton.button('option', 'icons', {primary: 'ui-icon-check'}); this.activebutton.button('option', 'icons', {primary: 'ui-icon-check'});
if (this.verb() in this.valueless_verbs) {
this.inputs.find('.value').hide();
} else {
this.inputs.find('.value').show();
}
this.inputs.show(); this.inputs.show();
} else { } else {
this.activebutton.button('option', 'icons', {primary: 'ui-icon-blank'}); this.activebutton.button('option', 'icons', {primary: 'ui-icon-blank'});
@ -312,7 +329,7 @@
}, },
value: function() { value: function() {
return this.inputs.find('.value input').val(); return this.inputs.find('.value input, .value select').val();
}, },
verb: function() { verb: function() {