Dernière mise à jour :2008-10-14

informatique

Il y a quelques temps, je travaillais au développement d'une application web qui visait à permettre à des utilisateurs ne connaissant pas le langage HTML, de concevoir facilement les pages de leur site.

Le site web en question était composé de plusieurs pages au format XHTML. L'outil de création de page utilisait la technologie des zones éditables offerte par Microsoft Internet Explorer version 5.5 et plus. Ces zones éditables sont des éléments du document auxquels on inscrit «true» comme valeur de l'attribut «contenteditable». L'élément en question se transforme alors en une zone d'édition WYSIWYG (What You See Is What You Get) du même genre que celle du logiciel FrontPage.

Accompagnant ces zones éditables, j'ai aussi incorporé une série de boutons permettant à l'utilisateur d'ajouter des images, des liens hypertexte et de changer le style du texte.

Voici un exemple de code qui cré une zone éditable accompagnée d'un bouton permettant de mettre en caractère gras le texte sélectionné par l'utilisateur dans la zone.

Listing 1.0 Exemple - Zone éditable
<script language="javascript" type="text/javascript">
<!--
function gras_Click()
{
document.execCommand('Bold',false);
}
// -->
</script>

<form>
<div id="txt1" contenteditable style="border:1px solid #000000;width:200px;height:100px;"></div>
<input type="button" onclick="gras_Click();" value="gras">
</form>

Le problème avec ces zones éditables, c'est que le code généré par l'application qui gère la zone est en un format HTML qui bien qu'étant du code HTML acceptable, ne respecte pas les normes XHTML.

Le langage XHTML est en fait une reproduction du langage HTML mais en format XML. En HTML on peut créer l'élément IMG (image) de plusieurs façon. Par exemple :

<IMG>
<Img>
<img />

Toutes ces manières d'écrire IMG sont valides en HTML car le langage ne se souci pas de la casse (majuscule/minuscule) ni de si le créateur du document place le caractère « / » pour indiquer la fin d'une balise. Par contre, XHTML s'en préocupe. Il en résulte donc qu'il n'existe qu'une seule façon d'écrire l'élément IMG en XHTML et c'est :

<img />

Puisque le format des fichiers créés avec l'application doit être XHTML, je ne pouvais donc pas utiliser directement le code généré par les zones éditables. Il était alors nécessaire de procéder à une converssion au format XHTML. J'ai donc créé deux petites fonction en JScript qui sur un principe de récursivité, convertissent tous les éléments enfants d'un élément parent, au format XHTML.

Listing 2.0 Fonctions de conversion
1. var strResultHTMLToXHTML = "";
2. 
3. function HTMLToXHTML2(objElementCible)
4. {
5.   for (var x=0;x<objElementCible.children.length;x++)
6.   {
7.    strTagName = new String(objElementCible.children[x].tagName);
8.    strResultHTMLToXHTML += "<" + strTagName.toLowerCase();
9.    if (objElementCible.children[x].className != "")
10.     strResultHTMLToXHTML += " class=\"" + objElementCible.children[x].className + "\"";
11.    for (var y=0;y<objElementCible.children[x].attributes.length;y++)
12.    {
13.     var varAttrValue = objElementCible.children[x].getAttribute(objElementCible.children[x].attributes[y].name);
14.     if ((varAttrValue != null) && (varAttrValue != "") && (varAttrValue != "[object]"))
15.     {
16.      var strAttrName = new String (objElementCible.children[x].attributes[y].name);
17.      if ((strAttrName != "contentEditable") && (strAttrName != "loop"))
18.       strResultHTMLToXHTML += " " + strAttrName.toLowerCase() + "=\"" + objElementCible.children[x].getAttribute(objElementCible.children[x].attributes[y].name) + "\"";
19.     }
20.    }
21.    switch (strTagName.toLowerCase())
22.    {
23.     case "img" : strResultHTMLToXHTML += " />";
24.      break;
25.     case "br" : strResultHTMLToXHTML += " />";
26.      break;
27.     default : strResultHTMLToXHTML += ">";
28.      var strNodesValue = "";
29.      for (var z=0;z<objElementCible.children[x].childNodes.length;z++)
30.      {
31.       if ((objElementCible.children[x].childNodes[z].nodeType == 3) && (objElementCible.children[x].childNodes[z].nodeValue != null))
32.        strNodesValue += objElementCible.children[x].childNodes[z].nodeValue;
33.       }
34.       strResultHTMLToXHTML += strNodesValue;
35.       HTMLToXHTML2(objElementCible.children[x]);
36.       strTagName = objElementCible.children[x].tagName;
37.       strResultHTMLToXHTML += "</" + strTagName.toLowerCase() + ">";
38.    }
39.   }
40. }
41. 
42. function HTMLToXHTML(objElementCible)
43. {
44.   HTMLToXHTML2(objElementCible);
45.   var strTmpResult = strResultHTMLToXHTML;
46.   strResultHTMLToXHTML = "";
47.   return strTmpResult;
48. }

