06-01-2005
Qu'il est agréable de trouver sur un plan le fameux macaron rouge "vous êtes ici". Sur un site web, c'est un peu pareil, il est de bon ton de dire au visiteur où il se situe dans le site. Généralement cela consiste à différencier dans la barre de navigation l'item correspondant à la page active.
Une pratique courante consiste à effectuer cette opération côté serveur. Comme dans l'exemple donné dans A List Apart, on renseigne sur chaque page une variable appelée par exemple $pageCourante ($pageCourante = "accueil") puis on vérifie à l'affichage de la navigation pour chaque item si il s'agit de la $pageCourante. Si c'est le cas, on affecte un id spécifique pour différencier l'item des autres. Grossièrement, le code PHP ressemble à ça :
<ul id="nav">
<li<?php if ($pageCourante=="accueil")
echo " id=\"pageActive\""; ?>>
<a href="index.php">Accueil</a></li>
<li<?php if ($pageCourante=="produits")
echo " id=\"pageActive\""; ?>>
<a href="produits.php">Produits</a></li>
<li<?php if ($pageCourante=="services")
echo " id=\"pageActive\""; ?>>
<a href="services.php">Services</a></li>
<li<?php if ($pageCourante=="contact")
echo " id=\"pageActive\""; ?>>
<a href="contact.php">Contact</a></li>
</ul>
Ca fonctionne bien, d'ailleurs j'ai moi-même adopté cette technique sur de nombreux sites. Néanmoins, je me demande maintenant si le fait que ce soit le serveur qui s'en occupe offre vraiment un intérêt et ce, pour au moins deux raisons. D'une part parce que cela oblige à rajouter pour chaque fichier du site le nom de la page en cours ($pageCourante = "accueil"), ce qui implique au pire de la maintenance fastidieuse ou au mieux un développement supplémentaire pour le gérer automatiquement. D'autre part, parce que je ne vois pas de valeur ajoutée à l'utilisation d'un langage serveur pour ça. Pas de problème de sécurité, simple information visuelle, bref, tout me fait plutôt pencher pour une solution côté client avec javascript.
Avant de nous plonger dans le code, dégageons la structure du script que nous allons écrire.
Côté résultat final, ça se passe par là. Côté code, ça donne :
function highlightNav() {
var chemin = "";
var cheminComplet = "";
// on essaye de détecter la page en cours pour modifier le style du lien actif
if(document.getElementById("nav")) {
// on récupère la page en cours
// si l'URL comporte une query string, on la retire
if(document.location.search) {
cheminComplet = document.location.href;
cheminCompletSansQueryString = cheminComplet.split(document.location.search);
cheminComplet = cheminCompletSansQueryString[0];
} else {
cheminComplet = document.location.href;
}
// si il n'y a pas de fichier après le dernier slash, on doit être sur la page index.php
cheminCompletDecoupe = cheminComplet.split("/");
if (cheminCompletDecoupe[cheminCompletDecoupe.length-1] == "") {
chemin = cheminComplet;
cheminComplet += "index.php";
} else {
chemin = cheminCompletDecoupe.splice(0,cheminCompletDecoupe.length-1)
chemin = chemin.join("/");
chemin += "/";
}
// on boucle sur les balises <a> pour récupérer leur href
listeDesLiens = document.getElementById("nav").getElementsByTagName("a");
for (var i=0; i<listeDesLiens.length; i++) {
// on compare le href avec le chemin de la page en cours
if(listeDesLiens[i].getAttribute("href") == cheminComplet || (chemin + listeDesLiens[i].getAttribute("href")) == cheminComplet) {
// on modifie le style du lien actif
listeDesLiens[i].style.color = "#cc0000";
// on sort de la boucle
break;
}
}
}
}
Parmi les problèmes à gérer, il faut noter que Firefox diffère d'Opera ou d'Internet Explorer sur un point important de notre script. Au moment de demander le contenu de l'attribut href des balises <a>, Firefox nous retourne le contenu exact, à savoir "produits.php" par exemple, tandis que les 2 autres nous retournent "http://www.monserveur.com/monRepertoire/produits.php". Au moment de comparer le lien avec le nom de la page en cours, il faut donc faire les deux tests, ce qui implique d'avoir retenu au préalable deux variables : le chemin (http://www.monserveur.com/monRepertoire/) et le chemin complet (http://www.monserveur.com/monRepertoire/produits.php).
Par ailleurs, il faut s'assurer lorsque nous manipulons l'URL de la page que celle-ci ne comprenne page un paramètre qui nous compliquerait la vie (mapage.php?monparametre=mavaleur). Ce qui nous intéresse c'est le chemin du fichier, pas le paramètre. On teste donc si l'URL comprend une query string et on la supprime.
if(document.location.search) {
cheminComplet = document.location.href;
cheminCompletSansQueryString = cheminComplet.split(document.location.search);
cheminComplet = cheminCompletSansQueryString[0];
}
Autre souci, si on se trouve à la racine d'un répertoire (http://www.monserveur.com/monRepertoire/), c'est la page par défaut qui sera appelée, index.htm, index.html, index.php, index.asp, etc. Pour autant, document.location.href ne nous retournera toujours que http://www.monserveur.com/monRepertoire/, sans plus de précision. Empiriquement, on déterminera donc dans notre cas précis qu'utilisant PHP, c'est la page index.php qui sera appelée si on se trouve dans ce cas de figure.
cheminCompletDecoupe = cheminComplet.split("/");
if (cheminCompletDecoupe[cheminCompletDecoupe.length-1] == "") {
chemin = cheminComplet;
cheminComplet += "index.php";
} else {
chemin = cheminCompletDecoupe.splice(0,cheminCompletDecoupe.length-1)
chemin = chemin.join("/");
chemin += "/";
}
Comme d'habitude ce code est fait rapidement et sans doute sujet à discussion. Les commentaires sont donc les bienvenus !