Problématique
Pour un projet j’utilise énormément GWT, qui me permet de coder en Java [1] et laisser le compilateur GWT se débrouiller pour faire du JavaScript ensuite.
Dans ce projet, l’utilisateur peut naviguer entre différents onglets de données. Ces onglets ne rafraîchissent pas la page en elle-même, se contentant de faire une requête au serveur pour chercher les données à afficher.
Mon objectif était de permettre d’avoir une URL directe sur chaque onglet pour utiliser des marque-pages, et également d’autoriser l’utilisation des flèches de navigation « suivant » et « précédent » du navigateur pour revenir en arrière ou en avant dans ces pages virtuelles.
Implémentation
Après expérimentation, cette fonctionnalité est assez simple à obtenir à travers la classe History de GWT.
Tout se passe à travers une ancre HTML, qui va contenir l’état de l’application sous forme de clés et valeurs associées.
Cette ancre apparaît dans la barre de navigation, et l’utilisateur peut donc mettre un marque-page ou la copier. À l’ouverture de l’application, elle sera utilisée pour récupérer l’onglet à afficher.
Mon implémentation est un peu plus large qu’une simple page, j’ai prévu de pouvoir stocker d’autres informations pour le futur. Pour des raisons obscures, j’ai utilisé le mot « history » dans les différents éléments. Les clés et valeurs sont stockées sous la forme #cle1:valeur1/cle2:valeur2.
La première brique est de récupérer l’ensemble des informations contenues dans l’ancre.
- final protected HashMap<String, String> _historySet = new HashMap<String, String>();
- protected void readHistory() {
- _historySet.clear();
- if (History.getToken().isEmpty())
- return;
- _historySet.put(split[0], split[1]);
- }
- }
La deuxième brique est de pouvoir stocker ces éléments.
- protected void storeHistory() {
- SortedSet<String> keys = new TreeSet<String>(_historySet.keySet());
- StringBuilder item = new StringBuilder();
- item.append(sep).append(key).append(":").append(_historySet.get(key));
- sep = "/";
- }
- History.newItem(item.toString());
- }
Je trie les clés pour assurer l’unicité des URLs quelque soit l’ordre dans lequel le code ajoute les valeurs.
Ensuite, il faut réagir aux opérations de l’utilisateur sur les flèches suivant et précédent.
- function void something() {
- (...)
- History.addValueChangeHandler(new ValueChangeHandler<String>() {
- public void onValueChange(ValueChangeEvent<String> event) {
- readHistory();
- adjustState();
- }
- });
- (...)
- }
Puis il faut créer une fonction adjustState() qui utilisera les informations contenues dans _historySet pour ajuster l’affichage ou l’état de l’application.
Enfin, la dernière brique à rajouter, après chargement des données de base dont l’application peut avoir besoin [2], est une simulation d’un changement dans l’historique.
- (...)
- History.fireCurrentHistoryState();
- (...)
Ce qui appellera le ValueChangeHandler ajouté précédemment.
Bien évidemment, il faut dans son code mettre à jour régulièrement _historySet et appeler storeHistory() pour refléter l’état dans l’URL affichée à l’utilisateur et lui permettre de mettre un marque-page.
Conclusion
Il s’agit d’une fonction bien plus simple à implémenter que j’avais espéré, et surtout plus agréable à gérer que les paramètres sous forme de ?cle=valeur&cle2=valeur2.
De plus, la gestion de la navigation par les flèches « suivant » et « précédent » permet de ne pas déstabiliser l’utilisateur pour qui cliquer quelque part doit se refléter dans l’historique.