Présentation de l'exercice
Nous voulons construire dynamiquement un sommaire pour un document assez long. Il doit être conçu en javascript et se présenter dans un menu sur le côté de la page. Nous allons décrire une première solution simple à ce problème, grâce au Document Object Model du W3C.
Voici un exemple de structure de texte et donc de menu (quand on enlève le contenu :-))
Premier titre (h2) Contenu (éventuellement) Petit titre A (h3) Du contenu Petit titre B (h3) Du contenu Deuxieme titre (h2) Contenu (éventuellement) Petit titre C (h3) Contenu Petit titre D (h3) Contenu
Le contenu dont on veut faire un sommaire est présent dans un balise identifiée comme "content". Ce texte est "hiérarchisé" par des balises d'entête. Nous nous limitons aux niveaux h2
et h3
.
Dans un premier temps, je conseille de faire le sommaire en fin de page pour éventuellement le décaler par positionnement.Voici un squelette de page possible :
<!doctype html>
<html>
<head>
<script>
function creerSommaire() {}
</script>
</head>
<body>
<div id="content">
Les éléments h2 et h3 qui nous intéressent
sont là
</div>
<div id="sommaire">
Au départ le menu est vide
</div>
<script>
creerSommaire();
</script>
</body>
</html>
Une documentation sur les fonctions DOM est disponible sur cette page : https://developer.mozilla.org/en-US/docs/Web/API/Node
Mise en oeuvre
Générer une liste
Pour générer la liste, il faut être capable de parcourir le document et en particulier de découvrir séquentiellement les h2
et les h3
.
Les éléments h2
et h3
sont frères (siblings) : ils ne sont pas imbriqués les uns dans les autres.
Vous avez accès à la méthode javascript standard mais relativement récente querySelector()
et à la propriété non moins récente nextElementSibling
.
Le résultat de cette étape est un menu avec les h2
et h3
sans numérotation et sans lien mais dans le bon ordre !
Pour information, voici la méthode nextSiblingElement()
une implémentation possible permettant de calculer la propriété nextElementSibling
lorsqu'elle n'est pas disponible. Grâce à prototype
, cette méthode enrichit Object
.
Object.prototype.nextSiblingElement = function() {
var n = this;
do n = n.nextSibling;
while (n && n.nodeType != 1); /* noeud non élément */
return n;
}
Ancres
On veut pouvoir cliquer sur une élément du sommaire et aller au document au bon endroit, il faut ajouter des ancres dans le document, c'est-à-dire des identifiants aux entêtes h2
et h3
si elles n'en ont pas ! (Dans le cas contraire, il faut réutiliser les identifiants qui existent).
Un identifiant ne peut être un simple nombre !
Numéroration
La dernière étape est d'ajouter une numérotation du document avec le javascript.
1. Premier titre (h2) 1.1 Petit titre A (h3) 1.2 Petit titre B (h3) 2. Deuxième titre (h2) 2.1 Petit titre C (h3) 2.2 Petit titre D (h3)
Voilà finalement le morceau de code, très simplifié, que je propose :
var elements = document.getElementById("content");
var h2 = elements.getElementsByTagName("h2");
var e = h2[0];
var i =0, j = 1, done = 0;
while (e!=null) {
if (e.tagName.toLowerCase().indexOf("h2")>=0) {
if (done==3)
document.writeln("</ol>");
i++;
document.write("<li><a> href=\'#a"+i+"\'>"+e.innerHTML+"</a></li>");
e.innerHTML = i+". "+e.innerHTML;
e.setAttribute("id", "a"+i);
done = 2;
} else if (e.tagName.toLowerCase().indexOf("h3")>=0) {
if (done==2) {
document.writeln("<ol>");
j=1;
}
document.write("<li>"+e.innerHTML+"</li>");
e.innerHTML = i+"."+j+". "+e.innerHTML;
j++;
done = 3;
}
e = e.nextObject(); // e.nextElementSibling();
}
if (done==3)
document.writeln("</ol>");
On time
Pour afficher le sommaire où on veut, il faut modifier le document quand il est complètement chargé. L'attribut onload
de la balise body
permet de détecter le chargement complet de la page. Il faut alors créer un fonction qui va peupler le div
qui va bien.
Si on n'attend pas que le document soit complètement chargé, on n'obtiendra que les balises déjà définies, ensemble qui poura éventuellement être vide.
Pour modifier le div
, soit on crée une chaîne de caractères que l'on place dans un innerHTML
, soit on utilise les fonctions du DOM.
Limites
Il est légitime de se demander si l'accessibilité est préservée et si le référencement est toujours possible. En ce qui concerne le référencement, on n'ajoute pas de nouveau contenu donc cela ne devrait pas poser de probleme.
Conclusion
Vous avons obtenu un joli sommaire dynamique ! On aurait pu fournir une fonction capable de traiter différents niveaux d'entête :-)