www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

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:
Mediteur.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; -} */ -