226 lines
10 KiB
JavaScript
226 lines
10 KiB
JavaScript
document.body.innerHTML = '';
|
|
|
|
// CETTE CLASSE PERMET LA CREATION DE HTML A PARTIR D'UN OBJET JAVASCRIPT
|
|
//
|
|
//
|
|
// Notation:
|
|
// - Une chaine de caractère précédée du symbole '@' correspond à un commentaire pour expliquer une valeur
|
|
//
|
|
//
|
|
// Types de donées:
|
|
// - <S> Chaine de caractère
|
|
// - <A> Tableau
|
|
// - <O> Tableau associatif (objet)
|
|
// - <I> Nombre entier
|
|
// - <F> Fonction
|
|
// - <*> Qu'importe
|
|
//
|
|
// Structure:
|
|
// - L'objet permettant la création du HTML correspond à un #Element
|
|
// - L'imbrication de ses #Element permet de construire une structure complète
|
|
//
|
|
//
|
|
// Fonctionnement:
|
|
// - En plus de l'objet correspondant à l'élément HMTL, il faut spécifier des #Descriptions permettant
|
|
// de générer le HTML
|
|
//
|
|
//
|
|
// Liste des attributs:
|
|
// 'node' <S> String permettant de lier l'élément à une définition (qui doit forcément avoir, soit une autre définition, soit 'node_type')
|
|
// 'node_type' <S> Type d'élément HTML, aucune définition n'est nécessaire
|
|
// 'children' <A> les #Element enfants de l'#Element en question
|
|
// 'prev_nodes' <A> les #Element précédant l'#Element en question
|
|
// 'next_nodes' <A> les #Element suivant l'#Element en question
|
|
// 'text' <S> Contenu textuel de l'#Element (cf. innerHTML)
|
|
// 'attributes' <O> Tableau associatif contenant les attributs de l'#Element
|
|
// 'listeners' <O> Contient les associations { '@eventName': '@eventFunction' } - @eventName<S> - @eventFunction<F>
|
|
// 'repeat' <O> Définit le nombre de fois qu'il faut dupliquer l'#Element { n: @nbRepeat, id: '@idDuRepeat'}
|
|
// 'n' <I> Nombre de fois qu'il faut dupliquer l'#Element
|
|
// 'id' <S> Identifiant de la répétition, permet d'interpoler l'indice et le total
|
|
// *Note: il est possible d'interpoler l'indice de l'#Element avec '{@idRepeat:i}' et le total avec '{@idRepeat:n}'
|
|
// 'browse' <A/O> Définit le tableau sur lequel dupliquer l'#Element { array: @tableau, funcs: { @nomValeur1: @func1, @nomValeur2: @func2 } }
|
|
// 'array' <A> Tableau pour lequel dupliquer l'#Element (pour chaque valeur), l'interpolation se fait avec '{@nomTab.@nomAttr}'
|
|
// 'funcs' <B> Définition d'actions sur chaque élément du tableau (interpolables de la même manière que les vrais attributs)
|
|
// *Note: il est possible d'interpoler l'indice de l'#Element avec '{@nomTab:i}' et le total avec '{@nomTab:n}'
|
|
// '$@someName' <*> Un attribut commençant par le caractère '$' sera passé au scope de ses enfants, voisins, et définitions
|
|
//
|
|
//
|
|
// Interpolation de valeurs:
|
|
// '{@nomVariable}' sera remplacé par la variable 'nomVariable', si elle n'existe pas, par une chaine vide
|
|
// *Note: le nom de la variable ne peut contenir que : 1. des lettres en minuscules, des underscore ('_')
|
|
// '{@nomTab[]}' sera remplacé par le tableau 'nomTab', si il n'existe pas, par un tableau vide
|
|
// *Note: le nom de la variable ne peut contenir que : 1. des lettres en minuscules, des underscore ('_')
|
|
// '{@nomFunc()}' sera remplacé par la fonction 'nomFunc', si elle n'existe pas, par une fonction vide
|
|
// *Note: le nom de la variable ne peut contenir que : 1. des lettres en minuscules, des underscore ('_')
|
|
// '{$@n}' sera remplacé par le @n-ième match de la dernière RegExp valide
|
|
// *Note: ne peut qu'être utilisé dans les définitions, car c'est le seul endroit ou peuvent être des RegExp
|
|
// '{@tab.@attr}' sera remplacé par l'attribut @attr de l'item en cours du tableau @tab
|
|
// *Note: si l'attribut n'existe pas, mais qu'une fonction est définie pour cette valeur, la fonction calculera la valeur
|
|
// *Note: n'est utilisable que dans un #Element ayant l'attribut 'browse'
|
|
//
|
|
//
|
|
// Définition
|
|
// Les clés de l'objet correspondent à l'attribut 'node', il peut soit être une chaine, soit une RegExp @r de la forme: '/^@r$/'
|
|
//
|
|
//
|
|
//
|
|
// Exemple: objet de définition
|
|
// ----------------------------
|
|
var default_definition = {
|
|
// Les #Element avec 'node' valant 'input' seront liés à cette définition
|
|
'input.text': {
|
|
node_type: 'input', // sera un <input>
|
|
attributes: {
|
|
name: '{name}', // l'attribut 'name' vaudra la valeur de la variable 'name'
|
|
value: '{value}', // l'attribut 'value' vaudra la valeur de la variable 'value'
|
|
type: 'text' // l'attribut 'type' vaudra 'text'
|
|
}
|
|
},
|
|
|
|
// Les #Element avec 'node' valant 'span:@x' avec @x un nombre entier, seront liés à cette définition
|
|
'/^span:(\d+)$/': {
|
|
node_type: 'span', // sera un <span>
|
|
text: 'span {spanRepeat:i} on {spanRepeat:n} (={$1})',
|
|
repeat: {
|
|
n: '{$1}', // sera dupliqué @x fois, avec @x récupéré dans le nom de la définition
|
|
id: 'spanRepeat' // sera accessible via l'id 'spanRepeat'
|
|
},
|
|
attributes: {
|
|
'class': '{class}' // l'attribut 'class' vaudra la valeur de la variable 'class'
|
|
}
|
|
},
|
|
|
|
// Les #Element avec 'node' valant 'simple-select', seront liés à cette définition
|
|
'simple-select': {
|
|
node_type: 'select', // sera un <select>
|
|
attributes: {
|
|
'class': '{select-class}' // l'attribut 'class' prendra la valeur de la variable 'select-class'
|
|
},
|
|
children: [
|
|
{
|
|
node_type: 'option', // contiendra des <option>
|
|
browse: {
|
|
array: '{options[]}', // chaque <option> sera dupliquée pour chaque valeur du tableau 'options'
|
|
funcs: {
|
|
// définit le "faux" attribut 'value' de chaque élément du tableau 'options'
|
|
// avec la fonction 'getvalue()' qui sera passée en paramètre
|
|
// *Node: le tableau n'aura pas d'attribut (tableau simple), cela renverra
|
|
// donc directement la valeur de chaque item
|
|
'options.value': '{getvalue()}',
|
|
|
|
// définit le "faux" attribut 'length' de chaque élément du tableau 'options'
|
|
// avec la fonction 'getstrlen()' qui sera passée en paramètre
|
|
// la fonction retournera la taille des chaines de chaque valeur du tableau
|
|
'options.length': '{getlength()}'
|
|
}
|
|
},
|
|
attributes: {
|
|
'class': '{option-class}', // l'attribut 'class' prendra la valeur de la variable 'option-class'
|
|
value: '{options:i}' // chaque <option> aura l'attribut 'value' qui vaut l'indice actuel de l'#Element
|
|
},
|
|
// aura pour contenu la valeur de l'item actuel @a du tableau,
|
|
// suivi du nombre de caractère @b de la valeur
|
|
// ex: "texteDeLitem (12 caractères)"
|
|
text: '{options.value} ({options.length} caractères)'
|
|
}
|
|
],
|
|
|
|
listeners: {
|
|
// ajoutera un listener sur l'évènement 'change' et lancera la fonction passée
|
|
// qui s'appelle 'onchange'
|
|
'change': '{onchange()}'
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
// Exemple formulaire
|
|
// ------------------
|
|
var exempleFormulaire = {
|
|
node_type: 'form', // sera un <form>
|
|
attributes: {
|
|
'method': 'POST', // aura l'attribut 'method' valant 'POST'
|
|
'action': '{url}' // aura l'attribut 'action' valant la valeur de la variable 'url'
|
|
},
|
|
|
|
// sera précédé par 2 <span> (cf. définition de 'span:(\d+)')
|
|
prev_nodes: [
|
|
{
|
|
node: 'span:2',
|
|
$class: 'beforeSpan' // les <span> hériterons de la variable 'class'
|
|
}
|
|
],
|
|
|
|
children: [
|
|
{ // contiendra en premier enfant un <input type='text'>
|
|
node: 'input.text',
|
|
$name: 'fname', // l'<input> héritera la variable 'name'
|
|
$value: '{default_firstname}' // l'<input> héritera la variable 'value', qui elle-même sera récupèrée de la variable 'default_firstname'
|
|
},
|
|
|
|
{ // contiendra en second enfant un <select> contenant les <options> en fonction du tableau 'liste-noms'
|
|
node: 'simple-select',
|
|
$options: '{liste_noms[]}', // la définition héritera du tableau 'options' valant le tableau donné 'liste_noms'
|
|
$select_class: 'gui-option', // la définition héritera de la variable 'select_class'
|
|
$option_class: 'gui-select', // la définition héritera de la variable 'option_class'
|
|
$onchange: '{my_onchange()}', // la définition héritera de la fonction 'onchange' valant la fonction donnée 'my_onchange'
|
|
$getvalue: '{getitemvalue()}', // la définition héritera de la fonction 'getvalue' valant la fonction données 'getitemvalue'
|
|
$getlength: '{getitemlength()}' // la définition héritera de la fonction 'getlength' valant la fonction données 'getitemvalue'
|
|
},
|
|
|
|
{ // contiendra en dernier enfant un <input type='submit' value='Valider'>
|
|
node_type: 'input', // sera un <input>
|
|
attributes: {
|
|
type: 'submit', // aura l'attribut 'type' qui vaut 'submit'
|
|
value: 'Valider' // aura l'attribut 'value' qui vaut 'Valider'
|
|
}
|
|
}
|
|
],
|
|
|
|
// sera suivi par 2 <span> (cf. définition de 'span:(\d+)')
|
|
next_nodes: [
|
|
{
|
|
node: 'span:2',
|
|
$class: 'afterSpan' // les <span> hériterons de la variable 'class'
|
|
}
|
|
]
|
|
};
|
|
|
|
//
|
|
// Exemple code de construction
|
|
// ----------------------------
|
|
//
|
|
// On instancie notre builder
|
|
var monBuilder = new FormBuilder(exempleFormulaire);
|
|
// on ajoute la/les définition(s)
|
|
monBuilder.add_definition(default_definition);
|
|
// on construit notre objet en lui passant toutes les données
|
|
monBuilder.build({
|
|
url: 'https://xdrm.io/page1', // variable 'url'
|
|
default_firstname: 'Jean', // variable 'default_firstname'
|
|
liste_noms: ['Jean', 'Pierre', 'Robert', 'Marie', 'Anna', 'Félicien', 'Marc', 'Jésus'], // tableau 'list_noms'
|
|
getitemvalue: function(item){ return item; }, // pour chaque item, retournera la valeur brute
|
|
getitemlength: function(item){ return item.length; } // pour chaque item, retournera la taille de la valeur
|
|
});
|
|
|
|
//
|
|
// Exemple code d'ajout au DOM
|
|
// ---------------------------
|
|
// soit monConteneur, l'élément qui contiendra le formulaire
|
|
var monConteneur = document.body;
|
|
// On ajoute le formulaire au conteneur
|
|
monBuilder.attach(monConteneur);
|
|
|
|
|
|
//
|
|
// Exemple de modification des valeurs
|
|
// -----------------------------------
|
|
// les variables ommises lors de la création, ne sont pas modifiables
|
|
monBuilder.update({
|
|
url: 'https://xdrm.io/page2', // on modifie l'URL
|
|
getitemlength: function(item){ return item.length+1; } // on modifie notre fonction (on renvoie taille+1)
|
|
});
|
|
// reconstruction du DOM
|
|
monBuilder.attach(monConteneur);
|