From 9fcc0ce735d2fd92949596139a14d2204d92abe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Fri, 6 Oct 2017 23:12:46 +0000 Subject: [PATCH] Tag bootstrap_for_typeahead customisable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../templatetags/bootstrap_form_typeahead.py | 101 ++++++++++++------ 1 file changed, 70 insertions(+), 31 deletions(-) diff --git a/machines/templatetags/bootstrap_form_typeahead.py b/machines/templatetags/bootstrap_form_typeahead.py index e4d8ace7..9253c995 100644 --- a/machines/templatetags/bootstrap_form_typeahead.py +++ b/machines/templatetags/bootstrap_form_typeahead.py @@ -41,7 +41,7 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs): bootstrap_form_typeahead **Parameters**: - + form 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 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 **Usage**:: @@ -56,15 +79,18 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs): {% bootstrap_form_typeahead form ['field1[,field2[,...]]] %} **Example**: - - {% bootstrap_form_typeahead form 'ipv4' %} + + {% bootstrap_form_typeahead form 'ipv4' choices='[...]' %} """ + t_fields = typeahead_fields.split(',') exclude = kwargs.get('exclude', None) 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()] - + form = '' for f_name, f_value in django_form.fields.items() : if not f_name in exclude : @@ -85,7 +111,12 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs): 'div', attrs = {'class': 'form-group'}, 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: form += render_field( @@ -94,7 +125,6 @@ def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs): **kwargs ) - return mark_safe( form ) 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 = \ '$("#'+input_id(f_name)+'").ready( function() {\n' + \ reset_input( f_name, f_value ) + '\n' + \ - typeahead_choices( f_value ) + '\n' + \ - typeahead_engine () + '\n' + \ + 'var choices = ' + choices + '\n' + \ + 'var engine = ' + default_engine() + '\n' + \ '$("#'+input_id(f_name) + '").typeahead(\n' + \ - typeahead_datasets( f_name ) + \ + default_datasets( f_name, match_func ) + \ ').bind(\n' + \ '"typeahead:select", ' + \ typeahead_updater( f_name ) + '\n' + \ @@ -136,8 +174,8 @@ def typeahead_full_script( f_name, f_value ) : def reset_input( f_name, f_value ) : return '$("#'+input_id(f_name)+'").val("");' -def typeahead_choices( f_value ) : - return 'var choices = [' + \ +def default_choices( f_value ) : + return '[' + \ ', '.join([ \ '{key: ' + (str(choice[0]) if choice[0] != '' else '""') + \ ', value: "' + str(choice[1]) + '"}' \ @@ -145,40 +183,41 @@ def typeahead_choices( f_value ) : ]) + \ '];' -def typeahead_engine () : - return 'var engine = new Bloodhound({ ' \ +def default_engine () : + return 'new Bloodhound({ ' \ 'datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"), ' \ 'queryTokenizer: Bloodhound.tokenizers.whitespace, ' \ '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 '{ ' \ 'hint: true, ' \ 'highlight: true, ' \ 'minLength: 0 ' \ '}, ' \ '{ ' \ - 'templates: { ' \ - 'suggestion: Handlebars.compile("
{{value}}
") ' \ - '}, ' \ 'display: "value", ' \ 'name: "'+f_name+'", ' \ - 'source: function(q, sync) {' \ - 'if (q === "") {' \ - 'var nb = 10;' \ - 'var first = [] ;' \ - 'for ( var i=0 ; i