Bonjour à tous,
Voici l'ébauche de mon véritable premier article.
####################################################
Virtualisation de pages web en DOM
En Javascript/AJAX, vous aurez sûrement déjà rencontré l'impossibilité pour l'utilisateur d'employer les fonctions "page précédente" et "page suivante".
Bien entendu, il existe des solutions jouant sur le hash mais ce n'est pas le cadre de ce sujet.
Je vais vous présenter une solution DOM, elle n'est pas correctement gérée par les navigateurs mais je la trouve plus qu'intéressante et espère que son implémentation sera corrigée par les concepteurs de navigateurs.
Vous ne le saviez peut-être pas mais votre navigateur n'enregistre pas que l'url des pages que vous visitez, en effet, il enregistre aussi l'état DOM de ces pages.
Pour tester le code présent dans cet article, je vous conseille d'utiliser Firefox, navigateur qui semble au plus proche d'une gestion totale.
Les méthodes que nous allons utiliser à cet effet sont :
document.open([MIMEtype [, historyPosition]]), elle sert à ouvrir un nouveau document dans l'onglet courant, ce qui ajoutera une nouvelle entrée à l'historique du navigateur. En théorie, il devrait être possible d'ajouter cette nouvelle entrée à une position déterminée, dans l'historique, mais nous ne l'emploierons pas, par respect de l'environnement de notre visiteur et afin de simuler la navigation classique.
document.writeln(text), servant à écrire dans le document courant.
document.close(), pour fermer le chargement du document.
Mise en pratique
Prenez une page web classique avec un bouton:
Ouvrons un document virtuel en Javascript :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Previous/Next DOM sample</title> </head> <body> <button>goTo</button> </body> </html>
La base est établie mais il serait bien de travailler avec un document valide :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 // La fonction ouvrant un document virtuel function goTo(){ document.open('text/html'); document.close(); } // Attachons cette fonction au clic sur notre bouton document.getElementsByTagName('button')[0].onclick=goTo;
À présent, une petit peu de contenu pour illustrer l'exemple et, puisque nous avions déjà du code présent dans la page, autant le réutiliser :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 function goTo(){ document.open('text/html'); // Ajoutons-y la déclaration XML document.writeln('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'); // Ainsi qu'un doctype document.writeln('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'); document.close(); } document.getElementsByTagName('button')[0].onclick=goTo;
Testez l'exemple, en ne cliquant qu'une seule fois sur le bouton (sous peine de déclencher une exception "attempt to run compile-and-go script on a cleared scope" qui provoquera un "page précédente" infini) et observez le comportement du navigateur.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 function goTo(){ // Sauvegardons le contenu du document courant, avant de le modifier var root=document.getElementsByTagName('html')[0]; document.open('text/html'); document.writeln('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'); document.writeln('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'); // Ajoutons le contenu sauvegardé au document virtuel document.appendChild(root); document.close(); } document.getElementsByTagName('button')[0].onclick=goTo;
Il y a bien un nouveau chargement et le bouton "page précédente" est devenu actif, cqfd!
Un petit effet visuel, afin de mieux voir ce qui se passe réellement.
Revenons sur l'exception déclenchée par Firefox lorsque l'on clique plusieurs fois sur le bouton.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 // Définissons une couleur d'origine pour le bouton document.getElementsByTagName('button')[0].style.color='red'; function goTo(){ var root=document.getElementsByTagName('html')[0],button; document.open('text/html'); document.writeln('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'); document.appendChild(root); // Récupérons notre bouton button=document.getElementsByTagName('button')[0]; // Modifions sa couleur, en fonction de la couleur qu'il avait précédemment button.style.color=button.style.color=='red'?'green':button.style.color=='green'?'blue':'red'; document.close(); } document.getElementsByTagName('button')[0].onclick=goTo;
Il semble, d'après mes tests, que window est remis à neuf au chargement du document virtuel, néanmoins, je soupçonne le navigateur de conserver des références qu'un document qui n'existe plus, nous allons donc les redéfinir :
Voilà, réessayez ce code et vous observerez qu'il est désormais possible de naviguer au sein de documents virtuels avec les boutons "page précédente" et "page suivante".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 document.getElementsByTagName('button')[0].style.color='red'; function goTo(){ // Sauvegardons notre fonction goTo var root=document.getElementsByTagName('html')[0],button,tmp=window.goTo; document.open('text/html'); document.writeln('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'); document.appendChild(root); button=document.getElementsByTagName('button')[0]; button.style.color=button.style.color=='red'?'green':button.style.color=='green'?'blue':'red'; document.close(); // Redéclarons notre fonction goTo window.goTo=tmp; } document.getElementsByTagName('button')[0].onclick=goTo;
Les bémols
Le navigateur semble ne conserver que le dernier état du DOM, impossible donc, actuellement, de baser la navigation d'une application web sur ce système.
Quid des autres navigateurs?
IE 9 :
Amnésie? Il ne semble pas possible de "sauvegarder" l'arbre DOM, pour le reconstituer, après document.open(). IE se rappelle bien du type d'objet (node) mais, par exemple, pas de son tagName.
Google Chrome 14 :
Ne semble pas stocker l'état du DOM et pré-remplit le document avec des noeuds HTML.
####################################################
Je vous invite à me faire part des vos avis, conseils/critiques et vous en remercie d'avance.
Partager