mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-23 03:43:12 +00:00
Tag bootstrap_for_typeahead customisable
Laisse la possibilité de changer certaines parties du script JS avec une string pour plus de facilité. Les parties modifiables sont le tableau des choix et le filtre qui match les query.
This commit is contained in:
parent
b5df315be9
commit
876f988412
1 changed files with 70 additions and 31 deletions
|
@ -41,7 +41,7 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs):
|
||||||
bootstrap_form_typeahead
|
bootstrap_form_typeahead
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
form
|
form
|
||||||
The form that is to be rendered
|
The form that is to be rendered
|
||||||
|
|
||||||
|
@ -49,6 +49,29 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs):
|
||||||
A list of field names (comma separated) that should be rendered
|
A list of field names (comma separated) that should be rendered
|
||||||
with typeahead instead of the default bootstrap renderer.
|
with typeahead instead of the default bootstrap renderer.
|
||||||
|
|
||||||
|
choices
|
||||||
|
A string representing the choices in JS. The choices must be an
|
||||||
|
array of objects. Each of those objects must at least have the
|
||||||
|
fields 'key' (value to send) and 'value' (value to display).
|
||||||
|
Other fields can be added as desired.
|
||||||
|
If not specified, the key is the id of the object and the value
|
||||||
|
is its string representation as in a normal bootstrap form.
|
||||||
|
Example :
|
||||||
|
choices='[{key:0,value:"choice0",extrafield:"data0"}, {...},...];'
|
||||||
|
|
||||||
|
match_func
|
||||||
|
A string representing a valid JS function used in the dataset to
|
||||||
|
overload the matching engine. This function is used the source of
|
||||||
|
the dataset. This function receives 2 parameters, the query and
|
||||||
|
the synchronize function as specified in typeahead.js documentation.
|
||||||
|
If needed, the local variables 'choices' and 'engine' contains
|
||||||
|
respectively the array of possible values and the engine to match
|
||||||
|
queries with possible values.
|
||||||
|
If not specified, the function used display up to the 10 first
|
||||||
|
elements if the query is empty and else the matching results.
|
||||||
|
Example :
|
||||||
|
match_func='function(q, sync) { engine.search(q, sync); }'
|
||||||
|
|
||||||
See boostrap_form_ for other arguments
|
See boostrap_form_ for other arguments
|
||||||
|
|
||||||
**Usage**::
|
**Usage**::
|
||||||
|
@ -56,15 +79,18 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs):
|
||||||
{% bootstrap_form_typeahead form ['field1[,field2[,...]]] %}
|
{% bootstrap_form_typeahead form ['field1[,field2[,...]]] %}
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
{% bootstrap_form_typeahead form 'ipv4' %}
|
{% bootstrap_form_typeahead form 'ipv4' choices='[...]' %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
t_fields = typeahead_fields.split(',')
|
t_fields = typeahead_fields.split(',')
|
||||||
exclude = kwargs.get('exclude', None)
|
exclude = kwargs.get('exclude', None)
|
||||||
exclude = exclude.split(',') if exclude else []
|
exclude = exclude.split(',') if exclude else []
|
||||||
|
t_choices = kwargs.get('choices', {})
|
||||||
|
t_match_func = kwargs.get('match_func', {})
|
||||||
hidden = [h.name for h in django_form.hidden_fields()]
|
hidden = [h.name for h in django_form.hidden_fields()]
|
||||||
|
|
||||||
form = ''
|
form = ''
|
||||||
for f_name, f_value in django_form.fields.items() :
|
for f_name, f_value in django_form.fields.items() :
|
||||||
if not f_name in exclude :
|
if not f_name in exclude :
|
||||||
|
@ -85,7 +111,12 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs):
|
||||||
'div',
|
'div',
|
||||||
attrs = {'class': 'form-group'},
|
attrs = {'class': 'form-group'},
|
||||||
content = hidden_tag( f_bound, f_name ) +
|
content = hidden_tag( f_bound, f_name ) +
|
||||||
typeahead_full_script( f_name, f_value )
|
typeahead_js(
|
||||||
|
f_name,
|
||||||
|
f_value,
|
||||||
|
t_choices,
|
||||||
|
t_match_func
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
form += render_field(
|
form += render_field(
|
||||||
|
@ -94,7 +125,6 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs):
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
return mark_safe( form )
|
return mark_safe( form )
|
||||||
|
|
||||||
def input_id( f_name ) :
|
def input_id( f_name ) :
|
||||||
|
@ -114,14 +144,22 @@ def hidden_tag( f_bound, f_name ):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def typeahead_full_script( f_name, f_value ) :
|
def typeahead_js( f_name, f_value, t_choices, t_match_func ) :
|
||||||
|
|
||||||
|
choices = mark_safe(t_choices[f_name]) if f_name in t_choices.keys() \
|
||||||
|
else default_choices( f_value )
|
||||||
|
|
||||||
|
match_func = mark_safe(t_match_func[f_name]) \
|
||||||
|
if f_name in t_match_func.keys() \
|
||||||
|
else default_match_func()
|
||||||
|
|
||||||
js_content = \
|
js_content = \
|
||||||
'$("#'+input_id(f_name)+'").ready( function() {\n' + \
|
'$("#'+input_id(f_name)+'").ready( function() {\n' + \
|
||||||
reset_input( f_name, f_value ) + '\n' + \
|
reset_input( f_name, f_value ) + '\n' + \
|
||||||
typeahead_choices( f_value ) + '\n' + \
|
'var choices = ' + choices + '\n' + \
|
||||||
typeahead_engine () + '\n' + \
|
'var engine = ' + default_engine() + '\n' + \
|
||||||
'$("#'+input_id(f_name) + '").typeahead(\n' + \
|
'$("#'+input_id(f_name) + '").typeahead(\n' + \
|
||||||
typeahead_datasets( f_name ) + \
|
default_datasets( f_name, match_func ) + \
|
||||||
').bind(\n' + \
|
').bind(\n' + \
|
||||||
'"typeahead:select", ' + \
|
'"typeahead:select", ' + \
|
||||||
typeahead_updater( f_name ) + '\n' + \
|
typeahead_updater( f_name ) + '\n' + \
|
||||||
|
@ -136,8 +174,8 @@ def typeahead_full_script( f_name, f_value ) :
|
||||||
def reset_input( f_name, f_value ) :
|
def reset_input( f_name, f_value ) :
|
||||||
return '$("#'+input_id(f_name)+'").val("");'
|
return '$("#'+input_id(f_name)+'").val("");'
|
||||||
|
|
||||||
def typeahead_choices( f_value ) :
|
def default_choices( f_value ) :
|
||||||
return 'var choices = [' + \
|
return '[' + \
|
||||||
', '.join([ \
|
', '.join([ \
|
||||||
'{key: ' + (str(choice[0]) if choice[0] != '' else '""') + \
|
'{key: ' + (str(choice[0]) if choice[0] != '' else '""') + \
|
||||||
', value: "' + str(choice[1]) + '"}' \
|
', value: "' + str(choice[1]) + '"}' \
|
||||||
|
@ -145,40 +183,41 @@ def typeahead_choices( f_value ) :
|
||||||
]) + \
|
]) + \
|
||||||
'];'
|
'];'
|
||||||
|
|
||||||
def typeahead_engine () :
|
def default_engine () :
|
||||||
return 'var engine = new Bloodhound({ ' \
|
return 'new Bloodhound({ ' \
|
||||||
'datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"), ' \
|
'datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"), ' \
|
||||||
'queryTokenizer: Bloodhound.tokenizers.whitespace, ' \
|
'queryTokenizer: Bloodhound.tokenizers.whitespace, ' \
|
||||||
'local: choices, ' \
|
'local: choices, ' \
|
||||||
'identify: function(obj) { return obj.value; } ' \
|
'identify: function(obj) { return obj.key; } ' \
|
||||||
'});'
|
'});'
|
||||||
|
|
||||||
def typeahead_datasets( f_name ) :
|
def default_datasets( f_name, match_func ) :
|
||||||
return '{ ' \
|
return '{ ' \
|
||||||
'hint: true, ' \
|
'hint: true, ' \
|
||||||
'highlight: true, ' \
|
'highlight: true, ' \
|
||||||
'minLength: 0 ' \
|
'minLength: 0 ' \
|
||||||
'}, ' \
|
'}, ' \
|
||||||
'{ ' \
|
'{ ' \
|
||||||
'templates: { ' \
|
|
||||||
'suggestion: Handlebars.compile("<div>{{value}}</div>") ' \
|
|
||||||
'}, ' \
|
|
||||||
'display: "value", ' \
|
'display: "value", ' \
|
||||||
'name: "'+f_name+'", ' \
|
'name: "'+f_name+'", ' \
|
||||||
'source: function(q, sync) {' \
|
'source: '+match_func + \
|
||||||
'if (q === "") {' \
|
|
||||||
'var nb = 10;' \
|
|
||||||
'var first = [] ;' \
|
|
||||||
'for ( var i=0 ; i<nb && i<choices.length; i++ ) {' \
|
|
||||||
'first.push(choices[i].value);' \
|
|
||||||
'}' \
|
|
||||||
'sync(engine.get(first));' \
|
|
||||||
'} else {' \
|
|
||||||
'engine.search(q, sync)' \
|
|
||||||
'}' \
|
|
||||||
'}' \
|
|
||||||
'}'
|
'}'
|
||||||
|
|
||||||
|
def default_match_func () :
|
||||||
|
return 'function(q, sync) {' \
|
||||||
|
'if (q === "") {' \
|
||||||
|
'var nb = 10;' \
|
||||||
|
'var first = [] ;' \
|
||||||
|
'for ( var i=0 ; i<nb && i<choices.length; i++ ) {' \
|
||||||
|
'first.push(choices[i].key);' \
|
||||||
|
'}' \
|
||||||
|
'sync(engine.get(first));' \
|
||||||
|
'} else {' \
|
||||||
|
'engine.search(q, sync);' \
|
||||||
|
'}' \
|
||||||
|
'}'
|
||||||
|
# matches.filter(function (elt) {return elt.type == $("#id_type").val();});sync(matches);})
|
||||||
|
|
||||||
def typeahead_updater( f_name ):
|
def typeahead_updater( f_name ):
|
||||||
return 'function(evt, item) { ' \
|
return 'function(evt, item) { ' \
|
||||||
'$("#'+hidden_id(f_name)+'").val( item.key ); ' \
|
'$("#'+hidden_id(f_name)+'").val( item.key ); ' \
|
||||||
|
|
Loading…
Reference in a new issue