Générer une table des matières dans une page Web

Résumé

Ce document propose un script qui permet de générer une table des matières à partir des titres h1, h2, h3, etc. d'une page Web.

Auteur: Christian Rémillard, GRDS

Modification: 2003-09-05

Cette page est en cours d'élaboration.

Fonction tdm

tdm(id, [niveau tdm, [titre min, [titre max]]])

Paramètres

id
Obligatoire. Chaîne de caractères (String). Valeur de l'attribut id de l'élément où sera générée la table des matières.
niveau tdm
Facultatif. Numéro (Number) compris entre 1 et 6. Niveau du titre (h1, h2, h3, etc.) de la table des matières. Valeur par défaut: 2.
titre min
Facultatif. Numéro (Number) compris entre 1 et 6. Niveau supérieur du titre (h1, h2, h3, etc.) à inclure dans la table des matières. Valeur par défaut: 2. Les titres de niveau 1, h1, ne sont pas inclus dans la table des matières par défaut.
titre max
Facultatif. Numéro (Number) compris entre 1 et 6. Niveau inférieur du titre (h4, h5, h6, etc.) à inclure dans la table des matières. Valeur par défaut: 6.

Exemples

L'exemple qui suit insère une table des matières à la place de l'élément dont l'attribut id="tdm".

Remarques

Version: 1.0

Modification: 2003-01-07

Description: Écrit une puce à numéro au début du contenu des éléments concernés.

Langages: JavaScript 1.0 et Document Object Model (Core) Level 1

On peut créer plusieurs numérotations indépendantes l'une de l'autre en ayant recours à plusieurs appel du script lors de l'initialisation de la page. Pour plus d'informations, voir le code source de cette page.

En plus de la classe CSS utilisée pour la numérotation, ce script affecte la classe compteur à la puce à numéro.

Télédéchargement

On peut se procurer le script à même le code source de cette page, ou encore télédécharger les fichiers.

Installation

  1. Copier les fichiers télédéchargés (tdm.js, tdm-1.css) dans le dossier où est situé votre page Web.
  2. Insérer dans l'entête du document HTML (c'est-à-dire dans l'élément head) un lien vers le script. Au besoin corriger le lien vers le fichier:

    <script type="text/javascript" src="tdm.js" charset="iso-8859-1"></script>
    
  3. Insérer dans l'entête du document HTML (c'est-à-dire dans l'élément head) un lien vers la feuille de style css pour la table des matières. Au besoin corriger le lien vers le fichier:

    <link type="text/css" rel="stylesheet" href="tdm-1.css" charset="iso-8859-1"></link>
    
  4. Insérez dans votre document un élément (par exemple div) avec dans l'attribut id une chaîne de caractères sans espaces ni accents qui servira à identifier l'endroit où la table des matières sera insérée (par exemple "tdm");

    <div id="tdm"></div>
  5. Placer un appel au script dans l'élément <body> sous la forme:

    <body onload="tdm('id', [niveau tdm, [titre min, [titre max]]]);">

    ExempleDescription
    maketoc('tdm'); 
    Insère une table des matières à la place de l'élément dont l'attribut id="tdm".
    maketoc('tdm',2,2,2);
    
    Insère une table des matières dont le titre est <h2>Table des matières</h2> et qui ne comprend que les titres de niveau 2 (h2).
    maketoc('tdm',2,3);
    
    Insère une table des matières dont le titre est <h2>Table des matières</h2> et qui ne comprend que les titres de niveau 3 (h3) ou plus (h4, h5 ou h6).

    Note: la valeurs du paramètre id doit être placée entre quillemets simples. Les paramètres entre crochets sont facultatifs.

Exemples

Consultez la source de cette page.

Code source

Appel de la fonction

<html>
<head>
...
<script type="text/javascript" src="tdm.js" charset="iso-8859-1"></script>
...
</head>
<body onload="tdm('tdm',2,2,2);">
...
<div id="tdm">La table des matières sera générée ici</div>
...
</body>
</html>

Fonction

/**
 * Crée une table des matières à partir des titres <h1>, <h2>, <h3> du document.
 **/
function tdm(replace, tdmHeadingLevel, minHeadingLevel, maxHeadingLevel) {

	// Global parameters

	// Create a link back to the contents
	var createBackLink = false;

	// Create a template for section number
	var sectionNoTemplate = document.createElement('span');
	sectionNoTemplate.className = 'section-no';

	// Create a template for a tdm entry number
	var tdmItemNoTemplate = document.createElement('span');
	tdmItemNoTemplate.className = 'tdm-item-no';

	// tdm heading level (i.e. 2 = h2, 3 = h3)

	if (!tdmHeadingLevel || tdmHeadingLevel < 1 || tdmHeadingLevel > 6) {
		var tdmHeadingLevel = 2;
	}

	if (!minHeadingLevel || minHeadingLevel < 1 || minHeadingLevel > maxHeadingLevel) {
		var minHeadingLevel = 2;
	}

	if (!maxHeadingLevel || maxHeadingLevel > 6 || maxHeadingLevel < minHeadingLevel) {
		var maxHeadingLevel = 6;
	}

	// Get the element node from the 'replace' id
	replace = document.getElementById(replace);

	// I18N

	// Label for the link back to the contents
	var backToContentsLabel = "retour";
	// Label for table of contents section
	var tdmLabel = "Table des matières";

	// Create a <div> element that is the root of the tdm tree
	var tdm = document.createElement("div");
	tdm.setAttribute('id','tdm');
 
	// Start the tdm with an anchor so we can link back to it

	var tdmHeadingNode = document.createElement('h' + tdmHeadingLevel);
	tdmHeadingNode.setAttribute('id','tdm-titre');
	tdmHeadingNode.appendChild(document.createTextNode(tdmLabel));
	tdm.appendChild(tdmHeadingNode);                   // Insert it
 
	// Create a <div> element that will hold the tdm and add it 
	var tdmBody = document.createElement("div");
	tdmBody.setAttribute('id','tdm-corps');
	tdm.appendChild(tdmBody);
 
	// Initialize an array that keeps track of section numbers
	var sectionNumbers = [0,0,0,0,0,0];

	// Recursively traverse the body of the document, looking for sections
	// sections marked with <h1>, <h2>, ... tags, and use them to create 
	// the tdm by adding rows to the table

	addSections(document.body, tdmBody, sectionNumbers);
 
	// Finally, insert the tdm into the document by replacing the node
	// specified by the replace argument with the tdm subtree

	replace.parentNode.replaceChild(tdm, replace);

	// This method recursively traverses the tree rooted at Node n, looking
	// looking for <h1> through <h6> tags, and uses the content of these tags
	// to build the table of contents by adding rows to the HTML table specified
	// by the tdm argument. It uses the sectionNumbers array to keep track of
	// the current section number.
	// This function is defined inside of maketdm(  ) so that it is not
	// visible from the outside. maketdm(  ) is the only function exported
	// by this JavaScript module.

	function addSections(n, tdm, sectionNumbers) {

		// Loop through all the children of n

		for(var m = n.firstChild; m != null; m = m.nextSibling) {

			// Check whether m is a heading element. It would be nice if we
			// could just use (m instanceof HTMLHeadingElement), but this is
			// not required by the specification and it does not work in IE.
			// Therefore, we must check the tagname to see if it is H1-H6.

			if ((m.nodeType == 1) &&  /* Node.ELEMENT_NODE */ 
				(m.tagName.length == 2) && (m.tagName.charAt(0) == "H")) {

				// Figure out what level heading it is

				var level = parseInt(m.tagName.charAt(1));

					//if (!isNaN(level) && (level >= 2) && (level <= 6)) {
					if (!isNaN(level) && (level >= minHeadingLevel) && (level <= maxHeadingLevel)) {

						var fragmentId = '';

						// Increment the section number for this heading level

						sectionNumbers[level-2]++;

						// And reset all lower heading-level numbers to zero

						for(var i = level - 1; i < 6; i++) sectionNumbers[i] = 0;

						// Now combine section numbers for all heading levels
						// to produce a section number like "2.3.1."

						var sectionNumber = "";
						for(var i = 0; i < level - 1; i++) {
							sectionNumber += sectionNumbers[i];
							if (i < level-1) sectionNumber += ".";
						}
 
						// Create an anchor to mark the beginning of this section
						// This will be the target of a link we add to the tdm
						// First, look if ther's already an id attribute

						if (m.getAttribute("id")) {
							fragmentId = m.getAttribute("id");
						} else {

							fragmentId = "SECT"+sectionNumber;
							m.setAttribute("id", fragmentId);
						}
 
						// Create a link back to the tdm and make it a
						// child of the anchor

						if (createBackLink) {
							var anchor = document.createElement("span");
							anchor.className = 'tdm-retour';
							var backlink = document.createElement("a");
							backlink.setAttribute("href", "#tdm");
							backlink.appendChild(document.createTextNode(backToContentsLabel));
							anchor.appendChild(backlink);
 
							// Insert the anchor into the document right before the
							// section header
							n.insertBefore(anchor, m);
						}
 
						// Now create a link to this section. It will be added
						// to the tdm below.

						var link = document.createElement("a");
						link.setAttribute("href", "#" + fragmentId);

						// Get the heading text using a function defined below

						var sectionTitle = getTextContent(m);

						// Use the heading text as the content of the link

						link.appendChild(document.createTextNode(sectionTitle));
 
						// Create a new entry for the tdm

						var tdmItem = document.createElement("div");
						tdmItem.className = 'tdm-item tdm-niveau-' + i;

						// Create two columns for the row

						var tdmItemEntry = document.createElement("span");
						tdmItemEntry.className = 'tdm-item-texte';

						tdmItemNoNode = tdmItemNoTemplate.cloneNode(false);
						tdmItemNoNode.appendChild(document.createTextNode(sectionNumber+" "));
						tdmItem.appendChild(tdmItemNoNode);

						// Put a link to the section in the second column
						tdmItemEntry.appendChild(link);

						// Add the columns to the row, and the row to the table
						//tdmItem.appendChild(tdmItemNumber);
						tdmItem.appendChild(tdmItemEntry);
						tdm.appendChild(tdmItem);
 
						// Modify the section header element itself to add
						// the section number as part of the section title

						sectionNumberNode = sectionNoTemplate.cloneNode(false);
						sectionNumberNode.appendChild(document.createTextNode(sectionNumber+" "));
						m.insertBefore(sectionNumberNode, m.firstChild);

						}
					}

					else {  // Otherwise, this is not a heading element, so recurse

						addSections(m, tdm, sectionNumbers);
					}
				}
			}
 
			// This utility function traverses Node n, returning the content of
			// all Text nodes found and discarding any HTML tags. This is also
			// defined as a nested function, so it is private to this module.

			function getTextContent(n) {
				var s = '';
				var children = n.childNodes;
				for(var i = 0; i < children.length; i++) {
					var child = children[i];
					if (child.nodeType == 3 /*Node.TEXT_NODE*/) s += child.data;
					else s += getTextContent(child);
				}
				return s;
			}
		}
		

© 2003, GRDS - Groupe de recherche départemental sur les documents structurés. Commentaires: <grds@umontreal.ca>