1. Analyse sémantique

Avant de foncer tête baissée dans le code, réfléchissons un petit peu à la façon de procéder. Une petite analyse sémantique de l'arborescence voulue nous permettra de définir précisément les balises XHTML à utiliser. Cela nous permettra aussi de penser à l'utilisation que l'on va faire des styles CSS.

Pour vous donner une idée, voici le résultat recherché :

Rendu voulu de l'arborescence

Comment pourrait-on définir cette arborescence ?

C'est un ensemble de listes non ordonnées de liens dont certains possèdent une image cliquable en forme de croix qui permet de dérouler la sous-partie correspondante.

Les listes seront donc représentées par des balises ul, dont les liens seront des balises li. Chaque lien permettant d'ouvrir une sous-partie contiendra à son tour une liste sous forme de balise ul. Ces éléments seront précédés d'une balise image img cliquable représentant une croix. Les autres éléments seront quand à eux précédés d'une balise image img non cliquable représentant une intersection dans la ligne pointillée. Il faut aussi, lors du déroulage d'une sous-partie, penser à continuer la ligne pointillé jusqu'au prochaine élément (cf. entre Composants PC et Portable).

2. Le découpage des images

Avant de commencer à coder, nous allons d'abord découper les images nécessaires à partir d'une image représentant l'arborescence que l'on peut concevoir sous Photoshop ou Gimp. Dans mon cas, je vais utiliser l'image que je vous ai montré dans la partie 1 :

Découpe de l'arborescence

  1. L'image plus.gif représente la croix signifiant qu'une sous-partie peut être déroulée.
  2. L'image minus.gif représente la barre signifiant qu'une sous-partie peut être enroulée.
  3. L'image line.gif représente la ligne pointillée.
  4. L'image join.gif représente l'intersection dans la ligne pointillée.
  5. L'image joinbottom.gif représente une intersection en fin de ligne pointillée.

Pour ceux qui auraient la flemme de se faire ces images, le pack que j'ai utilisé est dispo en téléchargement.

3. Le code XHTML

A partir de l'analyse faite précédemment, voici le code XHTML que contient le fichier arbo.php :

<ul id="racine">
   <li><a href="arbo.php">Ordinateurs</a>
      <ul id="niv1" class="niv1">
         <li><img src="img/join.gif" alt="" /><a href="?menu=pc">PC de bureau</a></li>
         <li><img src="img/minus.gif" alt="[+]" class="clic" /><a href="?menu=composantspc">Composants PC</a>
            <ul class="niv2">
               <li><img src="img/join.gif" alt="" /><a href="?menu=composantspc&smenu=boitiers">Boitiers</a></li>
               <li><img src="img/join.gif" alt="" /><a href="?menu=composantspc&smenu=processeur">Processeur</a></li>
               <li><img src="img/joinbottom.gif" alt="" /><a href="?menu=composantspc&smenu=alimentation">Alimentation</a></li>
            </ul>
         </li>
         <li><img src="img/join.gif" alt="" /><a href="?menu=portable">Portable</a></li>
         <li><img src="img/minus.gif" alt="[+]" class="clic" /><a href="?menu=composantsportable">Composants Portable</a>
            <ul class="niv2 last">
               <li><img src="img/join.gif" alt="" /><a href="?menu=composantsportable&smenu=memoire">Mémoire</a></li>
               <li><img src="img/join.gif" alt="" /><a href="?menu=composantsportable&smenu=memoire&smenu2=corsair">Corsair</a></li>
               <li><img src="img/joinbottom.gif" alt="" /><a href="?menu=composantsportable&smenu=memoire&smenu2=kingston">Kingston</a></li>
            </ul>
         </li>
      </ul>
   </li>
</ul>

Quelques explications :

  • La class last permettra, avec les styles CSS, de ne pas afficher la ligne pointillée lorsque la dernière sous-partie sera déroulée.
  • Les attributs alt des images sont vides car ces images n'ont pas lieux d'être pour un affichage non graphique, sauf pour les images plus.gif et minus.gif, où l'attribut alt vaut respectivement [+] et [-] pour signifier la possibilité de déroulage/enroulage d'une sous-partie.
  • Les éléments ayant une sous-partie sont pour l'instant précédés de l'image minus.gif, afin que, dans le cas où l'internaute ai désactivé Javascript, l'image soit cohérente avec le fait que la sous-partie est déployée.
  • La classe clic permet de changer le pointeur de la souris lors du survol de l'image, afin de faire comprendre que celle-ci est cliquable.

