Introduction
Le mot-clé, la catégorie, le tri et la page de Fieldnote peuvent déjà voyager dans une URL. Le contrôleur préparé remplace l'entrée courante après chaque recherche. Les liens directs restent utiles, mais la vue précédente est perdue : un lecteur ne peut pas parcourir plusieurs recherches puis revenir avec Back de manière fiable. Vous distinguerez les nouvelles actions de la restauration pour faire fonctionner l'historique du navigateur.
Cet atelier indépendant prépare les fichiers complets de sélection, de normalisation et d'URL du précédent ; aucune ancienne VM n'est requise. Il suppose le contrat à quatre états de cet atelier et les bases des fonctions, objets, sélections DOM et événements JavaScript. Vous apprendrez pushState, replaceState, popstate et pourquoi le partage exige l'URL plutôt qu'une préférence locale ancienne ou un objet d'historique en mémoire. Il n'y a ni requêtes asynchrones ni routeur de framework. Les 40 minutes sont une estimation de l'auteur.
Utilisez Workspace et Fieldnote. Modifiez seulement /home/labex/project/fieldnote/work/app.js. Préservez selection.js, state.js, url.js, catalog.js, view.js, HTML/CSS, Study indépendant et le service. Le moteur préparé affiche les véritables titre, description, date, heure et lieu de chaque événement sélectionné. Le site reste en anglais. Un lien ne fonctionne que tant que la route publique de cette VM existe ; ce n'est pas une publication sur Internet.
Créer des visites pour les changements validés
Dans cette étape, vous maintiendrez l'initialisation dans une seule entrée et créerez une nouvelle visite lorsqu'un lecteur valide une recherche ou une page différente.
Dans Fieldnote, choisissez Open Study view in a new page. Il s'agit d'une page autonome, pas de l'onglet intégré du produit. Lisez le résultat print & fold, Make, Soonest first, page 2. Choisissez Previous, puis passez Keyword à sound + light, Category à Listen, Sort by à Title A–Z et activez Search. La page revient à 1. Utilisez Back du navigateur, pas Previous du site : cela restaure les anciens mot-clé, catégorie, tri, page et enregistrements correspondants complets. Utilisez Forward pour rétablir la vue récente. C'est l'exemple normal ; il ne termine pas votre travail.
Voici la vue Study indépendante avant les modifications. Son href partagé décrit la même page visible ; il ne complète pas Work.

