(Article rédigé par un groupe d’étudiants d’IUT dans le cadre d’un projet tutoré)
Sur la toile, plusieurs scripts vous proposent d’afficher une arborescence de votre système de fichier tout d’un bloc. Sympathique, mais si vous possédez beaucoup de dossier le chargement risque d’être (très) long… Avec l’Ajax, nous allons charger les branches de l’arbre au fur et à mesure des clics de l’utilisateur !
D’abord, avant de nous lancer à corps perdu dans le code pure et dure, réfléchissons à l’organisation de notre fichier HTML. Voici une proposition :
<p>Dossier racine
<p onclick=”javascript:ouvrir()”>Premier dossier</p>
<p onclick=”javascript:ouvrir()”>Second dossier</p>
<p>Fichier 1</p>
<p>Fichier 2</p>
<p>Fichier 3</p>
</p>
Bon, cela n’a pas l’air mal. Imaginons qu’on clique sur le second dossier, on aurait alors un code du genre :
<p>Dossier racine
<p onclick=”javascript:ouvrir()”>Premier dossier</p>
<p onclick=”javascript:ouvrir()”>Second dossier
<p onclick=”javascript:ouvrir()”>Premier sous-dossier</p>
<p onclick=”javascript:ouvrir()”>Deuxième sous-dossier</p>
<p>Fichier divers</p>
</p>
<p>Fichier 1</p>
<p>Fichier 2</p>
<p>Fichier 3</p>
</p>
Actuellement notre principe est faillible :
– On ne peut pas fermer les dossiers
– On inclus des balises utilisant “onclick” dans d’autres balises “onclick”, donc les fonctions risquent d’entrer en conflit
On va donc mettre le “onclick” à l’intérieur dans les deux cas grâce à la balise “span” de cette façon :
<p>Dossier racine
<p><SPAN onclick=”javascript:ouvrir()”>Premier dossier</SPAN></p>
<p><SPAN onclick=”javascript:fermer()“>Second dossier</SPAN>
<p><SPAN onclick=”javascript:ouvrir()”>Premier sous-dossier</SPAN></p>
<p><SPAN onclick=”javascript:ouvrir()”>Deuxième sous-dossier</SPAN></p>
<p>Fichier divers</p>
</p>
<p>Fichier 1</p>
<p>Fichier 2</p>
<p>Fichier 3</p>
</p>
Si on clique sur le nom du dossier, le “onclick” est écrasé par la liste des sous-dossiers et sous-fichiers. Ainsi, plus aucune inclusion mutuelle conflictuelle. Vous remarquerez que de cette manière on met aussi en place la fonction de fermeture du dossier. Cela soulève un nouveau problème : Quand la fonction de fermeture est appelée par le “span”, comment fait-elle pour vider l’intérieur “p” en parent ? Il faut trouver un moyen de récupérer ce “p”, et nous allons le faire grâce aux identifiant :
<p>Dossier racine
<p ID=”Premier dossier”>
<span onclick=”javascript:ouvrir()”>Premier dossier</span></p>
<p ID=”Second dossier”><span onclick=”javascript:fermer()”>Second dossier</span>
<p ID=”Second dossier/Premier sous-dossier”>
<span onclick=”javascript:ouvrir()”>Premier sous-dossier</span></p>
<p ID=”Second dossier/Deuxième sous-dossier”>
<span onclick=”javascript:ouvrir()”>Deuxième sous-dossier</span></p>
<p>Fichier divers</p>
</p>
<p>Fichier 1</p>
<p>Fichier 2</p>
<p>Fichier 3</p>
</p>
Le “span” contenant la fonction de fermeture contient dans son innerHTML l’identifiant du dossier à vider ! En d’autres termes, la fonction connaît la balise à vider lors de la fermeture. Après mise en forme, voilà donc à quoi ressemble notre page arborescence.html :
<html>
<head>
<link rel="stylesheet" type="text/css" href="arborescence.css" media="all">
<script type="text/javascript" src="arborescence.js"></script>
</head>
<body>
<h1>Arborescence</h1>
<p id="C:"><span onclick="javascript:ouvrir('C:');">Cliquez ici pour ouvrir l'arbre</span></p>
</body>
</html>
C’est tout ! La récursivité et l’Ajax feront le reste. Notez qu’ici le dossier racine sera le lecteur C:, si vous n’êtes pas sous Windows nous vous conseillons vivement de prendre un autre répertoire. Sachez tout de même qu’il ne faut pas mettre de “/” à la fin.
Nous avons déterminé la façon dont sera structuré notre page HTML, passons aux fonctions javascript grâce à notre fichier arborescence.js. D’abord implémentons notre fameuse fonction de création de requête Ajax :
/*
Fonction qui crée un objet XHR.
Cette fonction initialisera la valeur dans la variable globale “requete”
*/
var requete = null; /* On crée une variable qui contiendra l’objet XHR */
function creerRequete() {
try {
requete = new XMLHttpRequest(); /* On essaye de créer un objet XmlHTTPRequest */
} catch (microsoft) {
/* Si cela ne marche pas, on a peut-être affaire
à un navigateur de Microsoft. On tente alors de créer un objet ActiveX */
try {
requete = new ActiveXObject(‘Msxml2.XMLHTTP’);
} catch(autremicrosoft) {
/* Autre méthode si la première n’a pas marché */
try {
requete = new ActiveXObject(‘Microsoft.XMLHTTP’);
} catch(echec) {
/* Si aucune méthode ne fonctionne, on laisse l’objet vide*/
requete = null;
}
}
}
if(requete == null) {
alert(‘Votre navigateur ne semble pas supporter les objets XMLHttpRequest.’);
}
}
Ensuite travaillons sur la fonction d’ouverture des dossiers. Il s’agit tout simplement de récupérer le dossier dans les paramètres et de l’envoyer à la page PHP. On redirige ensuite le tout vers la balise portant l’identifiant du dossier.
function ouvrir(id) {
/* On récupère la balise doté de l’identifiant précisé */
src = document.getElementById(id);
/* On crée notre super objet XHR global */
creerRequete();
/* On construit à l’avance notre URL en passant les paramètre en GET */
var url = ‘arborescence.php?dir=’+id;
/* On édite les propriété de l’objet : type de paramètre,
url (avec paramètres) et une option autorisant une réponse du serveur */
requete.open(‘GET’, url, true);
/* On initialise la fonction de renvoi d’information */
requete.onreadystatechange = function() {
if(requete.readyState == 4) {
if(requete.status == 200) {
src.innerHTML = requete.responseText;
}
}
};
/* C’est partit ! On envoi la requête XHR au serveur */
requete.send(null);
}
La fonction de fermeture n’est pas beaucoup plus complexe. A partir du chemin complet du dossier, il faut récupérer le nom simple. Ensuite on doir remplacer le contenu de la balise identifiée par le chemin complet par la balise du dossier, mais fermée, comme ceci :
<span onclick=”javascript:ouvrir(‘le chemin complet’);”>le nom simple</span>
Voilà la fonction implémentée :
function fermer(id) {
/* On récupère la dernière partie du chemin complet du dossier, c’est à dire juste le nom du dossier */
var nom = new RegExp(‘/’);
nom = id.split(nom);
nom = nom[nom.length-1];
/* Le chemin complet du dossier est aussi son identifiant, à partir de celui-ci on peut récupérer la balise le représentant */
src = document.getElementById(id);
/* On écrase le contenu de la balise par le ‘span’ permettant l’ouverture du dossier */
src.innerHTML = ‘<span onclick=”javascript:ouvrir(\”+id+’\’);”>’+nom+'</span>’;
}
Bon, notre fichier Javascript est fait, attaquons nous au script PHP : arborescence.php. Le but de celui-ci sera de récupérer le chemin du dossier, d’analyser sont contenu et de le renvoyer formaté en HTML de façon à ce que les dossiers trouvés puissent être à leur tour ouverts.
<?php
if(isset($_GET[‘dir’]))
{
// Si le dernier caractère du chemin complet du dossier n’est pas un slash, en mettre un
if(substr($_GET[‘dir’],-1)!=”/”)
$_GET[‘dir’].=”/”;
// Voici nos deux variables de retour, elles sont vides pour le moment
$ret1 = “”;
$ret2 = “”;
// Ouvrir le répertoire
$dir = opendir($_GET[‘dir’]);
// Tant qu’il y a des choses dedans, s’il ne s’agit
//pas des dossier “.” et “..”, ajouter le fichier ou le dossier selon le formatage HTML
while ( ($v = readdir($dir))!=”” )
if( $v!=”.” && $v!=”..” )
if(is_dir($_GET[‘dir’].$v))
$ret1.='<p id=”‘.$_GET[‘dir’].$v.'”><span onclick=”javascript:ouvrir(\”.$_GET[‘dir’].$v.’\’);”>’.$v.'</span></p>
‘;
else
$ret2.='<p>’.$v.'</p>
‘;
// Enfin, on affiche le ‘span’ permettant la fermeture et on met à la suite les dossiers puis les fichiers
echo ‘<span onclick=”javascript:fermer(\”.substr($_GET[‘dir’],0,-1).’\’);” class=”diropen”>’.ereg_replace(“^.*/([^/]*)/”,”\\1″,$_GET[‘dir’]).'</span>
‘.$ret1.’
‘.$ret2;
}
?>
Pour agrémenter le tout voilà une petite mise en page CSS grâce au fichier arborescence.css :
.diropen {
color: #ff0000;
cursor: pointer;
}
.dirclose {
color: #0000ff;
cursor: pointer;
}
.cadre {
margin-left: 50px;
}
.fic {
color: #008800;
margin-left: 50px;
}
Voilà, notre système doit fonctionner correctement. Notons tout de même que les caractères spéciaux ne sont pas gérés ! Suivant le navigateur l’ouverture d’un dossier contenant des accents peut être cause d’erreur.