4. Le résultat provisoire (sans Javascript)

A ce stage, nous disposons donc d'une arborescence XHTML/CSS valide.

5. Le code Javascript

Nous allons maintenant faire des petites fonction Javascript, qui permettront de mettre un peu d'intéractivité dans l'arborescence. Elle en restera pour autant accessible, car ce code ne sera ni intrusif, ni obligatoire pour le fonctionnement de l'arborescence. Même avec Javascript désactivé, le visiteur pourra l'utiliser normalement.

Voici les fonctions Javascript qui permettront le déroulement/enroulement des sous-parties, ainsi que celle qui enroulera toutes les sous-parties lors du chargement de l'arborescence. J'ai essayé de commenter le plus possible le code, afin de le rendre compréhensible pour tous. Des petites connaissances en Javascript et DOM seront certainement suffisantes pour la compréhension.

// Fonction qui affiche/cache un menu
function expand(li) {
	var node = li.firstChild;
	var img = li.firstChild;
	// parcours tous les fils pour trouver l'element UL
	while ( node.nodeName != "UL" )
		node = node.nextSibling;
	// parcours tous les fils pour trouver l'element IMG
	while ( img.nodeName != "IMG" )
		img = img.nextSibling;
	// affiche le menu
	if ( node.style.display == 'none' ) {
		node.style.display = 'block';
		img.src = 'images/arborescence/minus.gif';
		img.alt = '[-]';
	}
	// cache le menu
	else {
		node.style.display = 'none';
		img.src = 'images/arborescence/plus.gif';
		img.alt = '[+]';
	}
}

// Fonction qui affiche un menu ainsi que tous les menus supérieurs
function expandMultiple(id) {
	// recupere la source du clic
	a = document.getElementById(id);
	// recupere le menu a afficher
	var ul = a;
	while ( ul.nodeName != "UL" ) {
		ul = ul.nextSibling;
	}
	// affiche le menu et les menus supérieurs
	while(ul.nodeName=="UL") {
		if(ul.id != 'racine') {
			expand(ul.parentNode);
			ul = ul.parentNode.parentNode;
		}
	}
}

// Fonction qui cache tous les menus
function collapseMultiple() {
	// Recupere le menu de niveau 1
	niv1 = document.getElementById('niv1');
	// recupere tous les menus dépliants
	tab_ul = niv1.getElementsByTagName("UL");
	nb = tab_ul.length;
	// cache tous les menus
	for(var i=0; i<nb; i++) {
		expand(tab_ul[i].parentNode);
	}
}

// Fonction qui initialise l'arborescence
function initArbo(menu, smenu) {
	// ferme tous les menus
	collapseMultiple();
	// ouvre le smenu courant (passé en GET) si il existe
	if(document.getElementById(smenu)) {
		expandMultiple(smenu);
	}
	else {
		// sinon ouvre le menu courant (passé en GET) si il existe
		if(document.getElementById(menu)) {
			expandMultiple(menu);
		}
	}
}

Il suffit maintenant de rajouter un appel à ces fonctions sur l'événement onClick des images minus.gif, ainsi qu'au chargement de la page pour enrouler tous les sous-menus.

<img src="img/minus.gif" alt="" class="clic" onclick="expand(this.parentNode)" />

Et

<script type="text/javascript">
//<![CDATA[
// initialise l'arborescence
window.onLoad = initArbo('<?php print $_GET["menu"];?>', '<?php print $_GET["smenu"];?>');
//]]>
</script>

6. Le résultat final

Nous avons donc au final une arborescence fonctionnelle et surtout accessible, le tout grâce à XHTML, CSS et Javascript.

7. Conclusion

Et voilà, le tutoriel est terminé. Il ne vous reste donc plus qu'à tester tout ça de votre coté. Pour les plus feignants, tout le code, ainsi que les images sont disponibles dans un fichier compressé.