Fermez Study et choisissez Open Work view in a new page dans l'entrée Fieldnote. Les fichiers possèdent toutes les fonctions de G1, mais le contrôleur préparé remplace encore les entrées. Passez à Workspace. cd fixe le répertoire de ce terminal persistant ; cat lit un fichier sans le modifier :
cd /home/labex/project/fieldnote/work
cat app.js
La fonction actuelle show appelle normalize, crée une URL avec stateURL, remplace l'adresse et demande à draw d'afficher les enregistrements sélectionnés. Ces fonctions proviennent des fichiers préparés state.js, url.js, view.js et selection.js. Vous préserverez cet ordre tout en distinguant deux raisons d'afficher une vue.
history.pushState(null, '', url) ajoute une entrée de même origine et change l'adresse sans demander de nouvelle page. replaceState actualise seulement l'entrée courante. Le premier argument est un état associé facultatif ; nous utilisons null, car tout l'état nécessaire est déjà dans l'URL. La chaîne vide est l'argument de titre inutilisé de l'API. Aucune de ces méthodes ne déclenche elle-même popstate. L'étape suivante traite le parcours effectif de l'historique. La normalisation initiale utilise replace : ouvrir un lien n'ajoute donc pas d'entrée supplémentaire par l'initialisation. La recherche et les boutons utilisent push lorsque l'URL validée diffère ; valider une vue inchangée ne nécessite pas de doublon.
document.querySelector('form') trouve le formulaire préparé. form.elements.q accède au contrôle nommé q. preventDefault bloque la navigation normale du formulaire pour que le contrôleur actualise la vue. Un écouteur s'exécute lorsque l'événement nommé se produit. La syntaxe spread {...current, page: ...} copie les champs actuels, puis remplace la page en conservant les filtres validés. Modifier un contrôle reste un brouillon jusqu'à Search ; les boutons de page utilisent l'état validé.
Enregistrez ce remplacement complet. cat > app.js remplace seulement ce fichier. Le here-document entre guillemets <<'JS' conserve le contenu littéralement ; terminez par JS seul sur une ligne :
cat > app.js <<'JS'
const form = document.querySelector('form');
let current;
function show(raw, mode) {
current = normalize(raw);
const url = stateURL(current);
if (mode === 'push' && url.href !== location.href) {
history.pushState(null, '', url);
} else if (mode === 'replace') {
history.replaceState(null, '', url);
}
draw(current, matches(current));
}
form.addEventListener('submit', event => {
event.preventDefault();
show({q: form.elements.q.value, category: form.elements.category.value,
sort: form.elements.sort.value, page: 1}, 'push');
});
document.querySelector('#previous').addEventListener('click', () =>
show({...current, page: current.page - 1}, 'push'));
document.querySelector('#next').addEventListener('click', () =>
show({...current, page: current.page + 1}, 'push'));
show(readURL(), 'replace');
document.documentElement.dataset.ready = 'true';
JS
&& exige les deux conditions : seule une demande de push avec une adresse différente crée une visite. else if choisit le remplacement à l'initialisation. Les fichiers préparés restent responsables de la normalisation et des quatre clés du cours ; chemin réel du proxy, paramètres supplémentaires et fragment demeurent intacts. Le marqueur final data-ready indique que le contrôleur a terminé son premier dessin ; l'apparition d'un contrôle HTML ne signifie pas que JavaScript a fini.
Revenez à la page de travail autonome et actualisez. Recherchez print & fold, Make, Soonest first, puis choisissez Next. Observez l'édition du plan et l'événement de North room sur la deuxième page. Passez à sound + light, Listen, Title A–Z et envoyez : la page 1 présente les deux événements sonores distincts. Activez Open this view in a new page, puis actualisez cette nouvelle page. Elle doit garder Title A–Z ainsi que les bonnes dates et les bons lieux. Aucune préférence en cache n'est nécessaire : les quatre valeurs validées appartiennent à l'URL, y compris le tri non par défaut. Fermez la nouvelle page et conservez l'originale.
N'attendez pas encore de Back qu'il redessine Work : les nouvelles entrées existent, mais l'écouteur de restauration manque. Lancez Check de cette étape : il contrôle l'ouverture directe, les visites utiles et le remplacement initial, sans exiger l'écouteur suivant. Si une faute JavaScript bloque les mises à jour, utilisez cat app.js, comparez le bloc complet, remplacez-le et actualisez. Enregistrer le fichier corrigé ne vide pas le catalogue et ne nécessite pas de réinitialiser la VM.
Restaurer les vues avec les vrais Back et Forward
Dans cette étape, vous lirez l'URL après une vraie navigation historique et prouverez qu'un autre contexte peut reconstruire la même vue.
Back et Forward changent l'entrée courante. Le navigateur émet popstate lorsqu'il parcourt des entrées applicables du même document ; appeler pushState ne l'émet pas. Écoutez l'événement réel, lisez l'URL courante, normalisez et affichez la vue. Ne faites pas push depuis cet écouteur : vous créeriez une visite supplémentaire au lieu de restaurer l'existante. L'URL fonctionne aussi sans event.state en mémoire, comme lors d'une ouverture directe. N'utilisez pas localStorage comme autorité et ne stockez pas le tri uniquement dans un objet d'historique.
Passez à Workspace. Ajoutez un écouteur au fichier enregistré à l'étape précédente. Contrairement à >, >> ajoute sans supprimer le contenu existant. Exécutez le bloc une fois ; s'il a été ajouté deux fois par erreur, remplacez app.js par le bloc complet précédent, puis ajoutez-le une seule fois.
cat >> app.js <<'JS'
window.addEventListener('popstate', () => show(readURL(), 'replace'));
JS
La fonction fléchée est appelée lors du parcours natif de l'historique. Elle réutilise le chemin show : contrôles, ordre des enregistrements, étiquette de page, limites désactivées et href de partage correspondent tous à la nouvelle URL courante. Un remplacement peut normaliser une entrée équivalente, mais ne doit pas ajouter d'entrée. Le parcours de l'apprenant ne simule aucun événement et n'utilise pas de raccourci de test invisible.
Revenez à votre page de travail d'origine. Pour avoir une entrée initiale claire, ouvrez dans sa barre d'adresses l'URL réelle /work/ avec cette requête, en préservant l'origine et le chemin réels :
?edition=november&q=print%20%26%20fold&category=make&sort=title&page=2#directory-title
C'est l'état A : Title A–Z, page 2, Print & Fold: map edition, puis Print & Fold: tiny type. Lisez leurs heures et lieux. Créez B avec Previous : la page 1 contient les deux Print & Fold simples, puis Print & Fold: colour. Créez C en envoyant sound + light, Listen, Soonest first : page 1 sur 1, deux dates distinctes. Ces actions doivent préserver edition et le fragment. Changer les filtres réinitialise la page.
Utilisez deux fois le vrai Back : C → B → A. À chaque entrée, comparez les contrôles, la page, les titres ordonnés et les date/heure/lieu de chaque événement. Utilisez ensuite deux fois Forward : A → B → C. Répétez encore une fois le cycle Back/Back/Forward/Forward ; la restauration ne doit pas ajouter discrètement de visites ni perdre la chaîne de navigation vers l'avant. Changer d'onglet produit ne parcourt pas l'historique, et Previous du site pagine les résultats au lieu d'effectuer Back.
En C, activez le lien réel Open this view in a new page. La nouvelle page doit présenter le même état validé. Actualisez-la et comparez de nouveau. Le vérificateur ouvre aussi le lien exact dans un contexte propre, sans ancien localStorage ni état d'historique. Dans votre navigateur habituel, la nouvelle page est un onglet distinct, pas une garantie d'isolation de tout le stockage. Aucune API de presse-papiers ni message Copied non testé n'est nécessaire.
Revenez à la page d'origine, retournez à B et actualisez. Elle doit encore montrer B, car l'actualisation lit l'URL. Un mot-clé modifié sans envoi est un brouillon abandonné à l'actualisation. Testez-le explicitement : saisissez unsubmitted draft sans Search, actualisez et observez le retour du mot-clé validé de B. Pour une erreur courante, envoyez prnit, lisez le message valide sans résultat, puis corrigez en print & fold, Make et envoyez. Aucun faux événement de secours ne doit apparaître avec un résultat vide.
Aux largeurs de bureau, d'environ 768 et 390 pixels, comparez cartes complètes, contrôles et partage. Utilisez Tab puis Enter pour lancer une recherche et inspectez le focus visible ; conservez la structure adaptative préparée. Lancez Check. Il exécute votre frontend inchangé dans un environnement isolé, teste les vrais Back/Forward et l'ouverture dans un contexte propre, compare chaque enregistrement visible au catalogue indépendant et préserve l'espace de travail actif. Il ne crée pas de compte et ne publie pas de site durable.
Résumé
Vous avez séparé les nouvelles actions validées de la restauration initiale ou historique. Les vrais Back/Forward, les liens directs et l'actualisation utilisent maintenant le même état piloté par URL et les mêmes enregistrements complets. Le défi transfère ce comportement à un autre catalogue et une autre taille de page sans ajouter de routeur, de pagination backend ni de dépendance à un stockage privé.
