8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-22 11:23:10 +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:
Maël Kervella 2017-10-06 23:12:46 +00:00
parent 5bd110fbfc
commit 9fcc0ce735

View file

@ -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 ); ' \