tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
ISIMA
  • twitter
  • linkedin
  • viadeo

[JS] sommaire

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 :-)