1524 lines
42 KiB
JavaScript
1524 lines
42 KiB
JavaScript
/****************************************************/
|
|
/* _ _ _____ ___ _ ___ _______ __ */
|
|
/* | | | |_ _|_ _| | |_ _|_ _\ \ / / */
|
|
/* | | | | | | | || | | | | | \ V / */
|
|
/* | |_| | | | | || |___ | | | | | | */
|
|
/* \___/ |_| |___|_____|___| |_| |_| */
|
|
/****************************************************/
|
|
/* [1] REFERENCES DE VALEURS
|
|
=========================================================*/
|
|
// Construction d'un référence
|
|
var ref = function(ref_table, variable){
|
|
/* (1) On cherche une nouvelle clé */
|
|
var key = null;
|
|
|
|
while( key == null || ref_table.hasOwnProperty(key) )
|
|
key = '$'+ ( 0x10000000+Math.floor( Math.random()*0xefffffff) ).toString(16)+'$';
|
|
|
|
/* (2) On attribue la valeur */
|
|
ref_table[key] = variable;
|
|
|
|
/* (3) On retourne la clé */
|
|
return key;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************************/
|
|
/* _____ ___ ____ __ __ ____ _ _ ___ _ ____ _____ ____ */
|
|
/* | ___/ _ \| _ \| \/ | | __ )| | | |_ _| | | _ \| ____| _ \ */
|
|
/* | |_ | | | | |_) | |\/| |_____| _ \| | | || || | | | | | _| | |_) | */
|
|
/* | _|| |_| | _ <| | | |_____| |_) | |_| || || |___| |_| | |___| _ < */
|
|
/* |_| \___/|_| \_\_| |_| |____/ \___/|___|_____|____/|_____|_| \_\ */
|
|
/************************************************************************************/
|
|
|
|
|
|
/* CONSTRUCTEUR -> INITIALISE UNE L'INSTANCE
|
|
*
|
|
* @form_object<Object> Objet définissant le formulaire
|
|
*
|
|
*/
|
|
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 );
|
|
|
|
};
|
|
|
|
|
|
/************************************************************************/
|
|
/* _ _____ _____ ____ ___ ____ _ _ _____ _____ ____ */
|
|
/* / \|_ _|_ _| _ \|_ _| __ )| | | |_ _| ____/ ___| */
|
|
/* / _ \ | | | | | |_) || || _ \| | | | | | | _| \___ \ */
|
|
/* / ___ \| | | | | _ < | || |_) | |_| | | | | |___ ___) | */
|
|
/* /_/ \_\_| |_| |_| \_\___|____/ \___/ |_| |_____|____/ */
|
|
/************************************************************************/
|
|
|
|
/* DEFINITION DES ATTRIBUTS
|
|
*
|
|
*/
|
|
FormBuilder.prototype = {
|
|
form_object: this.form_object, // objet permettant la construction du formulaire
|
|
defs_object: {}, // objet des définitions des éléments
|
|
parent_element: null, // element qui contiendra le formulaire
|
|
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
|
|
observer: this.observer, // Observeur du sous-DOM qui sera créé
|
|
scope: {} // Scope pour les variables (getters + setters)
|
|
};
|
|
|
|
|
|
/* DEFINITION DES ATTRIBUTS STATIQUES
|
|
*
|
|
*/
|
|
FormBuilder.regex = {
|
|
reg_in_key: /^\/\^(.+)\$\/$/, // Regex associée à une "regex" incluse dans une clé
|
|
reg_out_val: /\{(\$[1-9])\}/, // Regex associée à la valeur du dernier match de "regex"
|
|
|
|
pri_out_val: /\{([a-z_]+)\}/g, // Regex associée à une variable primitif à remplacer
|
|
pri_in_key: /^\$([a-z_]+)$/, // Regex associée à la clé d'une variable primitive
|
|
|
|
arr_out_set: /^\{([a-z_]+)\[\]\}$/, // Regex associée à un tableau à remplacer
|
|
arr_out_val: /\{([a-z_]+)([\.:])([a-z_]+)\}/g, // Regex associée à une valeur de tableau à remplacer (primitif)
|
|
arr_in_key: /^\$([a-z_]+)$/, // Regex associée à la clé d'un tableau
|
|
|
|
fun_out_val: /^\{([a-z_]+)\(\)\}$/, // Regex associée à une function incluse dans une clé
|
|
|
|
ref_pri: /^\$[a-f0-9]{8}\$$/ // Clé de référence
|
|
};
|
|
|
|
FormBuilder.spread_attr = [ // Liste des attributs diffusant le scope
|
|
'children', // diffuse aux éléments
|
|
'next_nodes', // diffuse aux éléments
|
|
'prev_nodes', // diffuse aux éléments
|
|
'attributes', // diffuse aux attributs
|
|
'node_link',
|
|
'listeners',
|
|
|
|
'repeat',
|
|
'browse',
|
|
'funcs'
|
|
];
|
|
|
|
FormBuilder.spec_attr = [ // Liste des attributs à dupliquer jusque dans la definition primaire
|
|
'_value',
|
|
'_selected'
|
|
];
|
|
|
|
// Configuration des observers
|
|
FormBuilder.observe = {
|
|
attributes: {
|
|
attributes: true,
|
|
attributeOldValue: true,
|
|
childList: false,
|
|
characterData: false,
|
|
subtree: false,
|
|
characterDataOldValue: false
|
|
},
|
|
characterData: {
|
|
attributes: false,
|
|
attributeOldValue: false,
|
|
childList: false,
|
|
characterData: true,
|
|
subtree: false,
|
|
characterDataOldValue: true
|
|
}
|
|
};
|
|
|
|
// DEBUG des performances
|
|
FormBuilder.debug_time = false;
|
|
FormBuilder.debug_time_details = false;
|
|
|
|
/* DEMARRAGE DU DEBUG
|
|
*/
|
|
FormBuilder.debugStart = function(group, type){
|
|
if( type == 1 && FormBuilder.debug_time ){}
|
|
else if( type == 2 && FormBuilder.debug_time_details ){}
|
|
else return {type: 0};
|
|
|
|
var time_r = '['+ parseInt( Math.random()*0xeffffffff ).toString(16) +']';
|
|
|
|
console.time(time_r);
|
|
console.group(group);
|
|
|
|
return {
|
|
type: type,
|
|
time_r: time_r,
|
|
group: group
|
|
};
|
|
};
|
|
|
|
/* MESSAGE DE DEBUG
|
|
*/
|
|
FormBuilder.debug = function(message, type){
|
|
if( type == 1 && FormBuilder.debug_time ){}
|
|
else if( type == 2 && FormBuilder.debug_time_details ){}
|
|
else return {type: 0};
|
|
|
|
console.debug(message);
|
|
};
|
|
|
|
/* AFFICHAGE DU DEBUG
|
|
*/
|
|
FormBuilder.debugStop = function(obj){
|
|
if( obj.type == 1 && FormBuilder.debug_time ){}
|
|
else if( obj.type == 2 && FormBuilder.debug_time_details ){}
|
|
else return null;
|
|
|
|
|
|
console.timeEnd(obj.time_r);
|
|
console.groupEnd(obj.group);
|
|
};
|
|
|
|
// FormBuilder.debugStart = function(){ console.time(); };
|
|
// FormBuilder.debugStop = function(s){ console.timeEnd(); };
|
|
|
|
/************************************************************/
|
|
/* __ __ _____ _____ _ _ ___ ____ ____ */
|
|
/* | \/ | ____|_ _| | | |/ _ \| _ \/ ___| */
|
|
/* | |\/| | _| | | | |_| | | | | | | \___ \ */
|
|
/* | | | | |___ | | | _ | |_| | |_| |___) | */
|
|
/* |_| |_|_____| |_| |_| |_|\___/|____/|____/ */
|
|
/************************************************************/
|
|
|
|
/* AJOUTE UNE DEFINITION
|
|
*
|
|
* @def_object<Object> Objet de définition
|
|
*
|
|
*/
|
|
FormBuilder.prototype.add_definition = function(def_object){
|
|
var dbg = FormBuilder.debugStart('FormBuilder.add_definition', 1);
|
|
|
|
|
|
/* [1] On ajoute la définition
|
|
==================================================================*/
|
|
for( var key in def_object )
|
|
this.defs_object[key] = def_object[key];
|
|
|
|
|
|
FormBuilder.debugStop(dbg);
|
|
};
|
|
|
|
|
|
/* ON CONSTRUIT L'OBJET
|
|
*
|
|
* @scope<Object> [OPT] Objet contenant les variables à passer
|
|
*
|
|
*/
|
|
FormBuilder.prototype.build = function(scope){
|
|
var dbg = FormBuilder.debugStart('FormBuilder.build', 1);
|
|
|
|
/* [0] Gestion du paramètres
|
|
==================================================================*/
|
|
/* (1) On initialise le scope vide s'il n'est pas donné */
|
|
scope = (scope == null) ? {} : scope;
|
|
|
|
/* (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; };
|
|
|
|
/* (1) On définit le getter */
|
|
this.__defineGetter__('$'+key, (function(o, k){ return function(){
|
|
|
|
return o.ref_table[ o.scope['$'+k] ];
|
|
|
|
}; })(this, key) );
|
|
|
|
/* (2) On définit le setter */
|
|
this.__defineSetter__('$'+key, (function(o, k){ return function(v){
|
|
|
|
o.ref_table[ o.scope['$'+k] ] = v;
|
|
o.attach();
|
|
|
|
}; })(this, key) );
|
|
|
|
}
|
|
|
|
|
|
/* [1] On clone l'object
|
|
=========================================================*/
|
|
this.built_form = JSON.parse(JSON.stringify(this.form_object));
|
|
|
|
/* [2] On remplace les valeurs
|
|
==================================================================*/
|
|
this.built_form = FormBuilder.replaceStatements(this.built_form, scope, this.defs_object, this.ref_table, this.ref_assoc);
|
|
|
|
FormBuilder.debugStop(dbg);
|
|
};
|
|
|
|
|
|
/* ON MODIFIE L'OBJET (scope uniquement)
|
|
*
|
|
* @scope<Object> [OPT] Objet contenant les variables à modifier
|
|
*
|
|
*/
|
|
FormBuilder.prototype.update = function(scope){
|
|
var dbg = FormBuilder.debugStart('FormBuilder.update', 1);
|
|
|
|
/* [0] Gestion du paramètres
|
|
==================================================================*/
|
|
/* (1) On initialise le scope vide s'il n'est pas donné */
|
|
scope = (scope == null) ? {} : scope;
|
|
|
|
/* (2) On récupère toutes les références des variables */
|
|
for( var key in scope ){
|
|
|
|
// si on trouve l'association
|
|
if( this.ref_assoc.hasOwnProperty(key) ){
|
|
|
|
// On modifie la valeur
|
|
this.ref_table[ this.ref_assoc[key] ] = scope[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FormBuilder.debugStop(dbg);
|
|
};
|
|
|
|
|
|
|
|
/* CONSTRUIT LES DOM ASSOCIE A L'OBJET CONSTRUIT
|
|
*
|
|
* @parent<Element> Element auquel rattacher le formulaire
|
|
*
|
|
*/
|
|
FormBuilder.prototype.attach = function(parent){
|
|
var dbg = FormBuilder.debugStart('FormBuilder.attach', 1);
|
|
|
|
/* [0] Initialisation
|
|
=========================================================*/
|
|
/* (1) Gestion du paramètre @parent */
|
|
if( !(parent instanceof Element) && this.parent_element === null )
|
|
return false;
|
|
|
|
this.parent_element = (parent instanceof Element) ? parent : this.parent_element;
|
|
|
|
var d, i, j;
|
|
|
|
/* [1] Si on avait déja construit, on retire le dom
|
|
=========================================================*/
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* [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);
|
|
|
|
/* (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, FormBuilder.observe.attributes);
|
|
|
|
FormBuilder.debugStop(dbg);
|
|
};
|
|
|
|
/************************************************/
|
|
/* ____ _____ _ _____ ___ ____ */
|
|
/* / ___|_ _|/ \|_ _|_ _/ ___| */
|
|
/* \___ \ | | / _ \ | | | | | */
|
|
/* ___) || |/ ___ \| | | | |___ */
|
|
/* |____/ |_/_/ \_\_| |___\____| */
|
|
/************************************************/
|
|
|
|
|
|
/* CHERCHE UNE DEFINITION CORRESPONDANT A L'ATTRIBUT 'node'
|
|
*
|
|
* @node<String> Nom du node pour lequel trouver la définition
|
|
* @defs<Object> Objet de définition
|
|
*
|
|
* @return node_definition<Object> Retourne la définition pour le 'node' en question
|
|
* ou NULL si on ne trouve rien
|
|
*
|
|
*/
|
|
FormBuilder.fetchNodeDefinition = function(node, defs){
|
|
var dbg = FormBuilder.debugStart('FormBuilder::fetchNodeDefinition', 2);
|
|
FormBuilder.debug('node = "'+node+'"', 2);
|
|
|
|
/* [0] Initialisation
|
|
==================================================================*/
|
|
var m = null, key, i, regex;
|
|
r = FormBuilder.regex.reg_in_key;
|
|
|
|
|
|
/* [1] Si la définition existe, on la retourne
|
|
==================================================================*/
|
|
if( typeof defs != 'undefined' && defs.hasOwnProperty(node) ){
|
|
|
|
FormBuilder.debugStop(dbg);
|
|
|
|
return { def: defs[node] };
|
|
|
|
|
|
/* [2] Sinon, on cherche une REGEX
|
|
==================================================================*/
|
|
}else{
|
|
|
|
// Pour chaque définition
|
|
for( key in defs ){
|
|
|
|
/* (2.1) On regarde s'il n'y a pas de REGEX dans la clé
|
|
---------------------------------------------------------*/
|
|
if( r.test(key) ){
|
|
|
|
// On construit la regex
|
|
regex = new RegExp( key.slice(1, -1) );
|
|
|
|
/* (1) Si la regex match */
|
|
if( (m=regex.test(node)) ){
|
|
|
|
/* (2) On récupère les 'match' */
|
|
matches = {};
|
|
|
|
for( i = 1 ; i < RegExp.length && i < 10 ; i++ )
|
|
matches['$'+i] = RegExp['$'+i];
|
|
|
|
FormBuilder.debugStop(dbg);
|
|
|
|
/* (3) On renvoie le lien + le scope */
|
|
return { def: defs[key], scope: matches };
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FormBuilder.debugStop(dbg);
|
|
|
|
// Si on a rien trouvé, on retourne NULL
|
|
return {};
|
|
|
|
};
|
|
|
|
|
|
/* REMPLACE RECURSIVEMENT LES VALEURS DE @OBJECT AVEC LE @SCOPE -> RECURSIF
|
|
*
|
|
* @object<Object> Objet dans lequel remplacer les valeurs
|
|
* @scope<Object> Ensemble des variables permettant le remplacement
|
|
* @definitions<Object> Définitions des éléments
|
|
* @ref_table<Object> Table des références
|
|
* @ref_assoc<Object> Table des associations de références
|
|
*
|
|
* @return replaced<Object> Objet avec les remplacements effectués
|
|
*
|
|
*/
|
|
FormBuilder.replaceStatements = function(object, scope, definitions, ref_table, ref_assoc){
|
|
var dbg = FormBuilder.debugStart('FormBuilder::replaceStatements', 2);
|
|
|
|
|
|
/* [0] Initialisation
|
|
==================================================================*/
|
|
/* (1) Paramètres */
|
|
object = (object instanceof Object) ? object : {};
|
|
scope = (scope instanceof Object) ? JSON.parse(JSON.stringify(scope)) : {};
|
|
|
|
/* (2) Variables */
|
|
var key, r, tmp, m, found, lasti, s, parts;
|
|
var m_fun, m_arr, m_reg, m_pri, m_aval;
|
|
|
|
/* (3) On récupère le scope s'il est dans l'attribut 'scope' */
|
|
if( object.hasOwnProperty('scope') && object.scope instanceof Object )
|
|
for( key in object.scope )
|
|
scope[key] = object.scope[key];
|
|
|
|
|
|
/* [1] On lie les définitions de l'attribut 'node' -> 'node_link'
|
|
==================================================================*/
|
|
if( object.hasOwnProperty('node') && typeof object.node == 'string' ){
|
|
|
|
/* On cherche une définition */
|
|
found = FormBuilder.fetchNodeDefinition(object.node, definitions);
|
|
|
|
// Si on trouve
|
|
if( found.hasOwnProperty('def') ){
|
|
|
|
// 1. On clone la définition dans l'attribut 'node_link'
|
|
object.node_link = JSON.parse(JSON.stringify(found.def));
|
|
|
|
// 2. On ajoute les matches dans l'attribut 'scope'
|
|
if( found.hasOwnProperty('scope') )
|
|
for( key in found.scope )
|
|
scope[key] = found.scope[key];
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/* [2] Gestion de l'attribut 'browse'
|
|
=========================================================*/
|
|
if( object.hasOwnProperty('browse') ){
|
|
|
|
// Si le champ est correct, on définit l'ID avec le nom du tableau
|
|
if( object.browse.hasOwnProperty('array') && FormBuilder.regex.arr_out_set.test(object.browse.array) )
|
|
object.browse.id = RegExp.$1;
|
|
|
|
// Sinon, on supprime le 'browse'
|
|
else
|
|
delete object.browse;
|
|
|
|
}
|
|
|
|
|
|
/* [3] On remplace les valeurs
|
|
==================================================================*/
|
|
for( key in object ){
|
|
|
|
/* [1.1] Si c'est une string, on regarde s'il faut remplacer
|
|
==================================================================*/
|
|
if( typeof object[key] == 'string' ){
|
|
|
|
// On transforme en tableau
|
|
object[key] = [object[key]];
|
|
|
|
|
|
|
|
/* (2.1) On cherche toutes les FONCTIONS à remplacer
|
|
---------------------------------------------------------*/
|
|
/* (1) On récupère le remplacement */
|
|
m_fun = FormBuilder.replaceStatementsFunction(object[key][0], scope, ref_table);
|
|
|
|
/* (2) Si on un remplacement, on remplace, et on passe à la clé suivante */
|
|
if( m_fun !== false ){
|
|
object[key] = m_fun;
|
|
continue;
|
|
}
|
|
|
|
/* (2.2) On cherche tous les TABLEAUX à remplacer
|
|
---------------------------------------------------------*/
|
|
/* (1) On récupère le remplacement */
|
|
m_arr = FormBuilder.replaceStatementsArray(object[key][0], scope, ref_table);
|
|
|
|
/* (2) Si on un remplacement, on remplace, et on passe à la clé suivante */
|
|
if( m_arr !== false ){
|
|
object[key] = m_arr;
|
|
continue;
|
|
}
|
|
|
|
|
|
/* (2.3) On cherche toutes les match de REGEX à remplacer
|
|
---------------------------------------------------------*/
|
|
/* (1) On récupère les remplacements */
|
|
object[key] = FormBuilder.replaceStatementsRegex(object[key], scope);
|
|
|
|
|
|
/* (2.4) On cherche toutes les variables PRIMITIVES à remplacer
|
|
---------------------------------------------------------*/
|
|
/* (1) On récupère les remplacements */
|
|
object[key] = FormBuilder.replaceStatementsPrimary(object[key], scope);
|
|
|
|
|
|
/* (2.5) On cherche toutes les VALEURS DE REPEAT à remplacer
|
|
---------------------------------------------------------*/
|
|
/* (1) On récupère les remplacements */
|
|
object[key] = FormBuilder.replaceStatementsArrayValue(object[key], scope, ref_table, ref_assoc);
|
|
|
|
|
|
/* [1.2] Si c'est un type primitif, on le référencie
|
|
=========================================================*/
|
|
}else if( typeof object[key] === 'number' )
|
|
object[key] = [ ref(ref_table, object[key]) ];
|
|
|
|
|
|
}
|
|
|
|
|
|
/* [4] On ajoute les variables '$var' et '$$arr' au scope suivant
|
|
==================================================================*/
|
|
for( key in object ){
|
|
|
|
/* (1) Ajout des variables de type '$nomVar'
|
|
---------------------------------------------------------*/
|
|
if( FormBuilder.regex.pri_in_key.test(key) )
|
|
scope[ key.substring(1) ] = ref( ref_table, object[key] );
|
|
|
|
/* (2) Ajout des tableaux de type '$$nomArr'
|
|
---------------------------------------------------------*/
|
|
else if( FormBuilder.regex.arr_in_key.test(key) )
|
|
scope[ key.substring(2) ] = ref( ref_table, object[key] );
|
|
|
|
}
|
|
|
|
|
|
/* [5] On lance récursivement
|
|
==================================================================*/
|
|
/* on clone le scope */
|
|
scope = JSON.parse(JSON.stringify(scope));
|
|
|
|
for( key in object ){
|
|
|
|
/* S'il ne s'agit d'un attribut interdit */
|
|
if( FormBuilder.spread_attr.indexOf(key) > -1 ){
|
|
|
|
|
|
/* (1) Si c'est un tableau, on lance récursivement pour chaque item */
|
|
if( object[key] instanceof Array ){
|
|
|
|
for( var i in object[key] ){
|
|
|
|
// on lance récursivement
|
|
FormBuilder.debug('**'+key+'['+i+']', 2);
|
|
FormBuilder.replaceStatements(object[key][i], scope, definitions, ref_table, ref_assoc);
|
|
|
|
}
|
|
|
|
|
|
/* (2) Si c'est un objet, on lance récursivement */
|
|
}else if( object[key] instanceof Object ){
|
|
|
|
// on lance récursivement
|
|
FormBuilder.debug('**'+key, 2);
|
|
FormBuilder.replaceStatements(object[key], scope, definitions, ref_table, ref_assoc);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/* [5] On retourne l'object courant
|
|
==================================================================*/
|
|
FormBuilder.debugStop(dbg);
|
|
|
|
return object;
|
|
};
|
|
|
|
|
|
/* REMPLACE UNE FUNCTION SOUS LA FORME "{funcName}()" par sa référence
|
|
*
|
|
* @statement<String> String contenant la chaine
|
|
* @scope<Object> Objet contenant le scope
|
|
* @ref_table<Object> Objet contenant les références
|
|
*
|
|
* @return newVal<String> Retourne la nouvelle (ref) valeur ou FALSE si rien n'a été fais
|
|
*
|
|
*/
|
|
FormBuilder.replaceStatementsFunction = function(statement, scope, ref_table){
|
|
/* (1) On initialise les variables */
|
|
var match = null;
|
|
var regex = FormBuilder.regex.fun_out_val;
|
|
|
|
/* (2) On exécute la regex */
|
|
match = regex.exec(statement);
|
|
|
|
/* (3) Si ça match pas, on retourne FALSE */
|
|
if( match === null )
|
|
return false;
|
|
|
|
/* (4) Sinon, si la fonction n'est pas dans le scope, on l'initialise */
|
|
if( !scope.hasOwnProperty(match[1]) )
|
|
scope[match[1]] = ref( ref_table, function(){} ); // on met une fonction vide
|
|
|
|
/* (5) On remplace le 'statement' par la fonction */
|
|
return scope[match[1]];
|
|
|
|
};
|
|
|
|
|
|
/* REMPLACE UN TABLEAU SOUS LA FORME "{{arrayName}}" par sa référence
|
|
*
|
|
* @statement<String> String contenant la chaine
|
|
* @scope<Object> Objet contenant le scope
|
|
* @ref_table<Object> Objet contenant les références
|
|
*
|
|
* @return newVal<String> Retourne la nouvelle (ref) valeur ou FALSE si rien n'a été fais
|
|
*
|
|
*/
|
|
FormBuilder.replaceStatementsArray = function(statement, scope, ref_table){
|
|
/* (1) On initialise les variables */
|
|
var match = null;
|
|
var regex = FormBuilder.regex.arr_out_set;
|
|
|
|
/* (2) On exécute la regex */
|
|
match = regex.exec(statement);
|
|
|
|
/* (3) Si ça match pas, on retourne FALSE */
|
|
if( match === null )
|
|
return false;
|
|
|
|
/* (4) Sinon, si le tableau n'est pas dans le scope, on l'initialise */
|
|
if( !scope.hasOwnProperty(match[1]) )
|
|
scope[match[1]] = ref( ref_table, []); // on met un tableau vide
|
|
|
|
/* (5) On remplace le 'statement' par le tableau */
|
|
return scope[match[1]];
|
|
|
|
};
|
|
|
|
|
|
/* REMPLACE LES VALEURS DE MATCH DE REGEX SOUS LA FORME "{$matchNumber}" par leur référence
|
|
*
|
|
* @statements<Array> Tableau contenant les parties de la chaine
|
|
* @scope<Object> Objet contenant le scope
|
|
*
|
|
* @return splitVal<Array> Tableau contenant les parties de la chaine (références + chaine)
|
|
*
|
|
*/
|
|
FormBuilder.replaceStatementsRegex = function(statements, scope){
|
|
/* [1] Initialisation
|
|
=========================================================*/
|
|
var regex = FormBuilder.regex.reg_out_val;
|
|
var match = null;
|
|
var matches = [];
|
|
var lasti, parts, p, i, key;
|
|
|
|
/* [2] Pour chaque partie de la chaine
|
|
=========================================================*/
|
|
for( p = 0 ; p < statements.length ; p++ ){
|
|
|
|
/* (1) Initialisation */
|
|
m = null;
|
|
matches = [];
|
|
lasti = -1;
|
|
parts = [];
|
|
|
|
/* (2) Tant que ça match, on récupère les infos du match */
|
|
while( (match=regex.exec(statements[p])) !== null ){
|
|
// si on boucle, on sort
|
|
if( lasti >= regex.lastIndex ) break;
|
|
lasti = regex.lastIndex;
|
|
|
|
matches.push( match );
|
|
}
|
|
|
|
lasti = 0;
|
|
|
|
|
|
/* [3] Pour chaque match
|
|
=========================================================*/
|
|
for( i = 0 ; i < matches.length ; i++ ){
|
|
|
|
key = matches[i][1];
|
|
|
|
/* (1) On met la chaine d'avant le match (si existe) */
|
|
if( lasti > 0 || matches[i].index > 0 )
|
|
parts.push( statements[p].substr(lasti, matches[i].index-lasti) );
|
|
|
|
/* (2) Si la var n'est pas dans le scope, on l'initialise vide */
|
|
if( !scope.hasOwnProperty(key) )
|
|
scope[key] = ''; // on met une chaine vide
|
|
|
|
/* (3) On insère la valeur du scope */
|
|
parts.push( scope[key] );
|
|
|
|
/* (4) On met à jour l'index de fin pour la suite */
|
|
lasti = matches[i].index + matches[i][0].length;
|
|
|
|
}
|
|
|
|
/* (5) On ajoute la partie après le match */
|
|
if( lasti < statements[p].length )
|
|
parts.push( statements[p].substr(lasti, statements[p].length) );
|
|
|
|
|
|
/* [4] on remplace statements[p] par sa décomposition
|
|
=========================================================*/
|
|
statements = statements.slice(0, p).concat(parts).concat(statements.slice(p+1));
|
|
|
|
}
|
|
|
|
|
|
/* [5] On retourne la chaine modifiée (ou non)
|
|
=========================================================*/
|
|
return statements;
|
|
};
|
|
|
|
|
|
/* REMPLACE LES VARIABLE SOUS LA FORME "{varName}" par leur référence
|
|
*
|
|
* @statements<Array> Tableau contenant les parties de la chaine
|
|
* @scope<Object> Objet contenant le scope
|
|
*
|
|
* @return splitVal<Array> Tableau contenant les parties de la chaine (références + chaine)
|
|
*
|
|
*/
|
|
FormBuilder.replaceStatementsPrimary = function(statements, scope){
|
|
/* [1] Initialisation
|
|
=========================================================*/
|
|
var regex = FormBuilder.regex.pri_out_val;
|
|
var match = null;
|
|
var matches = [];
|
|
var lasti, parts, p, i, key;
|
|
|
|
|
|
/* [2] Pour chaque partie de la chaine
|
|
=========================================================*/
|
|
for( p = 0 ; p < statements.length ; p++ ){
|
|
|
|
/* (1) Initialisation */
|
|
m = null;
|
|
matches = [];
|
|
lasti = 0;
|
|
parts = [];
|
|
|
|
/* (2) Tant que ça match, on récupère les infos du match */
|
|
while( (match=regex.exec(statements[p])) !== null )
|
|
matches.push( match );
|
|
|
|
|
|
/* [3] Pour chaque match
|
|
=========================================================*/
|
|
for( i = 0 ; i < matches.length ; i++ ){
|
|
|
|
key = matches[i][1];
|
|
|
|
/* (1) On met la chaine d'avant le match (si existe) */
|
|
if( lasti > 0 || matches[i].index > 0 )
|
|
parts.push( statements[p].substr(lasti, matches[i].index-lasti) );
|
|
|
|
/* (2) Si la var n'est pas dans le scope, on l'initialise vide */
|
|
if( !scope.hasOwnProperty(key) )
|
|
scope[key] = ''; // on met une chaine vide
|
|
|
|
/* (3) On insère la valeur du scope */
|
|
parts.push( scope[key] );
|
|
|
|
/* (4) On met à jour l'index de fin pour la suite */
|
|
lasti = matches[i].index + matches[i][0].length;
|
|
|
|
}
|
|
|
|
/* (5) On ajoute la partie après le match */
|
|
if( lasti < statements[p].length )
|
|
parts.push( statements[p].substr(lasti, statements[p].length) );
|
|
|
|
|
|
/* [4] on remplace statements[p] par sa décomposition
|
|
=========================================================*/
|
|
statements = statements.slice(0, p).concat(parts).concat(statements.slice(p+1));
|
|
|
|
}
|
|
|
|
|
|
/* [5] On retourne la chaine modifiée (ou non)
|
|
=========================================================*/
|
|
return statements;
|
|
};
|
|
|
|
|
|
/* REMPLACE LES VARIABLE SOUS LA FORME "{arrName.itemValName}" par leur référence
|
|
*
|
|
* @statements<Array> Tableau contenant les parties de la chaine
|
|
* @scope<Object> Objet contenant le scope
|
|
* @ref_table<Object> Objet contenant les références
|
|
* @ref_assoc<Object> Table des associations de références
|
|
*
|
|
* @return splitVal<Array> Tableau contenant les parties de la chaine (références + chaine)
|
|
*
|
|
*/
|
|
FormBuilder.replaceStatementsArrayValue = function(statements, scope, ref_table, ref_assoc){
|
|
/* [1] Initialisation
|
|
=========================================================*/
|
|
var regex = FormBuilder.regex.arr_out_val;
|
|
var match = null;
|
|
var matches = [];
|
|
var lasti, parts, p, i, key;
|
|
|
|
|
|
/* [2] Pour chaque partie de la chaine
|
|
=========================================================*/
|
|
for( p = 0 ; p < statements.length ; p++ ){
|
|
|
|
/* (1) Initialisation */
|
|
m = null;
|
|
matches = [];
|
|
lasti = 0;
|
|
parts = [];
|
|
|
|
/* (2) Tant que ça match, on récupère les infos du match */
|
|
while( (match=regex.exec(statements[p])) !== null )
|
|
matches.push( match );
|
|
|
|
|
|
/* [3] Pour chaque match
|
|
=========================================================*/
|
|
for( i = 0 ; i < matches.length ; i++ ){
|
|
|
|
key = matches[i][1] + matches[i][2] + matches[i][3];
|
|
|
|
/* (1) On met la chaine d'avant le match (si existe) */
|
|
if( lasti > 0 || matches[i].index > 0 )
|
|
parts.push( statements[p].substr(lasti, matches[i].index-lasti) );
|
|
|
|
/* (2) On initialise la référence pour la remplir (si n'existe pas)*/
|
|
if( !ref_assoc.hasOwnProperty(key) )
|
|
ref_assoc[key] = ref(ref_table);
|
|
|
|
|
|
/* (3) On insère la valeur du scope */
|
|
parts.push( ref_assoc[key] );
|
|
|
|
/* (4) On met à jour l'index de fin pour la suite */
|
|
lasti = matches[i].index + matches[i][0].length;
|
|
|
|
}
|
|
|
|
/* (5) On ajoute la partie après le match */
|
|
if( lasti < statements[p].length )
|
|
parts.push( statements[p].substr(lasti, statements[p].length) );
|
|
|
|
|
|
/* [4] on remplace statements[p] par sa décomposition
|
|
=========================================================*/
|
|
statements = statements.slice(0, p).concat(parts).concat(statements.slice(p+1));
|
|
|
|
}
|
|
|
|
|
|
/* [5] On retourne la chaine modifiée (ou non)
|
|
=========================================================*/
|
|
return statements;
|
|
};
|
|
|
|
|
|
/* CONSTRUIT UNE CHAINE A PARTIR DE SES PARTIES (VARIABLES OU TEXTE BRUT)
|
|
*
|
|
* @ref_table<Object> Objet contenant les références
|
|
* @parts<Array> Tableau contenant les parties
|
|
*
|
|
* @return built<String> Chaine recomposée
|
|
*
|
|
*/
|
|
FormBuilder.readRef = function(ref_table, parts){
|
|
/* [0] Initialisation
|
|
=========================================================*/
|
|
var i, built = "";
|
|
|
|
|
|
/* [1] Si c'est un tableau ou une fonction, on le retourne
|
|
=========================================================*/
|
|
if( typeof parts == 'string' && FormBuilder.regex.ref_pri.test(parts) ){
|
|
|
|
// tant qu'on a une référence
|
|
while( typeof parts == 'string' && FormBuilder.regex.ref_pri.test(parts) ){
|
|
parts = ref_table[parts];
|
|
|
|
if( parts instanceof Array && parts.length == 1)
|
|
parts = parts[0];
|
|
}
|
|
|
|
return parts;
|
|
}
|
|
|
|
|
|
/* [2] Sinon, on remplace par les valeurs
|
|
=========================================================*/
|
|
for( i in parts ){
|
|
|
|
/* (1) Si référence, on ajoute la valeur (si elle existe) */
|
|
if( FormBuilder.regex.ref_pri.test(parts[i]) && ref_table.hasOwnProperty(parts[i]) ){
|
|
|
|
// si le résultat est un tableau, on lance récursivement
|
|
if( ref_table[parts[i]] instanceof Array )
|
|
built += FormBuilder.readRef(ref_table, ref_table[parts[i]]);
|
|
|
|
// sinon
|
|
else
|
|
built += ref_table[parts[i]];
|
|
|
|
/* (2) Sinon, on ajoute simplement */
|
|
}else
|
|
built += parts[i].toString();
|
|
|
|
}
|
|
|
|
|
|
/* [3] On retourne le résultat
|
|
=========================================================*/
|
|
return built;
|
|
|
|
};
|
|
|
|
|
|
/* CONSTRUIT UN ELEMENT A PARTIR D'UNE DEFINITION
|
|
*
|
|
* @definition<Object> Objet de définition de l'élément
|
|
* @ref_table<Object> Objet contenant les références
|
|
* @ref_assoc<Object> Table des associations de références
|
|
*
|
|
* @return built<Element[]> Retourne les éléments construits
|
|
*
|
|
*/
|
|
FormBuilder.createElements = function(definition, ref_table, ref_assoc){
|
|
var dbg = FormBuilder.debugStart('FormBuilder::createElements', 2);
|
|
|
|
/* [0] Initialisation
|
|
===========================================================*/
|
|
var built = [];
|
|
|
|
var i, j, k, n, tmp, b,
|
|
repeated = ['NULL'],
|
|
scope, funcs;
|
|
|
|
/* [1] Gestion de l'attribut 'repeat'
|
|
=========================================================*/
|
|
if( definition.hasOwnProperty('repeat') ){
|
|
tmp = FormBuilder.readRef( ref_table, definition.repeat.n );
|
|
|
|
// Si c'est bien un nombre
|
|
if( !isNaN(tmp) ){
|
|
|
|
/* (1) On initialise le tableau */
|
|
repeated = [];
|
|
|
|
|
|
/* (2) Vérification des variables */
|
|
if( !ref_assoc.hasOwnProperty(definition.repeat.id+':i') )
|
|
ref_assoc[definition.repeat.id+':i'] = ref(0);
|
|
|
|
if( !ref_assoc.hasOwnProperty(definition.repeat.id+':n') )
|
|
ref_assoc[definition.repeat.id+':n'] = ref(tmp);
|
|
|
|
|
|
/* (2) On construit le scope pour chaque valeur */
|
|
for( i = 0 ; i < tmp ; i++ ){
|
|
|
|
repeated[i] = {};
|
|
repeated[i][definition.repeat.id+':i'] = i;
|
|
repeated[i][definition.repeat.id+':n'] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* [2] Gestion de l'attribut 'browse'
|
|
=========================================================*/
|
|
if( definition.hasOwnProperty('browse') ){
|
|
tmp = FormBuilder.readRef( ref_table, definition.browse.array );
|
|
|
|
// Si c'est bien un tableau
|
|
if( tmp instanceof Array ){
|
|
|
|
/* (1) On initialise le tableau et le scope */
|
|
repeated = [];
|
|
scope = [];
|
|
funcs = {};
|
|
|
|
|
|
/* (2) On cherche les variables */
|
|
k = new RegExp( definition.browse.id+'.(.+)' );
|
|
|
|
// Si on trouve une valeur du type 'monTableauId.xxxxx'
|
|
for( i in ref_assoc )
|
|
if( k.test(i) )
|
|
scope.push( RegExp.$1 );
|
|
|
|
/* (2) On récupère les fonctions custom */
|
|
if( definition.browse.hasOwnProperty('funcs') ){
|
|
|
|
// Pour chaque fonction
|
|
for( i in definition.browse.funcs ){
|
|
|
|
// Si elle a le bon nom
|
|
if( k.test(i) ){
|
|
|
|
// on ajoute la fonction à la liste de fonctions
|
|
funcs[RegExp.$1] = FormBuilder.readRef( ref_table, definition.browse.funcs[i] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* (3) Vérification des variables */
|
|
if( !ref_assoc.hasOwnProperty(definition.browse.id+':i') )
|
|
ref_assoc[definition.browse.id+':i'] = ref(0);
|
|
|
|
if( !ref_assoc.hasOwnProperty(definition.browse.id+':n') )
|
|
ref_assoc[definition.browse.id+':n'] = ref(tmp);
|
|
|
|
|
|
/* (4) On construit le scope pour chaque valeur */
|
|
for( i = 0 ; i < tmp.length ; i++ ){
|
|
|
|
repeated[i] = {};
|
|
|
|
// Pour chaque champ, on récupère/calcule la valeur
|
|
for( j in scope ){
|
|
|
|
// {1} Si c'est une fonction custom //
|
|
if( funcs.hasOwnProperty(scope[j]) )
|
|
repeated[i][definition.browse.id+'.'+scope[j]] = funcs[ scope[j] ]( tmp[i] );
|
|
|
|
// {2} Si la valeur est un attribut //
|
|
else if( tmp[i].hasOwnProperty(scope[j]) )
|
|
repeated[i][definition.browse.id+'.'+scope[j]] = tmp[i][scope[j]];
|
|
|
|
|
|
}
|
|
|
|
repeated[i][definition.browse.id+':i'] = i;
|
|
repeated[i][definition.browse.id+':n'] = tmp.length;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* [xxxx] Pour chaque instance (répétition)
|
|
=========================================================*/
|
|
for( b = 0 ; b < repeated.length ; b++ ){
|
|
|
|
|
|
/* (1) On initialise l'élément courant */
|
|
built[b] = { prev: [], node: [], next: [] };
|
|
|
|
/* (2) Gestion des variables de 'repeat' et 'browse' */
|
|
if( repeated[b] instanceof Object ){
|
|
|
|
for( i in repeated[b] )
|
|
ref_table[ ref_assoc[i] ] = repeated[b][i];
|
|
|
|
}
|
|
|
|
|
|
/* [3] On construit les éléments @prev_nodes, s'ils existent
|
|
===========================================================*/
|
|
if( definition.hasOwnProperty('prev_nodes') )
|
|
for( i in definition.prev_nodes )
|
|
built[b].prev = FormBuilder.createElements(definition.prev_nodes[i], ref_table, ref_assoc);
|
|
|
|
|
|
/* [4] On construit les éléments @next_nodes s'ils existent
|
|
===========================================================*/
|
|
if( definition.hasOwnProperty('next_nodes') )
|
|
for( i in definition.next_nodes )
|
|
built[b].next = FormBuilder.createElements(definition.next_nodes[i], ref_table, ref_assoc);
|
|
|
|
|
|
/* [5] On construit l'objet actuel
|
|
===========================================================*/
|
|
/* (1) Si c'est un sub-node, on récupère la définition récursivement */
|
|
if( definition.hasOwnProperty('node_link') ){
|
|
|
|
tmp = FormBuilder.createElements(definition.node_link, ref_table, ref_assoc);
|
|
|
|
for( i in tmp ){
|
|
|
|
/* On ajoute les éléments à l'instance actuelle */
|
|
built[b].prev = built[b].prev.concat( tmp[i].prev );
|
|
built[b].node = built[b].node.concat( tmp[i].node );
|
|
built[b].next = tmp[i].next.concat( built[b].next );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* (2) Si on a le type de <tag> hmtl */
|
|
else if( definition.hasOwnProperty('node_type') ){
|
|
|
|
// {1} Création de l'élément //
|
|
built[b].node.push( document.createElement( FormBuilder.readRef(ref_table, definition.node_type) ) ) - 1;
|
|
|
|
}
|
|
|
|
|
|
/* (3) On ajoute les attributs
|
|
---------------------------------------------------------*/
|
|
if( definition.hasOwnProperty('attributes') ){
|
|
|
|
// Pour chaque attribut, on définit
|
|
for( i in definition.attributes )
|
|
// Pour chaque node
|
|
for( n in built[b].node )
|
|
built[b].node[n].setAttribute( i, FormBuilder.readRef(ref_table, definition.attributes[i]) );
|
|
|
|
}
|
|
|
|
|
|
/* (4) On ajoute le CSS
|
|
---------------------------------------------------------*/
|
|
if( definition.hasOwnProperty('css') ){
|
|
|
|
// On applique pour chaque noeud
|
|
for( n in built[b].node )
|
|
FormBuilder.applyCSS(built[b].node[n], definition.css);
|
|
|
|
}
|
|
|
|
|
|
/* (5) On ajoute le contenu HTML
|
|
---------------------------------------------------------*/
|
|
if( definition.hasOwnProperty('text') ){
|
|
|
|
// Note: Override les enfants
|
|
for( n in built[b].node )
|
|
built[b].node[n].innerHTML = FormBuilder.readRef(ref_table, definition.text);
|
|
|
|
}
|
|
|
|
|
|
/* (6) On ajoute les listeners
|
|
---------------------------------------------------------*/
|
|
if( definition.hasOwnProperty('listeners') ){
|
|
|
|
// Pour chaque listener
|
|
for( i in definition.listeners )
|
|
|
|
// Pour chaque node
|
|
for( n in built[b].node )
|
|
built[b].node[n].addEventListener( i, FormBuilder.readRef(ref_table, definition.listeners[i]), false );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (7) On ajoute les enfants
|
|
---------------------------------------------------------*/
|
|
if( definition.hasOwnProperty('children') ){
|
|
|
|
/* (1) Pour chaque enfant */
|
|
for( i in definition.children ){
|
|
|
|
tmp = FormBuilder.createElements(definition.children[i], ref_table, ref_assoc);
|
|
|
|
// Pour chaque node
|
|
for( n in built[b].node )
|
|
FormBuilder.attachElements(built[b].node[n], tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (8) Gestion de la récupération dynamique */
|
|
for( n in built[b].node ){
|
|
|
|
// {2} Determination du type //
|
|
var input = FormBuilder.fetchNodeType(definition) == 'input' && definition.hasOwnProperty('_value');
|
|
var select = FormBuilder.fetchNodeType(definition) == 'select' && definition.hasOwnProperty('_selected');
|
|
|
|
// {3} Si <select> //
|
|
if( select ){
|
|
|
|
|
|
// Des la creation, on selectionne l'option qui a la valeur
|
|
for( i = 0 ; i < built[b].node[n].children.length ; i++ ){
|
|
|
|
// si le bon <option>, on le selectionne
|
|
if( built[b].node[n].children[i].value == FormBuilder.readRef(ref_table, definition._selected) )
|
|
built[b].node[n].children[i].setAttribute('selected', true);
|
|
else
|
|
built[b].node[n].children[i].removeAttribute('selected');
|
|
|
|
}
|
|
|
|
// On met à jour la valeur
|
|
built[b].node[n].addEventListener('change', function(e){
|
|
|
|
// Uniquement si tableau de taille 1 avec une reference
|
|
if( !(definition._selected instanceof Array) ) return;
|
|
if( definition._selected.length > 1 ) return;
|
|
if( !FormBuilder.regex.ref_pri.test(definition._selected[0]) ) return;
|
|
|
|
// on recupere cette reference
|
|
var selected_ref = definition._selected[0];
|
|
|
|
// On recupere la derniere reference
|
|
var last = selected_ref,
|
|
curr = selected_ref;
|
|
|
|
// On var jusqu'a la valeur
|
|
while( FormBuilder.regex.ref_pri.test(curr) ){
|
|
last = curr;
|
|
curr = ref_table[ curr ];
|
|
|
|
if( curr instanceof Array )
|
|
curr = curr[0];
|
|
}
|
|
|
|
// On attribut la valeur modifiee
|
|
ref_table[ last ] = this.value;
|
|
}, false);
|
|
|
|
}
|
|
|
|
// {4} Si <input> de type texte //
|
|
if( input ){
|
|
|
|
// On met à jour la valeur
|
|
built[b].node[n].addEventListener('input', function(e){
|
|
|
|
// Uniquement si tableau de taille 1 avec une reference
|
|
if( !(definition._value instanceof Array) ) return;
|
|
if( definition._value.length > 1 ) return;
|
|
if( !FormBuilder.regex.ref_pri.test(definition._value[0]) ) return;
|
|
|
|
// on recupere cette reference
|
|
var value_ref = definition._value[0];
|
|
|
|
// On recupere la derniere reference
|
|
var last = value_ref,
|
|
curr = value_ref;
|
|
|
|
// On var jusqu'a la valeur
|
|
while( FormBuilder.regex.ref_pri.test(curr) ){
|
|
last = curr;
|
|
curr = ref_table[ curr ];
|
|
|
|
if( curr instanceof Array )
|
|
curr = curr[0];
|
|
}
|
|
|
|
// On attribut la valeur modifiee
|
|
ref_table[ last ] = this.value;
|
|
|
|
}, false);
|
|
|
|
}
|
|
|
|
// TODO: Gestion de la transmission de 'value' / 'selected' lors de la construction
|
|
|
|
}
|
|
}
|
|
|
|
|
|
var identifier = definition.hasOwnProperty('node') ? definition.node : definition.node_type
|
|
FormBuilder.debug('<'+identifier+'>', 2);
|
|
FormBuilder.debugStop(dbg);
|
|
|
|
/* [8] On ajoute l'élément à la définition et retourne
|
|
=========================================================*/
|
|
definition.dom = built;
|
|
return built;
|
|
};
|
|
|
|
|
|
/* ATTACHE UN JEU D'ELEMENTS A UN PARENT
|
|
*
|
|
* @parent<Element> Element parent
|
|
* @set<Array> Set d'enfants à attacher
|
|
*
|
|
*/
|
|
FormBuilder.attachElements = function(parent, set){
|
|
var dbg = FormBuilder.debugStart('FormBuilder::attachElements', 2);
|
|
|
|
var c, a;
|
|
|
|
/* [1] Pour chaque contexte (élément + prev + next)
|
|
=========================================================*/
|
|
for( c in set ){
|
|
|
|
|
|
/* (1) On attache les éléments précédents
|
|
---------------------------------------------------------*/
|
|
for( a in set[c].prev ){
|
|
|
|
/* (1) Si c'est un Element */
|
|
if( set[c].prev[a] instanceof Element )
|
|
parent.appendChild( set[c].prev[a] );
|
|
|
|
/* (2) On lance récursivement */
|
|
if( set[c].prev[a] instanceof Object )
|
|
FormBuilder.attachElements(parent, [ set[c].prev[a] ]);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* (2) On ajoute l'élément actuel
|
|
---------------------------------------------------------*/
|
|
for( a in set[c].node ){
|
|
|
|
/* (1) Si c'est un Element */
|
|
if( set[c].node[a] instanceof Element )
|
|
parent.appendChild( set[c].node[a] );
|
|
|
|
/* (2) On lance récursivement */
|
|
if( set[c].node[a] instanceof Object )
|
|
FormBuilder.attachElements(parent, [ set[c].node[a] ]);
|
|
|
|
}
|
|
|
|
|
|
/* (3) On attache les éléments suivants
|
|
---------------------------------------------------------*/
|
|
for( a in set[c].next ){
|
|
|
|
/* (1) Si c'est un Element */
|
|
if( set[c].next[a] instanceof Element )
|
|
parent.appendChild( set[c].next[a] );
|
|
|
|
/* (2) On lance récursivement */
|
|
if( set[c].next[a] instanceof Object )
|
|
FormBuilder.attachElements(parent, [ set[c].next[a] ]);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
FormBuilder.debugStop(dbg);
|
|
|
|
};
|
|
|
|
|
|
/* DETACHE UN JEU D'ELEMENTS D'UN PARENT
|
|
*
|
|
* @parent<Element> Element parent
|
|
* @set<Array> Set d'enfants à attacher
|
|
*
|
|
*/
|
|
FormBuilder.detachElements = function(parent, set){
|
|
|
|
var c, a;
|
|
|
|
/* [1] Pour chaque contexte (élément + prev + next)
|
|
=========================================================*/
|
|
for( c in set ){
|
|
|
|
|
|
/* (1) On attache les éléments précédents
|
|
---------------------------------------------------------*/
|
|
for( a in set[c].prev ){
|
|
|
|
/* (1) Si c'est un Element */
|
|
if( set[c].prev[a] instanceof Element )
|
|
parent.removeChild( set[c].prev[a] );
|
|
|
|
/* (2) On lance récursivement */
|
|
if( set[c].prev[a] instanceof Object )
|
|
FormBuilder.detachElements(parent, [ set[c].prev[a] ]);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* (2) On ajoute l'élément actuel
|
|
---------------------------------------------------------*/
|
|
for( a in set[c].node ){
|
|
|
|
/* (1) Si c'est un Element */
|
|
if( set[c].node[a] instanceof Element )
|
|
parent.removeChild( set[c].node[a] );
|
|
|
|
/* (2) On lance récursivement */
|
|
if( set[c].node[a] instanceof Object )
|
|
FormBuilder.detachElements(parent, [ set[c].node[a] ]);
|
|
|
|
}
|
|
|
|
|
|
/* (3) On attache les éléments suivants
|
|
---------------------------------------------------------*/
|
|
for( a in set[c].next ){
|
|
|
|
/* (1) Si c'est un Element */
|
|
if( set[c].next[a] instanceof Element )
|
|
parent.removeChild( set[c].next[a] );
|
|
|
|
/* (2) On lance récursivement */
|
|
if( set[c].next[a] instanceof Object )
|
|
FormBuilder.detachElements(parent, [ set[c].next[a] ]);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/* APPLIQUE UN STYLE CSS-LIKE A UN ELEMENT
|
|
*
|
|
* @element<Element> Element auquel on veut appliquer le css
|
|
* @css<Object> Objet contenant les règles css
|
|
*
|
|
*/
|
|
FormBuilder.applyCSS = function(element, css){
|
|
|
|
/* On applique chaque règle */
|
|
for( var r in css )
|
|
element.style[r] = css[r];
|
|
|
|
};
|
|
|
|
|
|
/* RETOURNE LE NODE_TYPE EN PARCOURANT LES DEFINITION RECURSIVEMENT
|
|
*
|
|
* @definition<Object> Definition contenant node_link ou node_type
|
|
*
|
|
* @return node_type<String> Node_type final en suivant les définition
|
|
*
|
|
*/
|
|
FormBuilder.fetchNodeType = function(definition){
|
|
|
|
/* (1) Si c'est la définition finale */
|
|
if( definition.hasOwnProperty('node_type') )
|
|
return definition.node_type;
|
|
|
|
/* (2) Si on trouve un lien vers définition, on lance récursivement */
|
|
else if( definition.hasOwnProperty('node_link') )
|
|
return FormBuilder.fetchNodeType(definition.node_link);
|
|
|
|
};
|
|
|
|
|
|
FormBuilder.DOMUpdates = function(events){
|
|
var e;
|
|
|
|
|
|
/* [1] On parcourt chaque évènement
|
|
=========================================================*/
|
|
for( e in events){
|
|
|
|
console.log( events[e] );
|
|
console.log( events[e].target );
|
|
console.log( events[e].type );
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|