Vous aurez sans doute remarqué en regardant le listing que la fonction HTMLToXHTML2 contient beaucoup plus de lignes de code que la fonction HTMLToXHTML. En fait, c'est HTMLToXHTML2 qui se charge d'effectuer presque tout le travail.

HTMLToXHTML a été créé simplement pour permettre de retourner un résultat correct. Durant le stade récursif à l'intérieur de HTMLToXHTML2, la fonction ajoute des données à la suite de celles déjà présentes dans la variable globale strResultHTMLToXHTML. La valeur de cette variable est remise à neuf juste avant que la fonction HTMLToXHTML renvoie un résultat.

Description du listing

Children Collection : Cette «collection» contient des renseignements sur tous les éléments enfants dans un document. Le listing débute par spécifier qu'il faut parcourir tous les éléments enfants de l'élément passé en paramètre, c'est-à-dire, effectuer une boucle de 0 à children.length. length est une propriété qui contient le nombre d'éléments dans la collection.

On cré ensuite le début de la balise en allant chercher le nom de la balise en position x en utilisant la propriété tagName et en convertissant celui-ci en lettres minuscules.

On cré ensuite le début de la balise en allant chercher le nom de la balise en position x en utilisant la propriété «tagName» et en convertissant celui-ci en lettres minuscules.

On vérifit ensuite si l'attribut «class» de l'élément est présent.

Remarque : La collection «attributes» ne contenant pas de mention à propos de l'attribut «class», nous devons utiliser un code spécifique à cet attribut.

Pour effectuer la vérification, on utilise la propriété «className». Si celle-ci est une chaine de caractères non-vide, on cré l'attribut «class» et on lui assigne sa valeur. Il reste ensuite à convertir tous les attributs. Pour celà, il existe une collection nommée «attributes» dont on se sert pour naviguer parmis les attributs, de la même façon que «children».

Le problème avec cette collection, c'est qu'elle contient tous les attributs possibles pour la balise cible et non pas seulement celles définies dans le code écrit par le créateur de la page.

Pour ne pas réécrire inutilement tout ces attributs dans notre balise, on vérifit à l'aide de la méthode «getAttribute» si l'attribut en case y de la collection contient une valeur. Lorsque cette méthode retourne une valeur null, celà signifit que l'attribut n'est pas présent dans la balise. La méthode peut aussi retourner [object] dans certain cas. Puisque celà ne concerne pas notre besoin, on élimine aussi cette possibilité.

Remarque : Vous constaterez que un peu plus bas dans le code certain nom d'attribut sont évalués (contenteditable et loop). Ce code a été volontairement ajouté dans le but de rejeter ces attributs puisque ceux-ci ne font pas partie de la spécification du W3C (organisme qui détermine les standards du Web tel HTML ou encore XHTML par exemple).

La dernière partie du programme est une instruction «switch». Cele-ci sert à détecter tous les éléments qui ne sont formés que d'une seule balise. Remarquez que les deux éléments présents (img et br) ne sont pas les seul dans ce cas. Nous pourrions en ajouter d'autres comme hr, link, meta etc...

Si l'élément est formé d'une balise ouvrante et fermante, il reste à trouver le texte (si il y en a) à l'intérieur de cet élément et aussi à appeler à nouveau la fonction HTMLToXHTML2 pour convertir tous les éléments enfants de cet élément. Pour trouver le texte dans un élément cible, on doit trouver un noeud (node) dont la valeur de la propriété «nodeType» est égale à 3, c'est-à-dire, à du texte.

Auteur : Sylvain Bilodeau

Date de mise en ligne : 2002-11-25

Aucun commentaire pour l'instant.