Bon ça m'a pris plus longtemps que prévu, dû à un problème de connexion ...
Pour commencer la fonction citée ci-dessus (document.implementation.hasFeature( "HTML", "2.0" ); ) ne fonctionne pas sous IE.
Alors comment fonctionne ce bout de code.
Le principe est le suivant :
On part du premier enfant du body en définissant le niveau de titre recherché à 1, et le préfixe de nos id à "toc". C'est ce que fait la fonction generateToc() avec ce bout de code :
nextLevel( "toc" , 1, document.body.firstChild )
Dans la fonction nextLevel(), on commence par créer une liste <ul> et au passage on initialise quelques variables :
var i = 1;
var list = document.createElement( "ul" );
var listitem = null;
var nextelement = curelement;
var doneSubLevel = true;
"i" nous servira à construire les ID.
nextelement est une copie de l'élément de départ, mais au fur et à mesure que l'on parcourra le document, il s'agira de l'élément en cours.
je reviendrai sur "listitem" et doneSubLevel plus loin.
On parcourt les noeuds jusqu'à trouver un élément (noeud dont le "nodeType" est 1) dont le "tagName" commence par H :
do
{
if( nextelement.nodeType == 1 && nextelement.tagName.substr(0,1) == "H" )
{
(Attention pour un document servi en tant que "text/html" le tagName est toujours en majuscule, même si c'est du xhtml.)
Si cet élément a le bon niveau de titre (on compare le niveau passé en paramètre au second caractère du tagName) :
On lui crée un ID avec le préfixe passé en paramètre et en y ajoutant un "_" et un numéro d'occurence. (ici c'est notre compteur "i" ). Au passage on se garde ce nouvel id sous le coude dans la variable nextid.
nextlevel = nextelement.tagName.substr(1,1); //récupération du second caractère du tagName
if( nextlevel == curlevel ) // comparaison avec le niveau de titre passé en paramètre
{
nextelement.id = nextid = curid + "_" + i++;
On crée un lien vers notre titre avec son id tout neuf :
var anchor = document.createElement( "a" );
anchor.href = "#" + nextid;
On recopie tous les noeuds enfants de notre titre dans ce lien.
for( j = 0; j < nextelement.childNodes.length; j ++ )
{ anchor.appendChild( nextelement.childNodes[j].cloneNode(true)); }
Ensuite on crée un <li> dans (le "listitem" déclaré plus haut), on y ajoute notre lien et on rattache le tout à la liste crée au début de la fonction :
listitem = document.createElement( "li");
listitem.appendChild( anchor );
list.appendChild( listitem );
Ensuite on défini doneSubLevel à false, pour signifier que l'on n'a pas encore traité les titres de niveau inférieurs (donc avec un numéro <h
x> supérieur) qui suivent notre titre courant.
doneSubLevel = false ;
}
Si notre élément a un niveau de titre inférieur (donc avec un numéro <h
x> supérieur) et que l'on n'a pas encore traité les niveaux de titre inférieur (doneSubLevel est faux), on n'a donc pas fait ce qui précède pour l'élément courant.
Comme le niveau ne correspond pas à celui qu'on cherche, on rappelle la fonction nextlevel() (celle là même qui est en cours d'execution et que je suis en train de décrire, et qui est donc une fonction récursive), avec le dernier ID qu'on a créé et qui servira de préfixe, et avec le niveau de titre que l'on vient de trouver, et on part de l'élément courant.
La fonction retournera un <ul> que l'on ajoute au listitem courant, juste derrière le titre que l'on y a mis précédement. Notez que si on n'a pas trouvé de titre du bon niveau, ici ça plante, puisque listitem est défini à null par défaut.
On n'oublie pas de positionner doneSubLevel à true pour indiquer qu'on a déjà traité les sous niveaux pour le titre courant.
else if( nextlevel > curlevel && !doneSubLevel )
{
listitem.appendChild( nextLevel( nextid, nextlevel, nextelement ) );
doneSubLevel = true;
}
Si on trouve un niveau de titre superieur à ce qu'on cherche, il nous faut donc remonter d'un cran, et on laisse en plan ce qu'on était en train de faire, on renvoie notre liste <ul> dans l'état où elle est.
La fonction appelante se chargera alors de l'ajouter là où il faut, soit après un titre dans un <li> si nextlevel() a été appelé par nextlevel() soit avant le premier enfant du body si nextlevel() a été appelé par generateToc().
}
else if( nextlevel < curlevel )
{
return list;
}
Si on est pas sorti de la fonction à l'étape suivante, on cherche le prochain noeud, s'il est "null" on a fini le document et on sort de la boucle, puis on renvoie la liste.
nextelement = nextelement.nextSibling;
} while( nextelement != null )
return list;
}
Fin de la fonction nextlevel().
Ce qui est difficile à appréhender et à décrire c'est qu'elle est récursive et qu'elle fait la même chose pour tous les niveaux de titre.
en gros ça fait le parcours suivant :
premier enfant du body : appel de nextlevel( niveau1 ) -> H1 -> H1 -> H2 ah, on appelle nextlevel( niveau2 ) -> H2 -> H2 -> H1 : ah, on retourne la liste des H2 -> H1 -> h3 : on appelle nextlevel( niveau3 ) -> h3 -> h1 ; on retourne la liste des h3 -> etc... jusqu'à la fin du document.
Les autres tags sont ignorés.
J'espère que l'explication est utile et assez claire...
Je suis pas sûr de me comprendre.
J'oubliais, mes fichiers sont en ligne à ces adresses :
http://lanza.online.fr/toc.html
http://lanza.online.fr/toc.js Modifié par Lanza (06 Nov 2005 - 21:21)