(() => { const main = document.getElementById("app-main"); const links = Array.from(document.querySelectorAll("[data-route]")); function normalizeRoute(value) { const raw = (value ?? "").toString().trim().toLowerCase(); if (!raw || raw === "/" || raw === "home" || raw === "index" || raw === "accueil") { return "home"; } return raw.replace(/^\/+|\/+$/g, "") || "home"; } function routeFromLocation() { const params = new URLSearchParams(window.location.search); if (params.has("p")) { return normalizeRoute(params.get("p")); } const rawSearch = window.location.search.replace(/^\?/, ""); if (rawSearch.startsWith("p/")) { return normalizeRoute(rawSearch.slice(2)); } if (rawSearch.startsWith("p=")) { return normalizeRoute(rawSearch.slice(2)); } const path = window.location.pathname.replace(/^\/+|\/+$/g, ""); if (path) { const parts = path.split("/"); if (parts[0] === "p" && parts[1]) { return normalizeRoute(parts.slice(1).join("/")); } return normalizeRoute(parts[0]); } return "home"; } function setActiveRoute(route) { links.forEach((link) => { const isActive = link.dataset.route === route; if (isActive) { link.setAttribute("aria-current", "page"); } else { link.removeAttribute("aria-current"); } }); } function setCanonicalUrl(route, replace = false) { const url = route === "home" ? "/" : `/?p/${route}/`; if (replace) { history.replaceState({ route }, "", url); return; } history.pushState({ route }, "", url); } function routeToSource(route) { return route === "home" ? null : `p/${route}/index.html`; } function routeToTitle(route) { if (route === "home") { return "Fws Web"; } const label = route .split("/") .filter(Boolean) .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)) .join(" / "); return `Fws Web - ${label}`; } async function loadRoute(route) { if (route === "home") { main.innerHTML = `

Navigation one-page

Le site change de contenu sans changer de page.

Les liens du menu modifient l'URL, puis le script charge le HTML correspondant depuis p/... et l'injecte dans le main.

Aller vers DL Rester sur l'accueil

Header commun

Le bandeau du haut reste identique sur chaque vue.

Footer commun

Le pied de page reste fixe, quelle que soit la section chargée.

Injection réelle

Chaque route peut venir d'un vrai fichier index.html dans p/.

`; return; } const source = routeToSource(route); if (!source) { throw new Error(`Route inconnue: ${route}`); } const response = await fetch(source, { cache: "no-store" }); if (!response.ok) { throw new Error(`Impossible de charger ${source} (${response.status})`); } const html = await response.text(); const parsed = new DOMParser().parseFromString(html, "text/html"); const injected = parsed.querySelector("[data-page-content]") ?? parsed.body; main.innerHTML = injected.innerHTML.trim(); } function render(route, { replaceHistory = false } = {}) { const safeRoute = route || "home"; loadRoute(safeRoute) .then(() => { setActiveRoute(safeRoute); setCanonicalUrl(safeRoute, replaceHistory); document.title = routeToTitle(safeRoute); window.scrollTo({ top: 0, behavior: "smooth" }); }) .catch((error) => { main.innerHTML = `

Erreur de chargement

${error.message}

`; setActiveRoute("home"); }); } document.addEventListener("click", (event) => { const link = event.target.closest("[data-route]"); if (!link) { return; } const route = normalizeRoute(link.dataset.route); if (!route) { return; } event.preventDefault(); render(route); }); window.addEventListener("popstate", () => { render(routeFromLocation(), { replaceHistory: true }); }); render(routeFromLocation(), { replaceHistory: true }); })();