From f1c32cabdb9168b28ac53aebac3843f6e608dafc Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Thu, 22 Sep 2016 15:01:01 +0200 Subject: [PATCH] Gestion des 'getter' et 'setter' dynamiques de variables directement sur l'objet, soit l'objet A notre 'FormBuilder' et 'someVar' une de ses variables de construction, 'someVar' est accessible via 'A.' en GET et en SET --- js/lib/form-builder-min.js | 45 ++++++++--------- js/lib/form-builder.js | 87 +++++++++++++++++++++++++++++++-- js/lib/form-builder/main-min.js | 2 +- js/lib/form-builder/main.js | 5 +- 4 files changed, 111 insertions(+), 28 deletions(-) diff --git a/js/lib/form-builder-min.js b/js/lib/form-builder-min.js index e817c88..8098dc3 100644 --- a/js/lib/form-builder-min.js +++ b/js/lib/form-builder-min.js @@ -1,25 +1,26 @@ -var ref=function(a,b){for(var e=null;null==e||a.hasOwnProperty(e);)e="$"+(268435456+Math.floor(4026531839*Math.random())).toString(16)+"$";a[e]=b;return e},FormBuilder=function(a){this.form_object=a};FormBuilder.prototype={form_object:this.form_object,defs_object:{},parent_element:null,built_form:null,root_element:null,ref_table:{$00000000$:null},ref_assoc:{NULL:"$00000000$"}}; +var ref=function(a,b){for(var e=null;null==e||a.hasOwnProperty(e);)e="$"+(268435456+Math.floor(4026531839*Math.random())).toString(16)+"$";a[e]=b;return e},FormBuilder=function(a){this.form_object=a;this.observer=new MutationObserver(FormBuilder.DOMUpdates)};FormBuilder.prototype={form_object:this.form_object,defs_object:{},parent_element:null,built_form:null,root_element:null,ref_table:{$00000000$:null},ref_assoc:{NULL:"$00000000$"},observer:this.observer,scope:{}}; FormBuilder.regex={reg_in_key:/^\/\^(.+)\$\/$/,reg_out_val:/\{(\$[1-9])\}/,pri_out_val:/\{([a-z_]+)\}/g,pri_in_key:/^\$([a-z_]+)$/,arr_out_set:/^\{([a-z_]+)\[\]\}$/,arr_out_val:/\{([a-z_]+)([\.:])([a-z_]+)\}/g,arr_in_key:/^\$([a-z_]+)$/,fun_out_val:/^\{([a-z_]+)\(\)\}$/,ref_pri:/^\$[a-f0-9]{8}\$$/};FormBuilder.spread_attr="children next_nodes prev_nodes attributes node_link listeners repeat browse funcs".split(" ");FormBuilder.debug_time=!1;FormBuilder.debug_time_details=!1; FormBuilder.debugStart=function(a,b){if(1!=b||!FormBuilder.debug_time)if(2!=b||!FormBuilder.debug_time_details)return{type:0};var e="["+parseInt(64424509439*Math.random()).toString(16)+"]";console.time(e);console.group(a);return{type:b,time_r:e,group:a}};FormBuilder.debug=function(a,b){if(1!=b||!FormBuilder.debug_time)if(2!=b||!FormBuilder.debug_time_details)return{type:0};console.debug(a)}; FormBuilder.debugStop=function(a){if(1!=a.type||!FormBuilder.debug_time)if(2!=a.type||!FormBuilder.debug_time_details)return null;console.timeEnd(a.time_r);console.groupEnd(a.group)};FormBuilder.prototype.add_definition=function(a){var b=FormBuilder.debugStart("FormBuilder.add_definition",1),e;for(e in a)this.defs_object[e]=a[e];FormBuilder.debugStop(b)}; -FormBuilder.prototype.build=function(a){var b=FormBuilder.debugStart("FormBuilder.build",1);a=null==a?{}:a;for(var e in a)a[e]=ref(this.ref_table,a[e]),this.ref_assoc[e]=a[e];this.built_form=JSON.parse(JSON.stringify(this.form_object));this.built_form=FormBuilder.replaceStatements(this.built_form,a,this.defs_object,this.ref_table,this.ref_assoc);FormBuilder.debugStop(b)}; -FormBuilder.prototype.update=function(a){var b=FormBuilder.debugStart("FormBuilder.update",1);a=null==a?{}:a;for(var e in a)this.ref_assoc.hasOwnProperty(e)&&(this.ref_table[this.ref_assoc[e]]=a[e]);FormBuilder.debugStop(b)}; -FormBuilder.prototype.attach=function(a){var b=FormBuilder.debugStart("FormBuilder.attach",1);if(!(a instanceof Element)&&null===this.parent_element)return!1;this.parent_element=a instanceof Element?a:this.parent_element;this.built_form.hasOwnProperty("dom")&&FormBuilder.detachElements(this.parent_element,this.built_form.dom);a=FormBuilder.createElements(this.built_form,this.ref_table,this.ref_assoc);FormBuilder.attachElements(this.parent_element,a);FormBuilder.debugStop(b)}; -FormBuilder.fetchNodeDefinition=function(a,b){var e=FormBuilder.debugStart("FormBuilder::fetchNodeDefinition",2);FormBuilder.debug('node = "'+a+'"',2);var d,f;r=FormBuilder.regex.reg_in_key;if("undefined"!=typeof b&&b.hasOwnProperty(a))return FormBuilder.debugStop(e),{def:b[a]};for(d in b)if(r.test(d)&&(f=new RegExp(d.slice(1,-1)),f.test(a))){matches={};for(f=1;ff;f++)matches["$"+f]=RegExp["$"+f];FormBuilder.debugStop(e);return{def:b[d],scope:matches}}FormBuilder.debugStop(e);return{}}; -FormBuilder.replaceStatements=function(a,b,e,d,f){var g=FormBuilder.debugStart("FormBuilder::replaceStatements",2);a=a instanceof Object?a:{};b=b instanceof Object?JSON.parse(JSON.stringify(b)):{};var c,h;if(a.hasOwnProperty("scope")&&a.scope instanceof Object)for(c in a.scope)b[c]=a.scope[c];if(a.hasOwnProperty("node")&&"string"==typeof a.node&&(h=FormBuilder.fetchNodeDefinition(a.node,e),h.hasOwnProperty("def")&&(a.node_link=JSON.parse(JSON.stringify(h.def)),h.hasOwnProperty("scope"))))for(c in h.scope)b[c]= -h.scope[c];a.hasOwnProperty("browse")&&(a.browse.hasOwnProperty("array")&&FormBuilder.regex.arr_out_set.test(a.browse.array)?a.browse.id=RegExp.$1:delete a.browse);for(c in a)"string"==typeof a[c]?(a[c]=[a[c]],h=FormBuilder.replaceStatementsFunction(a[c][0],b,d),!1!==h?a[c]=h:(h=FormBuilder.replaceStatementsArray(a[c][0],b,d),!1!==h?a[c]=h:(a[c]=FormBuilder.replaceStatementsRegex(a[c],b),a[c]=FormBuilder.replaceStatementsPrimary(a[c],b),a[c]=FormBuilder.replaceStatementsArrayValue(a[c],b,d,f)))): -"number"===typeof a[c]&&(a[c]=[ref(d,a[c])]);for(c in a)FormBuilder.regex.pri_in_key.test(c)?b[c.substring(1)]=ref(d,a[c]):FormBuilder.regex.arr_in_key.test(c)&&(b[c.substring(2)]=ref(d,a[c]));b=JSON.parse(JSON.stringify(b));for(c in a)if(-1=e.lastIndex);)g=e.lastIndex,f.push(d);for(d=g=0;d",2);FormBuilder.debugStop(d);return a.dom=f}; -FormBuilder.attachElements=function(a,b){var e=FormBuilder.debugStart("FormBuilder::attachElements",2),d,f;for(d in b){for(f in b[d].prev)b[d].prev[f]instanceof Element&&a.appendChild(b[d].prev[f]),b[d].prev[f]instanceof Object&&FormBuilder.attachElements(a,[b[d].prev[f]]);for(f in b[d].node)b[d].node[f]instanceof Element&&a.appendChild(b[d].node[f]),b[d].node[f]instanceof Object&&FormBuilder.attachElements(a,[b[d].node[f]]);for(f in b[d].next)b[d].next[f]instanceof Element&&a.appendChild(b[d].next[f]), -b[d].next[f]instanceof Object&&FormBuilder.attachElements(a,[b[d].next[f]])}FormBuilder.debugStop(e)}; -FormBuilder.detachElements=function(a,b){var e,d;for(e in b){for(d in b[e].prev)b[e].prev[d]instanceof Element&&a.removeChild(b[e].prev[d]),b[e].prev[d]instanceof Object&&FormBuilder.detachElements(a,[b[e].prev[d]]);for(d in b[e].node)b[e].node[d]instanceof Element&&a.removeChild(b[e].node[d]),b[e].node[d]instanceof Object&&FormBuilder.detachElements(a,[b[e].node[d]]);for(d in b[e].next)b[e].next[d]instanceof Element&&a.removeChild(b[e].next[d]),b[e].next[d]instanceof Object&&FormBuilder.detachElements(a, -[b[e].next[d]])}};FormBuilder.applyCSS=function(a,b){for(var e in b)a.style[e]=b[e]}; +FormBuilder.prototype.build=function(a){var b=FormBuilder.debugStart("FormBuilder.build",1);a=null==a?{}:a;var e={},c;for(c in a)a[c]=ref(this.ref_table,a[c]),this.ref_assoc[c]=a[c],this.scope["$"+c]=this.ref_assoc[c],e["$"+c]={get:function(a,b){return function(){return a.ref_table[a.scope["$"+b]]}}(this,c),set:function(a,b){return function(c){a.ref_table[a.scope["$"+b]]=c}}(this,c)},propName=null;Object.defineProperties(this,e);this.built_form=JSON.parse(JSON.stringify(this.form_object));this.built_form= +FormBuilder.replaceStatements(this.built_form,a,this.defs_object,this.ref_table,this.ref_assoc);FormBuilder.debugStop(b)};FormBuilder.prototype.update=function(a){var b=FormBuilder.debugStart("FormBuilder.update",1);a=null==a?{}:a;for(var e in a)this.ref_assoc.hasOwnProperty(e)&&(this.ref_table[this.ref_assoc[e]]=a[e]);FormBuilder.debugStop(b)}; +FormBuilder.prototype.attach=function(a){var b=FormBuilder.debugStart("FormBuilder.attach",1);if(!(a instanceof Element)&&null===this.parent_element)return!1;this.parent_element=a instanceof Element?a:this.parent_element;this.built_form.hasOwnProperty("dom")&&(this.observer.disconnect(),FormBuilder.detachElements(this.parent_element,this.built_form.dom));FormBuilder.createElements(this.built_form,this.ref_table,this.ref_assoc);FormBuilder.attachElements(this.parent_element,this.built_form.dom);this.observer.observe(this.parent_element, +{childList:!0,attributes:!0,characterData:!0,subtree:!0,attributeOldValue:!0,characterDataOldValue:!0});FormBuilder.debugStop(b)};FormBuilder.prototype.getter=function(a){return this.ref_table[this.scope[a]]};FormBuilder.prototype.setter=function(a,b){this.ref_table[this.scope[a]]=b}; +FormBuilder.fetchNodeDefinition=function(a,b){var e=FormBuilder.debugStart("FormBuilder::fetchNodeDefinition",2);FormBuilder.debug('node = "'+a+'"',2);var c,f;r=FormBuilder.regex.reg_in_key;if("undefined"!=typeof b&&b.hasOwnProperty(a))return FormBuilder.debugStop(e),{def:b[a]};for(c in b)if(r.test(c)&&(f=new RegExp(c.slice(1,-1)),f.test(a))){matches={};for(f=1;ff;f++)matches["$"+f]=RegExp["$"+f];FormBuilder.debugStop(e);return{def:b[c],scope:matches}}FormBuilder.debugStop(e);return{}}; +FormBuilder.replaceStatements=function(a,b,e,c,f){var g=FormBuilder.debugStart("FormBuilder::replaceStatements",2);a=a instanceof Object?a:{};b=b instanceof Object?JSON.parse(JSON.stringify(b)):{};var d,h;if(a.hasOwnProperty("scope")&&a.scope instanceof Object)for(d in a.scope)b[d]=a.scope[d];if(a.hasOwnProperty("node")&&"string"==typeof a.node&&(h=FormBuilder.fetchNodeDefinition(a.node,e),h.hasOwnProperty("def")&&(a.node_link=JSON.parse(JSON.stringify(h.def)),h.hasOwnProperty("scope"))))for(d in h.scope)b[d]= +h.scope[d];a.hasOwnProperty("browse")&&(a.browse.hasOwnProperty("array")&&FormBuilder.regex.arr_out_set.test(a.browse.array)?a.browse.id=RegExp.$1:delete a.browse);for(d in a)"string"==typeof a[d]?(a[d]=[a[d]],h=FormBuilder.replaceStatementsFunction(a[d][0],b,c),!1!==h?a[d]=h:(h=FormBuilder.replaceStatementsArray(a[d][0],b,c),!1!==h?a[d]=h:(a[d]=FormBuilder.replaceStatementsRegex(a[d],b),a[d]=FormBuilder.replaceStatementsPrimary(a[d],b),a[d]=FormBuilder.replaceStatementsArrayValue(a[d],b,c,f)))): +"number"===typeof a[d]&&(a[d]=[ref(c,a[d])]);for(d in a)FormBuilder.regex.pri_in_key.test(d)?b[d.substring(1)]=ref(c,a[d]):FormBuilder.regex.arr_in_key.test(d)&&(b[d.substring(2)]=ref(c,a[d]));b=JSON.parse(JSON.stringify(b));for(d in a)if(-1=e.lastIndex);)g=e.lastIndex,f.push(c);for(c=g=0;c",2);FormBuilder.debugStop(c);return a.dom=f}; +FormBuilder.attachElements=function(a,b){var e=FormBuilder.debugStart("FormBuilder::attachElements",2),c,f;for(c in b){for(f in b[c].prev)b[c].prev[f]instanceof Element&&a.appendChild(b[c].prev[f]),b[c].prev[f]instanceof Object&&FormBuilder.attachElements(a,[b[c].prev[f]]);for(f in b[c].node)b[c].node[f]instanceof Element&&a.appendChild(b[c].node[f]),b[c].node[f]instanceof Object&&FormBuilder.attachElements(a,[b[c].node[f]]);for(f in b[c].next)b[c].next[f]instanceof Element&&a.appendChild(b[c].next[f]), +b[c].next[f]instanceof Object&&FormBuilder.attachElements(a,[b[c].next[f]])}FormBuilder.debugStop(e)}; +FormBuilder.detachElements=function(a,b){var e,c;for(e in b){for(c in b[e].prev)b[e].prev[c]instanceof Element&&a.removeChild(b[e].prev[c]),b[e].prev[c]instanceof Object&&FormBuilder.detachElements(a,[b[e].prev[c]]);for(c in b[e].node)b[e].node[c]instanceof Element&&a.removeChild(b[e].node[c]),b[e].node[c]instanceof Object&&FormBuilder.detachElements(a,[b[e].node[c]]);for(c in b[e].next)b[e].next[c]instanceof Element&&a.removeChild(b[e].next[c]),b[e].next[c]instanceof Object&&FormBuilder.detachElements(a, +[b[e].next[c]])}};FormBuilder.applyCSS=function(a,b){for(var e in b)a.style[e]=b[e]};FormBuilder.DOMUpdates=function(a){console.log(a)}; diff --git a/js/lib/form-builder.js b/js/lib/form-builder.js index 55ed15c..918d4b3 100644 --- a/js/lib/form-builder.js +++ b/js/lib/form-builder.js @@ -43,9 +43,16 @@ var ref = function(ref_table, variable){ */ var FormBuilder = function(form_object){ + /* [1] Enregistrement du formulaire + =========================================================*/ /* On définit le formulaire (sous forme de description formelle) */ this.form_object = form_object; + + /* [2] On initialise notre Observer + =========================================================*/ + this.observer = new MutationObserver( FormBuilder.DOMUpdates ); + }; @@ -67,7 +74,9 @@ FormBuilder.prototype = { built_form: null, // Object correspondant au formulaire construit root_element: null, // Element correspondant à l'objet construit ref_table: {'$00000000$': null}, // Tableau contenant la liste des références - ref_assoc: {'NULL': '$00000000$'} // Association entre table de référence et scope d'entrée + ref_assoc: {'NULL': '$00000000$'}, // Association entre table de référence et scope d'entrée + observer: this.observer, // Observeur du sous-DOM qui sera créé + scope: {} // Scope pour les variables (getters + setters) }; @@ -191,15 +200,43 @@ FormBuilder.prototype.build = function(scope){ /* (1) On initialise le scope vide s'il n'est pas donné */ scope = (scope == null) ? {} : scope; + var properties = {}; + /* (2) On transforme toutes les variables en références */ for( var key in scope ){ + // On enregistre la référence scope[key] = ref(this.ref_table, scope[key]); // On enregistre l'association, pour modifier plus tard this.ref_assoc[key] = scope[key]; + + // On ajoute une entrée dans le @scope + // this.scope['$'+key] = this.ref_assoc[key]; + this.scope['$'+key] = this.ref_assoc[key]; + + var fset = function(o, k, v){ o.ref_table[ o.scope['$'+k] ] = v; }; + + properties['$'+key] = { + get: (function(o, k){ return function(){ + + return o.ref_table[ o.scope['$'+k] ]; + + }; })(this, key), + set: (function(o, k){ return function(v){ + + o.ref_table[ o.scope['$'+k] ] = v; + + }; })(this, key) + }; + + + propName = null; + } + Object.defineProperties(this, properties); + /* [1] On clone l'object =========================================================*/ this.built_form = JSON.parse(JSON.stringify(this.form_object)); @@ -265,6 +302,10 @@ FormBuilder.prototype.attach = function(parent){ =========================================================*/ if( this.built_form.hasOwnProperty('dom') ){ + /* (1) On déconnecte l'observer */ + this.observer.disconnect(); + + /* (2) On détache les éléments */ FormBuilder.detachElements(this.parent_element, this.built_form.dom); } @@ -273,14 +314,48 @@ FormBuilder.prototype.attach = function(parent){ /* [1] On construit le DOM =========================================================*/ + /* (1) On récupère les éléments */ var dom = FormBuilder.createElements(this.built_form, this.ref_table, this.ref_assoc); - FormBuilder.attachElements(this.parent_element, dom); + /* (2) On attache les éléments */ + FormBuilder.attachElements(this.parent_element, this.built_form.dom); + + /* (3) On lance l'observer */ + this.observer.observe(this.parent_element, { + childList: true, + attributes: true, + characterData: true, + subtree: true, + attributeOldValue: true, + characterDataOldValue: true + }); FormBuilder.debugStop(dbg); }; +/* CUSTOM GETTER DE VARIABLE +* +* @varName Nom de la variable +* +* @return varValue Retourne la valeur de la variable +* +*/ +FormBuilder.prototype.getter = function(varName){ + return this.ref_table[ this.scope[varName] ]; +}; + + +/* CUSTOM SETTER DE VARIABLE +* +* @varName Nom de la variable +* @newValue Nouvelle valeur de la variable +* +*/ +FormBuilder.prototype.setter = function(varName, newValue){ + this.ref_table[ this.scope[varName] ] = newValue; +}; + /************************************************/ /* ____ _____ _ _____ ___ ____ */ /* / ___|_ _|/ \|_ _|_ _/ ___| */ @@ -1242,7 +1317,7 @@ FormBuilder.attachElements = function(parent, set){ }; -/* DETACHE UN JEU D'ELEMENTS A UN PARENT +/* DETACHE UN JEU D'ELEMENTS D'UN PARENT * * @parent Element parent * @set Set d'enfants à attacher @@ -1321,3 +1396,9 @@ FormBuilder.applyCSS = function(element, css){ element.style[r] = css[r]; }; + + +FormBuilder.DOMUpdates = function(events){ + // TODO + console.log(events); +}; diff --git a/js/lib/form-builder/main-min.js b/js/lib/form-builder/main-min.js index b371b0a..f80c726 100644 --- a/js/lib/form-builder/main-min.js +++ b/js/lib/form-builder/main-min.js @@ -2,4 +2,4 @@ document.body.innerHTML="";"use strict"; var default_definition={input:{node_type:"input"},"/^h([1-6])$/":{node_type:"h{$1}"},br:{node_type:"br"},option:{node_type:"option"},select:{node_type:"select"},span:{node_type:"span"},"/^br([0-9]+)$/":{node:"br",repeat:{n:"{$1}",id:"brs"}}},custom_definition={"/^input.([a-z]+)$/":{node:"input",attributes:{type:"{$1}","data-name":"{name}",value:"{value}",placeholder:"{placeholder}"},listeners:{click:"{click_listener()}"}},"custom-select":{node:"span",attributes:{"class":"select-container nobold"},children:[{node:"select", attributes:{"data-name":"{name}"},children:[{node:"option",attributes:{value:"{options:i}"},text:"{options.value}",browse:{array:"{options[]}",funcs:{"options.value":"{getoptval()}"}}}],listeners:{change:"{listener()}"}}]}},contactForm={node:"h4",attributes:{"data-icon":"o","class":"new-contact colo2"},children:[{node:"input.hidden",$name:"uid",$value:"{uid}"},{node:"input.hidden",$name:"call",$value:"{call}"},{node:"input.hidden",$name:"sms",$value:"{sms}"},{node:"input.hidden",$name:"countcall", $value:"{count_call}",$click_listener:"{my_listener()}"},{node:"input.hidden",$name:"countsms",$value:"{count_sms}"},{node:"input.text",$name:"number",$value:"{number}"},{node:"custom-select",$name:"existing",$options:"{existing[]}",$listener:"{existingsel()}"},{node:"input.text",$name:"username",$placeholder:"{username_ph}",$value:"{username}"},{node:"input.submit",$value:"Enregistrer",attributes:{"class":"primary sub-number"}}],next_nodes:[{node:"br"}]},a="

\n\t\n\t\n\t\n\t\n\t\n\t \n\t\n\t    ou    \n\t \n\t\n

\n\n", -fb=new FormBuilder(contactForm);fb.add_definition(default_definition);fb.add_definition(custom_definition);fb.build({uid:1,call:2,sms:3,count_call:4,count_sms:5,number:"01 02 03 04 05",existing:["Jean","Archibald","Daniel","Maurice"],username:"moi-meme",my_listener:function(b){console.log("clicked",b)},existingsel:function(b){console.log("selected",b)},getoptval:function(b){return b}});fb.attach(document.body); +fb=new FormBuilder(contactForm);fb.add_definition(default_definition);fb.add_definition(custom_definition);fb.build({uid:1,call:2,sms:3,count_call:4,count_sms:5,number:"01 02 03 04 05",existing:["Jean","Archibald","Daniel","Maurice"],username:"moi-meme",username_ph:"Pseudo",my_listener:function(b){console.log("clicked",b)},existingsel:function(b){console.log("selected",b)},getoptval:function(b){return b}});fb.attach(document.body); diff --git a/js/lib/form-builder/main.js b/js/lib/form-builder/main.js index 0e856fe..345346f 100644 --- a/js/lib/form-builder/main.js +++ b/js/lib/form-builder/main.js @@ -103,6 +103,7 @@ var a = ("

\n"+ // FormBuilder.debug_time = true; // FormBuilder.debug_time_details = true; + var fb = new FormBuilder(contactForm); fb.add_definition(default_definition); fb.add_definition(custom_definition); @@ -115,8 +116,8 @@ fb.build({ number: '01 02 03 04 05', existing: ['Jean', 'Archibald', 'Daniel', 'Maurice'], username: 'moi-meme', - // username_ph: 'Pseudo', - my_listener: function(e){ console.log('clicked', e); }, + username_ph: 'Pseudo', + my_listener: function(e){ console.log('clicked', e); }, existingsel: function(e){ console.log('selected', e); }, getoptval: function(opt){ return opt; } });