- Author:
- miracle2k
- Posted:
- September 18, 2007
- Language:
- Python
- Version:
- .96
- Score:
- 0 (after 0 ratings)
Adds a filter input above a select widget that allows live-filtering on the client-side (no ajax) in Firefox.
Example:
make_fields_searchable(ModelItemForm, { 'publisher': {'set_size': 8}, 'developer': {'set_size': 8}, 'genre': {}, 'platform': {} })
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | """
Adds client-side Javascript filtering to the widget instance passed. The widget
is expected to render as an HTML select, or the Javascript associated will fail.
This only works in Gecko - functionality in IE and Opera is limited. The list is
not filtered, but the first matching item will automatically be selected.
"""
make_searchable_js = \
"""
// filters a select by hiding all non-matching items - only works in FF so far.
//
// select - the id of the select control to filter
// filter_by_ctrl - a reference to an input object with the text to filter by
function filter_select(select, filter_by_ctrl)
{
filter_text = filter_by_ctrl.value.replace(/^\s+|\s+$/g,""); // trimmed
if (filter_by_ctrl.value == filter_by_ctrl.old_value) return false;
select_ctrl = document.getElementById(select);
sel_found = false;
for(i=0;i<select_ctrl.options.length;i++)
{
do_show = (!filter_text ||
select_ctrl.options[i].value=="" ||
select_ctrl.options[i].text.search(new RegExp(filter_text, "i"))!=-1)
select_ctrl.options[i].style.display = do_show ?'block':'none';
// preselect the first item, and try to be smart about it
if (!sel_found && do_show) {
if (
(select_ctrl.options[i].value=="" && !filter_text) ||
(select_ctrl.options[i].value!="")
)
{
if (!select_ctrl.options[i].selected)
{
select_ctrl.options[i].selected = true;
// we need to call a possible onchange manually, because it doesn't
// happen by itself. unfortunately, there is also an old but as-of-yet
// unfixed bug in firefox that requires the setTimeout() workaround,
// see:
// * https://bugzilla.mozilla.org/show_bug.cgi?id=317600
// * https://bugzilla.mozilla.org/show_bug.cgi?id=246518
if (select_ctrl.onchange) window.setTimeout(function(){select_ctrl.onchange()}, 0);
}
sel_found = true;
}
}
}
// do some work of our own to determine one the value has changed, for
// performance reaonns, but e.g. we also don't want to change the selection
// unless the filter changed at least, and definitely not on control keys
// such as arrow up or arrow down.
filter_by_ctrl.old_value = filter_by_ctrl.value;
}
// helper function that helps redirect certain keys from the filter input
// to the select, to allow a certain amount of control without changing focus (
// e.g. key up, down, ...)
//
// select - the id of the select to control
// e - event object
function filter_select_ctrl(select, e)
{
select_ctrl = document.getElementById(select);
if (e.keyCode == 40) {
for(i=select_ctrl.selectedIndex+1;i<select_ctrl.options.length;i++) {
if (select_ctrl.options[i].style.display!='none') {
select_ctrl.options[i].selected = true;
return true;
}
}
}
else if (e.keyCode == 38) {
for(i=select_ctrl.selectedIndex-1;i>=0;i--) {
if (select_ctrl.options[i].style.display!='none') {
select_ctrl.options[i].selected = true;
return true;
}
};
}
// TODO: page up / page down (33/34)
}
"""
def make_searchable(widget, set_size=None):
def render_hook(self, old_render, name, value, attrs, choices):
result = '<input type="text" onkeyup="filter_select(\'%(id)s\', this)"'\
' onkeypress="filter_select_ctrl(\'%(id)s\', (window.event)?window.event:event)" /><br />' % {'id': attrs['id']}
# add a search box
return result+old_render(name, value, attrs, choices)
old_render = widget.render
import new
widget.render = new.instancemethod(
lambda self, name, value, attrs=None, choices=(): \
render_hook(self, old_render, name, value, attrs, choices),
widget, widget.__class__)
widget.attrs['tabindex'] = -1
if set_size: widget.attrs['size'] = set_size
"""
Make multiple fields of a form searchable in one go.
form can be either a form class, or a form instance.
fields can be a list of valid field names for this form, or a dict with
field names as keys, and options dicts as values. Example:
{'foreignkey': {'set_size': 5}, ...}
Valid options are whatever is allowed by make_searchable(), the dict
is directly expandend to a parameter list on call.
"""
def make_fields_searchable(form, fields):
# determine whether this is a form class or a form instance, and use
# the correct field property accordingly.
if hasattr(form, 'base_fields'): fields_array = form.base_fields
else: fields_array = form.fields
# get a list of field names
if type(fields) == list: field_names = fields
else: field_names = fields.keys()
for field in field_names:
params = {}
if type(fields) == dict:
params = fields[field]
make_searchable(fields_array[field].widget, **params)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Please login first before commenting.