Le problème
La présence d'espaces et de blancs dans le DOM peut rendre la manipulation de l'arbre de contenu difficile dans des aspects qu'on ne prévoit pas forcément. Dans Mozilla, tous les espaces et blancs dans le contenu texte du document original sont représentés dans le DOM (cela ne concerne pas les blancs à l'intérieur des balises). (C'est nécessaire en interne afin que l'éditeur puisse conserver le formatage des documents et que l'instruction white-space: pre
en CSS fonctionne.) Cela signifie que :
- il y aura certains nœuds texte qui ne contiendront que du vide, et
- certains nœuds texte commenceront ou se termineront par des blancs.
En d'autres termes, l'arbre DOM pour le document qui suit ressemblera à l'image ci-dessous (où « \n » représente un retour à la ligne) :
<!-- My document --> <html> <head> <title>My Document</title> </head> <body> <h1>Header</h1> <p> Paragraph </p> </body> </html>
Ceci peut rendre les choses un peu plus difficiles pour les utilisateurs du DOM qui aimeraient parcourir le contenu, sans se préoccuper des blancs.
Rendre les choses plus faciles
Le code JavaScript ci-dessous définit plusieurs fonctions facilitant la manipulation d'espaces dans le DOM :
/** * Les blancs sont définis comme l'un de ces caractères * "\t" TAB \u0009 * "\n" LF \u000A * "\r" CR \u000D * " " SPC \u0020 * * On n'utilise pas les "\s" de JavaScript car les espaces insécables * (et quelques autres caractères) en font partie. */ /** * Détermine si un nœud texte est entièrement composé de blancs * * @param nod Un nœud implémentant l'interface |CharacterData| (c'est-à-dire, * un nœud |Text|, |Comment| ou |CDATASection|) * @return Vrai si tout le contenu texte de |nod| est composé de blancs, * faux dans les autres cas. */ function is_all_ws( nod ) { // Utilisation des fonctionnalités String et RegExp d'ECMA-262 Edition 3 return !(/[^\t\n\r ]/.test(nod.data)); } /** * Détermine si un nœud devrait être ignoré par les fonctions itérateurs. * * @param nod Un objet implémentant l'interface DOM1 |Node|. * @return vrai si le nœud est : * 1) un nœud |Text| composé uniquement de blancs * 2) un nœud de commentaire |Comment| * et faux dans les autres cas. */ function is_ignorable( nod ) { return ( nod.nodeType == 8) || // Un nœud de commentaire ( (nod.nodeType == 3) && is_all_ws(nod) ); // un nœud texte, uniquement des blancs } /** * Version de |previousSibling| qui passe les nœuds entièrement constitués * de blancs ou les commentaires. (Normalement |previousSibling| est une propriété * de tous les nœuds DOM qui donne le nœud du même niveau, qui est lethat is * un enfant du même parent, qui se trouve immédiatement avant le nœud * de référence.) * * @param sib Le nœud de référence. * @return Soit : * 1) Le nœud de même niveau le plus proche de |sib| qui n'est pas * ignorable d'après |is_ignorable|, ou * 2) null si un tel nœud n'existe pas. */ function node_before( sib ) { while ((sib = sib.previousSibling)) { if (!is_ignorable(sib)) return sib; } return null; } /** * Version de |nextSibling| qui passe les nœuds qui sont entièrement constitués de * blancs ou les commentaires. * * @param sib Le nœud de référence. * @return Soit : * 1) Le nœud suivant de même niveau le plus proche de |sib| qui n'est pas * ignorable selon |is_ignorable|, ou * 2) null si un tel nœud n'existe pas. */ function node_after( sib ) { while ((sib = sib.nextSibling)) { if (!is_ignorable(sib)) return sib; } return null; } /** * Version de |lastChild| qui passe les nœuds qui sont entièrement constitués de * blancs ou les commentaires. (Normalement |lastChild| est une propriété * de tous les nœuds DOM qui donne le dernier des nœuds contenus directement * dans le nœud de référence.) * * @param sib Le nœud de référence. * @return Soit : * 1) Le dernier enfant de |sib| qui n'est pas * ignorable selon |is_ignorable|, ou * 2) null si un tel nœud n'existe pas. */ function last_child( par ) { var res=par.lastChild; while (res) { if (!is_ignorable(res)) return res; res = res.previousSibling; } return null; } /** * Version de |firstChild| qui passe les nœuds qui sont entièrement constitués de * blancs ou les commentaires. * * @param sib Le nœud de référence. * @return Soit : * 1) The premier enfant de |sib| qui n'est pas * ignorable selon |is_ignorable|, ou * 2) null si un tel nœud n'existe pas. */ function first_child( par ) { var res=par.firstChild; while (res) { if (!is_ignorable(res)) return res; res = res.nextSibling; } return null; } /** * Version de |data| qui ne renvoie pas les blancs en début et en fin * de chaîne et normalise tous les blancs en un seul espace. (Normalement, * |data| est une propriété des nœuds textes qui donne le texte du nœud.) * * @param txt Le nœud texte dont les données doivent être renvoyées * @return Une chaîne donnant le contenu du nœud texte avec * tous les blancs réduits à un simple espace. */ function data_of( txt ) { var data = txt.data; // Utilisation des fonctionnalités String et RegExp d'ECMA-262 Edition 3 data = data.replace(/[\t\n\r ]+/g, " "); if (data.charAt(0) == " ") data = data.substring(1, data.length); if (data.charAt(data.length - 1) == " ") data = data.substring(0, data.length - 1); return data; }
Exemple
Le code qui suit montre l'utilisation des fonctions présentées plus haut. Il parcourt les enfants d'un élément (dont les enfants sont tous des éléments) pour trouver celui dont le texte est "Ceci est le troisième paragraphe"
, et change ensuite l'attribut class
et le contenu de ce paragraphe.
var cur = first_child(document.getElementById("test")); while (cur) { if (data_of(cur.firstChild) == "Ceci est le troisième paragraphe.") { cur.className = "magic"; cur.firstChild.data = "Ceci est un paragraphe magique."; } cur = node_after(cur); }
Informations sur le document original
- Auteur : L. David Baron
- Dernière mise à jour : 1er janvier 2003
- Copyright : © 1998-2005 by individual mozilla.org contributors ; contenu disponible sous licence Creative Commons