Makina Blog

Le blog Makina-corpus

Modales et pseudo-navigation avec Foundation 6


Manipuler l'historique avec pushState.

Avant-propos

Je nomme pseudo-navigation l'usage de l'API history.pushState() de HTML5 afin de changer dynamiquement l'URL courante mais sans recharger la page courante, l'historique restant cohérent (c'est-à-dire qu'on peut cliquer sur le bouton Précédent du navigateur et on revient à la page précédente).

En général on nomme ce principe "manipulation de l'historique par pushState", je trouve que c'est une dénomination un peu lourde, donc je propose pseudo-navigation, qui me semble adéquat et suffisamment concis.

Note: j'invite humblement tout le monde à soutenir cette dénomination.

Objectif

Notre cas d'utilisation est assez classique :

  • Notre page d'accueil http://monsite.com/ contient des liens vers des trucs et des machins :
  • Quand on clique sur un machin, le contenu correspondant s'affiche dans une fenêtre modale (par un chargement AJAX) et l'URL devient http://monsite.com/machin :
  • Si on ferme la modale ou si on clique sur le bouton Précédent, on revient sur la page d'accueil et l'URL devient http://monsite.com/ :
  • Et si on accède directement à l'URL d'un truc comme http://monsite.com/truc, la modale est ouverte directement :
  • Et là aussi, si on ferme la modale, on revient sur http://monsite.com/.

Foundation 6

Le framework retenu est Foundation 6. Bootstrap et Foundation ont suivi des chemins parallèles, et même si, au grès des versions successives, on a pu trouver l'un supérieur à l'autre, ils sont aujourd'hui relativement équivalents.

La modale de Foundation s'appelle Reveal, et c'est sur elle que nous bâtissons notre solution.

Voici un exemple élémentaire :

<p><a data-open="exampleModal1">Click me for a modal</a></p>

<div class="reveal" id="exampleModal1" data-reveal>
 <h1>Awesome. I Have It.</h1>
</div>

On utilise l'attribut data-open sur le lien pour désigner la modale à ouvrir.

Solution

Chargement dynamique du contenu de la modale

Tout d'abord, nous avons besoin d'un peu de markup pour notre exemple :

<a data-target="/truc" data-open="modal">Truc</a>
<a data-target="/machin" data-open="modal">Machin</a>

<div class="large reveal" id="modal" data-reveal></div>

Notre modale est donc vide initialement, et on a ajouté un attribut data-target, qui n'est pas prévu par Foundation, et qui va nous servir à indiquer l'URL du contenu à charger dans la modale.

Le chargement de notre contenu à l'ouverture de la modale va se faire en 2 temps:

  • sur le click d'un lien, on lit la valeur de data-target, et on la stocke dans un attribut data-url sur l'élément de la modale:
$('a').on('click', function() {
    $('#modal').attr("data-url", $(this).attr('data-target'));
});
  • sur l'événement open.zf.reveal, on charge en AJAX le contenu distant désigné par data-url:
$('#modal').on('open.zf.reveal', function() {
    var url = $(this).attr('data-url');
    $(this).load(getAjaxURL(url));
});

Note: ici, la fonction getAjaxURL() permet d'obtenir l'URL correspondant au contenu de /truc, elle est donc dépendante du backend utilisé.

  • sur l'événement closed.zf.reveal, on vide le contenu de la modal:
$('#modal').on('closed.zf.reveal', function() {
    $(this).html('');
});

Gestion de la pseudo-navigation

Maintenant que notre modale sait afficher un contenu correspondant à une URL, il faut que cette URL soit affichée dans la barre d'adresse et ajoutée dans l'historique de navigation.

Tout d'abord, dans l'événement open.zf.reveal, on va ajouter un pushState:

$('#modal').on('open.zf.reveal', function() {
    var url = $(this).attr('data-url');
    history.pushState({page: url}, null, url); 
    $(this).load(url);
});

Donc maintenant, quand on ouvre la modale, l'URL change et l'historique est alimenté.

Notons qu'on passe un objet en premier paramètre du pushState, contenant un attribut page (ce nom est arbitraire) qui nous servira plus tard.

Ensuite, il faut que la fermeture de la modale revienne à l'URL racine, on ajoute donc aussi un pushState dans closed.zf.reveal :

$('#modal').on('closed.zf.reveal', function() {
    history.pushState({}, null, '/');
    $(this).html('');
});

Et maintenant, il faut aussi gérer le popState, c'est-à-dire restaurer l'état voulu lorsqu'on utilise les boutons Précédent/Suivant du navigateur:

window.addEventListener('popstate', function(e) {
    if(e.state.page) {
        $('#modal').attr("data-url", $(this).attr('data-target'));
        $('#modal').foundation('open');
    } else {
        $('#modal').foundation('close');
    }
});

C'est ici qu'on se sert des données transmises lors du pushState :

  • si state contient notre attribut page, cela signifie que c'est un état correspondant à une modale ouverte et on utilise l'url indiquée par l'attribut page pour ouvrir la modale avec le bon contenu,
  • au contraire, si state n'a pas d'attribut page, il s'agit d'un état correspondant à la page d'accueil, donc on ferme la modale.

Cohérence pour les URL directes

Dernier point, si un utilisateur demande directement la page http://monsite.com/truc (parce qu'on lui a transmis par mail, parce qu'il l'a trouvé dans une recherche Google, etc.), on souhaite que la modale soit automatiquement ouverte avec le contenu truc:

if(location.pathname != "/") {
    $('#modal').attr("data-url", location.pathname);
    $('#modal').foundation('open');
}

Actualités en lien

Image
Capture d'une partie de carte montrant un réseau de voies sur un fond de carte sombre. Au centre, une popup affiche les information de l'un des tronçons du réseau.
28/02/2024

Géné­rer un fichier PMTiles avec Tippe­ca­noe

Exemple de géné­ra­tion et d’af­fi­chage d’un jeu de tuiles vecto­rielles en PMTiles à partir de données publiques.

Voir l'article
Image
Read The Docs
01/02/2024

Publier une documentation VitePress sur Read The Docs

À l'origine, le site de documentation Read The Docs n'acceptait que les documentations Sphinx ou MKDocs. Depuis peu, le site laisse les mains libres pour builder sa documentation avec l'outil de son choix. Voici un exemple avec VitePress.

Voir l'article
Image
Widget
04/04/2023

Créer une application en tant que composant web avec Stencil

Mise en place dans le cadre de Geotrek, cette solution permet de se passer d'une iFrame pour afficher une application dans n'importe quel site.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus