commit cdb74ea9487100681351ac0a70a5377772adb097
parent b87de4ae3469ce87e5077ceb1eee20a994f608fb
Author: Georges Dupéron <jahvascriptmaniac+github@free.fr>
Date: Sun, 12 Sep 2010 03:44:15 +0200
Bind bidirectionnel entre le modèle et les champs de formulaire et le texte des éléments.
Diffstat:
| M | editeur.js | | | 300 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
1 file changed, 177 insertions(+), 123 deletions(-)
diff --git a/editeur.js b/editeur.js
@@ -1,17 +1,48 @@
$(function() {
$(".éditeur-semantique").each(function(i,e) {
- éditeurSémantique(e, typesNoeud);
+ éditeurSémantique(e, schémasTypesNoeud);
});
});
Object.keys = function(object) {
var keys = [];
- for (k in object) {
+ for (var k in object) {
keys.push(k);
}
return keys;
}
+function valeur(v) {
+ var valeur = v;
+ var écouteurs = [];
+ var f = function(v) {
+ if (typeof v == "undefined") {
+ return f.get();
+ } else {
+ return f.set(v);
+ }
+ };
+ f.ajouterÉcouteur = function(écouteur) {
+ if (écouteurs.indexOf(écouteur) < 0)
+ écouteurs.push(écouteur);
+ }
+ f.enleverÉcouteur = function(écouteur) {
+ var i = écouteurs.indexOf(écouteur);
+ if (i >= 0) écouteurs.splice(i,1);
+ }
+ f.get = function() {
+ return valeur;
+ }
+ f.set = function(v) {
+ var oldv = valeur;
+ valeur = v;
+ $(écouteurs).each(function(i,f){
+ f(v, oldv);
+ });
+ }
+ return f;
+}
+
/* ===== Types de noeud ===== */
var MULTI_LIGNE = 0;
@@ -24,6 +55,25 @@ $.fn.extend({
this.append(modèle.enfant(i).créerVue(typeVue));
}
return this;
+ },
+ bindText: function(valeur) {
+ var that = this;
+ valeur.ajouterÉcouteur(function(valeur, oldval) {
+ that.text(valeur);
+ });
+ this.text(valeur.get());
+ return this;
+ },
+ bindVal: function(valeur) {
+ var that = this;
+ valeur.ajouterÉcouteur(function(valeur, oldval) {
+ that.val(valeur);
+ });
+ this.val(valeur.get());
+ this.bind("propertychange input cut paste keypress", function() {
+ valeur.set(that.val());
+ });
+ return this;
}
});
@@ -38,114 +88,110 @@ function squeletteAperçuNoeud(noeud) {
var étiquette = $('<span class="étiquette"/>').appendTo(html);
var contenu = $('<' + ct.tagc + ' class="contenu"/>').appendTo(html);
- html.click(function(){console.log("plop", noeud); return false; });
+ html.click(function(){
+ noeud.document().noeudActif.set(noeud);
+ return false;
+ });
return html;
}
-var typeNoeudDéfaut = {
- catégorie: EN_LIGNE,
- enfants: ['texte'],
- vues: {
- aperçu: function() {
- return squeletteAperçuNoeud(this)
- .children(".contenu").appendVuesEnfants(this, 'aperçu').end();
- },
- edition: function() {
- return $('<div class="info">Cliquez sur du texte pour le modifier.</div>');
- }
- },
- vue: function (typeVue) {
- return typesNoeud[this.type().nom].vues[typeVue].call(this, typeVue);
- },
- propriétés: {}
-}
-
// Nettoie typesNoeud
-function TypesNoeud(typesNoeud) {
- for (var i in typesNoeud) {
- this[i] = $.extend({}, typeNoeudDéfaut, typesNoeud[i]);
- this[i].vues = $.extend({}, typeNoeudDéfaut.vues, typesNoeud[i].vues);
+function TypesNoeud(schémaDéfaut, schémasTypesNoeud) {
+ for (var i in schémasTypesNoeud) {
+ this[i] = $.extend({}, schémaDéfaut, schémasTypesNoeud[i]);
+ this[i].vues = $.extend({}, schémaDéfaut.vues, schémasTypesNoeud[i].vues);
this[i].nom = i;
}
}
-var typesNoeud = new TypesNoeud({
- document: {
- catégorie: MULTI_LIGNE,
- enfants: ['titre', 'paragraphe'],
- // surcharge de la _fonction_ "vue" (pas le tableau "vues").
- vue: function() {
- return $('<div class="conteneur-esem"/>').appendVuesEnfants(this, 'aperçu');
- }
- },
- titre: {
- catégorie: MONO_LIGNE,
- enfants: ['important', 'texte'],
- },
- paragraphe: {
- catégorie: MULTI_LIGNE,
- enfants: ['important', 'texte'],
- },
- important: {
- catégorie: EN_LIGNE,
- enfants: ['texte'],
- },
- lien: {
+var schémasTypesNoeud = new TypesNoeud(
+ {// Schéma par défaut
catégorie: EN_LIGNE,
enfants: ['texte'],
vues: {
aperçu: function() {
- var ret = squeletteAperçuNoeud(this);
- $('<span class="cible"/>').text(this.propriété("cible")).appendTo(ret.children(".contenu"));
- $('<span class="texte"/>').text(this.propriété("texte")).appendTo(ret.children(".contenu"));
- return ret;
+ return squeletteAperçuNoeud(this)
+ .children(".contenu").appendVuesEnfants(this, 'aperçu').end();
},
édition: function() {
- return édition_noeud(this).prepend('<input type="text" value="<<<propriétés.cible>>>"/>')
- },
+ return $('<div class="info">Cliquez sur du texte pour le modifier.</div>');
+ }
},
- propriétés: {
- interne: false,
- cible: 'http://www.example.com/',
- texte: 'texte du lien'
- }
+ vue: function (typeVue) {
+ return this.type().vues[typeVue].call(this, typeVue);
+ },
+ propriétés: {}
},
- texte: {
- catégorie: EN_LIGNE,
- enfants: [],
- vues: {
- aperçu: function() {
- return $('<span class="noeud texte en-ligne"/>')
- .text(this.propriété("texte"));
- // .bind_text(this.texte);
- },
- édition: function() {
- return $("<textarea/>").bind_val(this.propriété("texte")); // TODO
+ {// Schémas des types de noeud
+ document: {
+ catégorie: MULTI_LIGNE,
+ enfants: ['titre', 'paragraphe'],
+ // surcharge de la _fonction_ "vue" (pas le tableau "vues").
+ vue: function() {
+ var html = $('<div class="conteneur-esem"/>');
+ var aperçu = $('<div class="aperçu"/>').appendTo(html).appendVuesEnfants(this, 'aperçu');
+ var boutons = $('<div class="boutons"/>').appendTo(html);
+ var édition = $('<div class="éditeur"/>').appendTo(html);
+ this.noeudActif.ajouterÉcouteur(function(actif, oldActif) {
+ édition.empty();
+ édition.append(actif.créerVue("édition"));
+ });
+ return html;
+ }
+ },
+ titre: {
+ catégorie: MONO_LIGNE,
+ enfants: ['important', 'texte'],
+ },
+ paragraphe: {
+ catégorie: MULTI_LIGNE,
+ enfants: ['important', 'texte'],
+ },
+ important: {
+ catégorie: EN_LIGNE,
+ enfants: ['texte'],
+ },
+ lien: {
+ catégorie: EN_LIGNE,
+ enfants: ['texte'],
+ vues: {
+ aperçu: function() {
+ var ret = squeletteAperçuNoeud(this);
+ $('<span class="cible"/>').bindText(this.propriété("cible")).appendTo(ret.children(".contenu"));
+ $('<span class="texte"/>').bindText(this.propriété("texte")).appendTo(ret.children(".contenu"));
+ return ret;
+ },
+ édition: function() {
+ return $('<input type="text"/>').bindVal(this.propriété("texte"));
+ },
},
+ propriétés: {
+ interne: false,
+ cible: 'http://www.example.com/',
+ texte: 'texte du lien'
+ }
},
- propriétés: {
- texte: ''
+ texte: {
+ catégorie: EN_LIGNE,
+ enfants: [],
+ vues: {
+ aperçu: function() {
+ return $('<span class="noeud texte en-ligne"/>')
+ .bindText(this.propriété("texte"));
+ },
+ édition: function() {
+ return $("<textarea/>").bindVal(this.propriété("texte")); // TODO
+ },
+ },
+ propriétés: {
+ texte: ''
+ }
}
}
-});
-
-/* ===== Textarea => éditeur sémantique ===== */
+);
-function éditeurSémantique(textareaOrigine, schémasTypesNoeud) {
- // XML -> modèle
- var textareaOrigine = $(textareaOrigine);
- var xml = $("<document/>").append(textareaOrigine.val()); // Est-ce portable ?.
- var modèle = xmlVersModèle(xml.get(0), schémasTypesNoeud);
-
- // Vue
- var vue = modèle.créerVue(null);
- textareaOrigine.replaceWith(vue);
-
- // Debug
- m = modèle;
- v = vue;
-}
+/* ===== Manipulation des noeuds ===== */
var créerDocument = function(schémasTypesNoeud) {
function clôture_référence_document(privé_document) {
@@ -219,19 +265,35 @@ var créerDocument = function(schémasTypesNoeud) {
};
};
function clôture_propriétés(propriétésDéfaut) {
- var privé_propriétés = $.extend(true, {}, propriétésDéfaut);
+ var privé_propriétés = {};
+ for (i in propriétésDéfaut) {
+ privé_propriétés[i] = valeur(propriétésDéfaut);
+ }
+
return {
propriété: function(nom) {
return privé_propriétés[nom];
},
listePropriétés: function() {
return Object.keys(privé_propriétés);
- },
- setPropriété: function(propriété, valeur) {
- if (propriété in privé_propriétés)
+ }
+/* setPropriété: function(propriété, valeur) {
+ var oldval = privé_propriétés[propriété];
+ if (propriété in privé_propriétés) {
privé_propriétés[propriété] = valeur;
+ $.each(privé_écouteurs[propriété], function(i,écouteur) {
+ écouteur(valeur, oldval);
+ });
+ }
// TODO : modifier la vue
- }
+ },
+ ajouterÉcouteurPropriété: function(propriété, écouteur) {
+ privé_écouteurs[propriété].push(écouteur);
+ },
+ enleverÉcouteurPropriété: function(propriété, écouteur) {
+ var i = privé_écouteurs[propriété].écouteur;
+ privé_écouteurs[propriété].splice(i,1);
+ }*/
}
};
@@ -282,14 +344,10 @@ var créerDocument = function(schémasTypesNoeud) {
}
function clôture_document(privé_schémasTypesNoeud) {
- var privé_noeudActif = null;
var privé_pressePapier = null;
var privé_document = {
- setNoeudActif: function(noeud) {
- // TODO : vue.setActif(bool);
- privé_noeudActif = noeud;
- },
+ noeudActif: valeur(null),
schémaTypeNoeud: function(type) {
return privé_schémasTypesNoeud[type];
},
@@ -313,14 +371,31 @@ var créerDocument = function(schémasTypesNoeud) {
return document = clôture_document(schémasTypesNoeud);
}
-function xmlVersModèle(xml, schémasTypesNoeud, document) {
+/* ===== Textarea => éditeur sémantique ===== */
+
+function éditeurSémantique(textareaOrigine, schémasTypesNoeud) {
+ // XML -> modèle
+ var textareaOrigine = $(textareaOrigine);
+ var xml = $("<document/>").append(textareaOrigine.val()); // Est-ce portable ?.
+ var modèle = XMLVersModèle(xml.get(0), schémasTypesNoeud);
+
+ // Vue
+ var vue = modèle.créerVue(null);
+ textareaOrigine.replaceWith(vue);
+
+ // Debug
+ m = modèle;
+ v = vue;
+}
+
+function XMLVersModèle(xml, schémasTypesNoeud, document) {
var tag = xml.tagName.toLowerCase();
// Création du noeud
if (document) {
var noeud = document.créerNoeud(tag);
} else {
- var document = créerDocument(typesNoeud);
+ var document = créerDocument(schémasTypesNoeud);
var noeud = document;
}
@@ -328,13 +403,13 @@ function xmlVersModèle(xml, schémasTypesNoeud, document) {
$.each(noeud.listePropriétés(), function(i,prop) {
var propval = $(xml).attr(prop);
if (typeof propval != "undefined") {
- noeud.setPropriété(prop, propval);
+ noeud.propriété(prop).set(propval);
}
});
// Remplissage des enfants
$(xml).children().each(function (i,e) {
- var x = xmlVersModèle(e, schémasTypesNoeud, document);
+ var x = XMLVersModèle(e, schémasTypesNoeud, document);
noeud.insérerFin(x);
});
@@ -355,27 +430,6 @@ vue.setPropriété(propriété, valeur);
*/
-/*function valeur(v) { // TODO : voir si ça peut marcher aussi pour des éléments complets (pas que du texte).
- var valeur = v;
- var écouteurs = [];
- var f = function(v) {
- if (typeof v == "undefined") {
- return valeur;
- } else {
- var oldv = v;
- valeur = v;
- $(écouteurs).each(function(i,f){
- f(v, oldv);
- });
- }
- };
- f.ajouterÉcouteur = function(rappel) {
- écouteurs.push(rappel);
- }
- // TODO : piquer le code de : http://github.com/jsmaniac/2010-ide-langage-grunt-flin607/blob/master/jside4/callbacks.js
- return f;
-} */
-