From 919537f278028c1fd04d24e54497ffaa659986d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Sun, 15 Oct 2017 18:47:14 +0000 Subject: [PATCH 1/3] Valable sans JS --- machines/views.py | 4 +- re2o/templatetags/massive_bootstrap_form.py | 310 +++++++++++++------- 2 files changed, 211 insertions(+), 103 deletions(-) diff --git a/machines/views.py b/machines/views.py index 3cc906c0..6a87a9f8 100644 --- a/machines/views.py +++ b/machines/views.py @@ -129,11 +129,13 @@ def generate_ipv4_mbf_param( form, is_type_tt ): i_engine = { 'ipv4': generate_ipv4_engine( is_type_tt ) } i_match_func = { 'ipv4': generate_ipv4_match_func( is_type_tt ) } i_update_on = { 'ipv4': [f_type_id( is_type_tt )] } + i_gen_select = { 'ipv4': False } i_mbf_param = { 'choices': i_choices, 'engine': i_engine, 'match_func': i_match_func, - 'update_on': i_update_on + 'update_on': i_update_on, + 'gen_select': i_gen_select } return i_mbf_param diff --git a/re2o/templatetags/massive_bootstrap_form.py b/re2o/templatetags/massive_bootstrap_form.py index df7edc1f..ae4d5cdc 100644 --- a/re2o/templatetags/massive_bootstrap_form.py +++ b/re2o/templatetags/massive_bootstrap_form.py @@ -113,12 +113,29 @@ def massive_bootstrap_form(form, mbf_fields, *args, **kwargs): A dict of list of ids that the values depends on. The engine and the typeahead properties are recalculated and reapplied. Example : - 'addition' : { + 'update_on' : { 'field_A' : [ 'id0', 'id1', ... ] , 'field_B' : ... , ... } + gen_select (optional) + A dict of boolean telling if the form should either generate + the normal select (set to true) and then use it to generate + the possible choices and then remove it or either (set to + false) generate the choices variable in this tag and do not + send any select. + Sending the select before can be usefull to permit the use + without any JS enabled but it will execute more code locally + for the client so the loading might be slower. + If not specified, this variable is set to true for each field + Example : + 'gen_select' : { + 'field_A': True , + 'field_B': ... , + ... + } + See boostrap_form_ for other arguments **Usage**:: @@ -146,6 +163,11 @@ def massive_bootstrap_form(form, mbf_fields, *args, **kwargs): [ '': '' [, '': '' [, ... ] ] ] + } ], + [, 'gen_select': { + [ '': '' + [, '': '' + [, ... ] ] ] } ] } ] [ ] @@ -163,6 +185,7 @@ def massive_bootstrap_form(form, mbf_fields, *args, **kwargs): engine = param.get('engine', {}) match_func = param.get('match_func', {}) update_on = param.get('update_on', {}) + gen_select = param.get('gen_select', {}) hidden_fields = [h.name for h in form.hidden_fields()] html = '' @@ -184,40 +207,43 @@ def massive_bootstrap_form(form, mbf_fields, *args, **kwargs): multiple = f_value.widget.allow_multiple_selected f_bound = f_value.get_bound_field( form, f_name ) + if gen_select.get(f_name, True) : + html += render_field( + f_bound, + *args, + **kwargs + ) + f_value.widget = TextInput( attrs = { 'name': 'mbf_'+f_name, 'placeholder': f_value.empty_label } ) - html += render_field( + replace_input = render_field( f_value.get_bound_field( form, f_name ), *args, **kwargs ) - if multiple : - content = mbf_js( - f_name, - f_value, - f_bound, - multiple, - choices, - engine, - match_func, - update_on - ) - else : - content = hidden_tag( f_bound, f_name ) + mbf_js( - f_name, - f_value, - f_bound, - multiple, - choices, - engine, - match_func, - update_on - ) + if not gen_select.get(f_name, True) : + html += replace_input + + content = mbf_js( + f_name, + f_value, + f_bound, + multiple, + replace_input, + choices, + engine, + match_func, + update_on, + gen_select + ) + if not multiple and not gen_select.get(f_name, True) : + content += hidden_tag( f_bound, f_name ) + html += render_tag( 'div', content = content, @@ -257,12 +283,14 @@ def hidden_tag( f_bound, f_name ): } ) -def mbf_js( f_name, f_value, f_bound, multiple, - choices_, engine_, match_func_, update_on_ ) : +def mbf_js( f_name, f_value, f_bound, multiple, replace_input, + choices_, engine_, match_func_, update_on_, gen_select_ ) : """ The whole script to use """ + gen_select = gen_select_.get( f_name, True ) + choices = ( mark_safe( choices_[f_name] ) if f_name in choices_.keys() - else default_choices( f_value ) ) + else default_choices( f_value, f_bound, gen_select ) ) engine = ( mark_safe( engine_[f_name] ) if f_name in engine_.keys() else default_engine ( f_name ) ) @@ -272,82 +300,120 @@ def mbf_js( f_name, f_value, f_bound, multiple, update_on = update_on_[f_name] if f_name in update_on_.keys() else [] - if multiple : - js_content = ( - 'var choices_{f_name} = {choices};' - 'var engine_{f_name};' - 'var setup_{f_name} = function() {{' - 'engine_{f_name} = {engine};' - '$( "#{input_id}" ).tokenfield( "destroy" );' - '$( "#{input_id}" ).tokenfield({{typeahead: [ {datasets} ] }});' - '}};' - '$( "#{input_id}" ).bind( "tokenfield:createtoken", {create} );' - '$( "#{input_id}" ).bind( "tokenfield:edittoken", {edit} );' - '$( "#{input_id}" ).bind( "tokenfield:removetoken", {remove} );' - '{updates}' - '$( "#{input_id}" ).ready( function() {{' - 'setup_{f_name}();' - '{init_input}' - '}} );' - ).format( - f_name = f_name, - choices = choices, - engine = engine, - input_id = input_id( f_bound ), - datasets = default_datasets( f_name, match_func ), - create = tokenfield_create( f_name, f_bound ), - edit = tokenfield_edit( f_name, f_bound ), - remove = tokenfield_remove( f_name, f_bound ), - updates = ''.join( [ ( - '$( "#{u_id}" ).change( function() {{' - 'setup_{f_name}();' - '{reset_input}' - '}} );' - ).format( - u_id = u_id, - reset_input = tokenfield_reset_input( f_bound ), - f_name = f_name - ) for u_id in update_on ] - ), - init_input = tokenfield_init_input( f_name, f_bound ), + if gen_select : + if multiple : + js_content = ( + '$( "#{input_id}" ).ready( function() {{' + 'var choices_{f_name} = {choices};' + '{del_select}' + 'var engine_{f_name};' + 'var setup_{f_name} = function() {{' + 'engine_{f_name} = {engine};' + '$( "#{input_id}" ).tokenfield( "destroy" );' + '$( "#{input_id}" ).tokenfield({{typeahead: [ {datasets} ] }});' + '}};' + '$( "#{input_id}" ).bind( "tokenfield:createtoken", {tok_create} );' + '$( "#{input_id}" ).bind( "tokenfield:edittoken", {tok_edit} );' + '$( "#{input_id}" ).bind( "tokenfield:removetoken", {tok_remove} );' + '{tok_updates}' + 'setup_{f_name}();' + '{tok_init_input}' + '}} );' + ) + else : + js_content = ( + '$( "#{input_id}" ).ready( function() {{' + 'var choices_{f_name} = {choices};' + '{del_select}' + '{gen_hidden}' + 'var engine_{f_name};' + 'var setup_{f_name} = function() {{' + 'engine_{f_name} = {engine};' + '$( "#{input_id}" ).typeahead( "destroy" );' + '$( "#{input_id}" ).typeahead( {datasets} );' + '}};' + '$( "#{input_id}" ).bind( "typeahead:select", {typ_select} );' + '$( "#{input_id}" ).bind( "typeahead:change", {typ_change} );' + '{typ_updates}' + 'setup_{f_name}();' + '{typ_init_input}' + '}} );' ) else : - js_content = ( - 'var choices_{f_name} = {choices};' - 'var engine_{f_name};' - 'var setup_{f_name} = function() {{' - 'engine_{f_name} = {engine};' - '$( "#{input_id}" ).typeahead( "destroy" );' - '$( "#{input_id}" ).typeahead( {datasets} );' - '}};' - '$( "#{input_id}" ).bind( "typeahead:select", {select} );' - '$( "#{input_id}" ).bind( "typeahead:change", {change} );' - '{updates}' - '$( "#{input_id}" ).ready( function() {{' - 'setup_{f_name}();' - '{init_input}' - '}} );' - ).format( - f_name = f_name, - choices = choices, - engine = engine, - input_id = input_id( f_bound ), - datasets = default_datasets( f_name, match_func ), - select = typeahead_select( f_bound ), - change = typeahead_change( f_bound ), - updates = ''.join( [ ( - '$( "#{u_id}" ).change( function() {{' - 'setup_{f_name}();' - '{reset_input}' - '}} );' - ).format( - u_id = u_id, - reset_input = typeahead_reset_input( f_bound ), - f_name = f_name - ) for u_id in update_on ] - ), - init_input = typeahead_init_input( f_name, f_bound ), + if multiple : + js_content = ( + 'var choices_{f_name} = {choices};' + 'var engine_{f_name};' + 'var setup_{f_name} = function() {{' + 'engine_{f_name} = {engine};' + '$( "#{input_id}" ).tokenfield( "destroy" );' + '$( "#{input_id}" ).tokenfield({{typeahead: [ {datasets} ] }});' + '}};' + '$( "#{input_id}" ).bind( "tokenfield:createtoken", {tok_create} );' + '$( "#{input_id}" ).bind( "tokenfield:edittoken", {tok_edit} );' + '$( "#{input_id}" ).bind( "tokenfield:removetoken", {tok_remove} );' + '{tok_updates}' + '$( "#{input_id}" ).ready( function() {{' + 'setup_{f_name}();' + '{tok_init_input}' + '}} );' ) + else : + js_content = ( + 'var choices_{f_name} = {choices};' + 'var engine_{f_name};' + 'var setup_{f_name} = function() {{' + 'engine_{f_name} = {engine};' + '$( "#{input_id}" ).typeahead( "destroy" );' + '$( "#{input_id}" ).typeahead( {datasets} );' + '}};' + '$( "#{input_id}" ).bind( "typeahead:select", {typ_select} );' + '$( "#{input_id}" ).bind( "typeahead:change", {typ_change} );' + '{typ_updates}' + '$( "#{input_id}" ).ready( function() {{' + 'setup_{f_name}();' + '{typ_init_input}' + '}} );' + ) + + js_content = js_content.format( + f_name = f_name, + choices = choices, + del_select = del_select( f_bound, replace_input ), + gen_hidden = gen_hidden( f_bound ), + engine = engine, + input_id = input_id( f_bound ), + datasets = default_datasets( f_name, match_func ), + typ_select = typeahead_select( f_bound ), + typ_change = typeahead_change( f_bound ), + tok_create = tokenfield_create( f_name, f_bound ), + tok_edit = tokenfield_edit( f_name, f_bound ), + tok_remove = tokenfield_remove( f_name, f_bound ), + typ_updates = ''.join( [ ( + '$( "#{u_id}" ).change( function() {{' + 'setup_{f_name}();' + '{reset_input}' + '}} );' + ).format( + u_id = u_id, + reset_input = typeahead_reset_input( f_bound ), + f_name = f_name + ) for u_id in update_on ] + ), + tok_updates = ''.join( [ ( + '$( "#{u_id}" ).change( function() {{' + 'setup_{f_name}();' + '{reset_input}' + '}} );' + ).format( + u_id = u_id, + reset_input = tokenfield_reset_input( f_bound ), + f_name = f_name + ) for u_id in update_on ] + ), + tok_init_input = tokenfield_init_input( f_name, f_bound ), + typ_init_input = typeahead_init_input( f_name, f_bound ), + ) return render_tag( 'script', content=mark_safe( js_content ) ) @@ -403,9 +469,21 @@ def tokenfield_reset_input( f_bound ) : input_id = input_id( f_bound ), ) -def default_choices( f_value ) : +def default_choices( f_value, f_bound, gen_select ) : """ The JS script creating the variable choices_ """ - return '[{objects}]'.format( + if gen_select : + c = ( 'function plop(o) {{' + 'var c = [];' + 'for( let i=0 ; i