/** * Client-side navigation runtime, served at `/__wrnexus/nav.js`. * * Progressive enhancement over normal links: intercepts same-origin `` * clicks, fetches the target page's HTML, swaps the `#app` container in place, * updates history/title/scroll, ensures any framework runtimes the new page * needs are present, and re-hydrates. * * Before replacing the current page, component lifecycle behaviors are * explicitly disposed. This ensures `unmount` hooks and watcher cleanups run * before the old DOM is removed. * * Programmatic navigation is exposed as: * * window.__wrnexusNavigate(url) */ export const NAV_RUNTIME = String.raw` (function () { if ( !window.history || !history.pushState || !window.fetch || !window.DOMParser ) { return; } if (window.__wrnexusNavInstalled) { return; } window.__wrnexusNavInstalled = true; var APP_ID = "app"; var inFlight = null; var memory = Object.create(null); var keepAlive = Object.create(null); var keepAliveOrder = []; function keepAliveKey(node) { return String(node && node.getAttribute("data-wrn-keepalive") || ""); } function retainKeepAlive(root) { Array.prototype.forEach.call(root.querySelectorAll("[data-wrn-keepalive]"), function (node) { var key = keepAliveKey(node); if (!key) return; if (!keepAlive[key]) keepAliveOrder.push(key); keepAlive[key] = node; if (node.parentNode) node.parentNode.removeChild(node); }); while (keepAliveOrder.length > 32) { var expired = keepAliveOrder.shift(); if (expired && keepAlive[expired]) { dispose(keepAlive[expired]); delete keepAlive[expired]; } } } function restoreKeepAlive(root) { var placeholders = []; if (root.matches && root.matches("[data-wrn-keepalive]")) placeholders.push(root); Array.prototype.forEach.call(root.querySelectorAll("[data-wrn-keepalive]"), function (node) { placeholders.push(node); }); placeholders.forEach(function (placeholder) { var saved = keepAlive[keepAliveKey(placeholder)]; if (saved && placeholder.parentNode) placeholder.parentNode.replaceChild(saved, placeholder); }); } function preservationPolicy(doc) { var meta = doc.querySelector('meta[name="wrnexus-preserve"]'); var out = Object.create(null); String(meta && meta.getAttribute("content") || "").split(",").forEach(function (name) { if (name) out[name] = true; }); return out; } function syncPreservationPolicy(nextDocument) { var selector = 'meta[name="wrnexus-preserve"]'; var current = document.querySelector(selector); var next = nextDocument.querySelector(selector); if (!next) { if (current) current.remove(); return; } if (!current) { current = document.createElement("meta"); current.setAttribute("name", "wrnexus-preserve"); document.head.appendChild(current); } current.setAttribute("content", next.getAttribute("content") || ""); } function stateKey(url) { try { var parsed = new URL(url, location.href); return "wrnexus:navigation:" + parsed.pathname + parsed.search; } catch (_) { return "wrnexus:navigation:" + String(url); } } function safeField(field) { var type = String(field.type || "").toLowerCase(); var name = String(field.name || field.id || "").toLowerCase(); return type !== "password" && type !== "file" && type !== "hidden" && !field.hasAttribute("data-no-preserve") && !/(?:csrf|token|secret|password|credential)/.test(name); } function capturePage(url) { var policy = preservationPolicy(document); var state = { fields: Object.create(null), elements: Object.create(null) }; if (policy.scroll) state.scroll = [window.scrollX || 0, window.scrollY || 0]; if (policy.forms || policy.filters || policy.pagination || policy.workflow) { Array.prototype.forEach.call(document.querySelectorAll("#app input,#app select,#app textarea"), function (field, index) { if (!safeField(field)) return; var key = field.name || field.id || String(index); state.fields[key] = { value: field.value, checked: !!field.checked, selectedIndex: field.selectedIndex }; }); } if (policy.tabs || policy.expanded || policy.component) { Array.prototype.forEach.call(document.querySelectorAll("#app [data-wrn-preserve]"), function (node, index) { var key = node.getAttribute("data-wrn-preserve") || node.id || String(index); state.elements[key] = { selected: node.getAttribute("aria-selected"), expanded: node.getAttribute("aria-expanded"), value: "value" in node ? node.value : null, }; }); } memory[stateKey(url)] = state; try { sessionStorage.setItem(stateKey(url), JSON.stringify(state)); } catch (_) {} } function restorePage(url, isPop) { var policy = preservationPolicy(document); var state = memory[stateKey(url)]; if (!state) { try { state = JSON.parse(sessionStorage.getItem(stateKey(url)) || "null"); } catch (_) {} } if (state && (policy.forms || policy.filters || policy.pagination || policy.workflow)) { Array.prototype.forEach.call(document.querySelectorAll("#app input,#app select,#app textarea"), function (field, index) { if (!safeField(field)) return; var saved = state.fields && state.fields[field.name || field.id || String(index)]; if (!saved) return; if (field.type === "checkbox" || field.type === "radio") field.checked = !!saved.checked; else field.value = saved.value; if (field.tagName === "SELECT") field.selectedIndex = saved.selectedIndex; field.dispatchEvent(new Event("input", { bubbles: true })); }); } if (state && (policy.tabs || policy.expanded || policy.component)) { Array.prototype.forEach.call(document.querySelectorAll("#app [data-wrn-preserve]"), function (node, index) { var key = node.getAttribute("data-wrn-preserve") || node.id || String(index); var saved = state.elements && state.elements[key]; if (!saved) return; if (saved.selected != null) node.setAttribute("aria-selected", saved.selected); if (saved.expanded != null) node.setAttribute("aria-expanded", saved.expanded); if (saved.value != null && "value" in node) node.value = saved.value; }); } if (state && policy.scroll && state.scroll) window.scrollTo(state.scroll[0], state.scroll[1]); else if (!isPop) window.scrollTo(0, 0); } function pathOf(src) { return String(src).split("?")[0]; } function isLocalLink(anchor) { if ( !anchor || anchor.hasAttribute("download") || anchor.hasAttribute("data-no-nav") ) { return false; } if (anchor.target && anchor.target !== "_self") { return false; } if (anchor.origin !== location.origin) { return false; } var href = anchor.getAttribute("href"); if (!href || href.charAt(0) === "#") { return false; } var rel = ( anchor.getAttribute("rel") || "" ).toLowerCase(); return rel.indexOf("external") === -1; } function currentDocumentNonce() { var node = document.querySelector("script[nonce],style[nonce]"); if (!node) return ""; return node.nonce || node.getAttribute("nonce") || ""; } function syncWrnStyles(nextDocument) { var current = Array.prototype.slice.call( document.querySelectorAll("style[data-wrnexus-style-id]"), ); var next = Array.prototype.slice.call( nextDocument.querySelectorAll("style[data-wrnexus-style-id]"), ); var currentById = Object.create(null); var nextIds = Object.create(null); var nonce = currentDocumentNonce(); current.forEach(function (style) { var id = style.getAttribute("data-wrnexus-style-id"); if (id) currentById[id] = style; }); next.forEach(function (nextStyle) { var id = nextStyle.getAttribute("data-wrnexus-style-id"); if (!id) return; nextIds[id] = true; var currentStyle = currentById[id]; if (!currentStyle) { currentStyle = document.createElement("style"); currentStyle.setAttribute("data-wrnexus-style-id", id); } ["data-wrnexus-style-owner", "data-wrnexus-style-kind"].forEach(function (name) { var value = nextStyle.getAttribute(name); if (value == null) currentStyle.removeAttribute(name); else currentStyle.setAttribute(name, value); }); if (nonce) currentStyle.setAttribute("nonce", nonce); if (currentStyle.textContent !== nextStyle.textContent) { currentStyle.textContent = nextStyle.textContent; } document.head.appendChild(currentStyle); }); current.forEach(function (style) { var id = style.getAttribute("data-wrnexus-style-id"); if (id && !nextIds[id]) style.remove(); }); } function loadedScriptPaths() { var loaded = {}; document .querySelectorAll("script[src]") .forEach(function (script) { var src = script.getAttribute("src"); if (src) { loaded[pathOf(src)] = true; } }); return loaded; } function runtimeIds(root) { var ids = {}; if (!root || !root.querySelectorAll) return ids; var nodes = []; if (root.matches && root.matches("[data-wrnexus-runtime]")) nodes.push(root); root.querySelectorAll("[data-wrnexus-runtime]").forEach(function (node) { nodes.push(node); }); nodes.forEach(function (node) { String(node.getAttribute("data-wrnexus-runtime") || "") .split(/[\s,]+/) .forEach(function (id) { if (id) ids[id] = true; }); }); return ids; } function packageRuntimeRegistry() { return window.__wrnexusRuntimes || {}; } function mountPackageRuntimes(root) { var ids = runtimeIds(root); var registry = packageRuntimeRegistry(); Object.keys(ids).forEach(function (id) { var runtime = registry[id]; if (!runtime || typeof runtime.mount !== "function") return; try { runtime.mount(root); } catch (error) { console.error("[wrnexus] failed to mount runtime", id, error); } }); } function unmountPackageRuntimes(root) { var ids = runtimeIds(root); var registry = packageRuntimeRegistry(); Object.keys(ids).forEach(function (id) { var runtime = registry[id]; if (!runtime || typeof runtime.unmount !== "function") return; try { runtime.unmount(root); } catch (error) { console.error("[wrnexus] failed to unmount runtime", id, error); } }); } /** * Append framework runtimes declared by the incoming document but not * currently loaded. */ function ensureScripts(doc) { var loaded = loadedScriptPaths(); doc .querySelectorAll("script[src]") .forEach(function (script) { var src = script.getAttribute("src"); if (!src || loaded[pathOf(src)]) { return; } loaded[pathOf(src)] = true; var element = document.createElement("script"); Array.prototype.forEach.call( script.attributes, function (attribute) { if (attribute.name === "src") return; element.setAttribute( attribute.name, attribute.value, ); }, ); element.src = src; if (!script.hasAttribute("async")) { element.async = false; } element.addEventListener("load", function () { try { mountPackageRuntimes(document); window.dispatchEvent( new CustomEvent( "wrnexus:runtime-loaded", { detail: { src: src } }, ), ); } catch (_) {} }); element.addEventListener("error", function () { console.error( "[wrnexus] failed to load client runtime", src, ); }); document.body.appendChild(element); }); } /** * Run explicit component cleanup before removing the existing page. * * The reactive runtime also observes removed DOM nodes, but explicit * disposal here guarantees that unmount hooks run before replacement. */ function dispose(root) { unmountPackageRuntimes(root); try { var stores = window.__wrnexusStoreContainer; if (stores && typeof stores.disposePageStores === "function") { Promise.resolve(stores.disposePageStores()).catch(function (error) { console.error("[wrnexus] failed to dispose page stores", error); }); } } catch (error) { console.error("[wrnexus] failed to access page stores", error); } try { if ( typeof window.__wrnexusDisposeBehaviors === "function" ) { window.__wrnexusDisposeBehaviors(root); } } catch (error) { console.error( "[wrnexus] failed to dispose page behaviors", error, ); } } /** * Re-hydrate already-loaded runtimes against newly inserted DOM. * * All framework hydration functions must remain idempotent. */ function rehydrate(root) { mountPackageRuntimes(root); try { if ( typeof window.__wrnexusHydrateScopes === "function" ) { window.__wrnexusHydrateScopes(root); } } catch (error) { console.error( "[wrnexus] failed to hydrate reactive scopes", error, ); } try { if ( typeof window.__wrnexusHydrateCsrFetches === "function" ) { window.__wrnexusHydrateCsrFetches(root); } } catch (error) { console.error( "[wrnexus] failed to hydrate CSR bindings", error, ); } try { if ( window.__wrnValidate && typeof window.__wrnValidate.init === "function" ) { window.__wrnValidate.init(document); } } catch (error) { console.error( "[wrnexus] failed to hydrate validation", error, ); } try { if ( window.wrnTheme && typeof window.wrnTheme.bind === "function" ) { window.wrnTheme.bind(document); } } catch (error) { console.error( "[wrnexus] failed to hydrate theme bindings", error, ); } } function dispatchNavigationEvent(url) { try { window.dispatchEvent( new CustomEvent("wrnexus:navigated", { detail: { url: url, }, }), ); } catch (_) { // CustomEvent may not be available in very old browsers. } } function hardNavigate(url) { location.href = url; } function render(html, url, isPop) { var doc; try { doc = new DOMParser().parseFromString( html, "text/html", ); } catch (_) { hardNavigate(url); return; } capturePage(location.href); var incomingApp = doc.getElementById(APP_ID); var currentApp = document.getElementById(APP_ID); if (!incomingApp || !currentApp) { hardNavigate(url); return; } if (doc.title) { document.title = doc.title; } syncPreservationPolicy(doc); syncWrnStyles(doc); var importedNodes = []; for ( var index = 0; index < incomingApp.childNodes.length; index++ ) { importedNodes.push( document.importNode( incomingApp.childNodes[index], true, ), ); } /* * Run unmount hooks and watcher cleanup while the current DOM is still * connected. This is important for components that remove window or * document listeners during lifecycle.unmount. */ retainKeepAlive(currentApp); dispose(currentApp); try { /* * Avoid innerHTML so navigation works with strict Trusted Types and CSP * configurations. */ currentApp.replaceChildren.apply( currentApp, importedNodes, ); restoreKeepAlive(currentApp); } catch (_) { hardNavigate(url); return; } /* * Load any runtime required only by the incoming page. Fresh scripts * initialise themselves when loaded. */ ensureScripts(doc); /* * Hydrate runtimes that are already available. Hydration is scoped to * #app instead of the entire document for less DOM traversal. */ rehydrate(currentApp); if (!isPop) { history.pushState( { wrnexusNav: true, }, "", url, ); } restorePage(url, isPop); dispatchNavigationEvent(url); } function navigate(url, isPop) { var token = {}; inFlight = token; window.dispatchEvent(new CustomEvent("wrnexus:navigation-start", { detail: { url: url } })); var pending = prefetched.get(url) || requestDocument(url, false); prefetched.delete(url); pending .then(function (result) { if (inFlight !== token) return null; if (result.redirectedUrl) url = result.redirectedUrl; if (result.contentType.indexOf("text/html") === -1) { hardNavigate(url); return null; } render(result.text, url, isPop); return null; }) .catch(function () { if (inFlight === token) hardNavigate(url); }); } var prefetched = new Map(); function requestDocument(url, isPrefetch) { return fetch(url, { headers: { "x-wrnexus-nav": "1", ...(isPrefetch ? { "x-wrnexus-prefetch": "1" } : {}), accept: "text/html", }, credentials: "same-origin", }).then(function (response) { var contentType = response.headers.get("content-type") || ""; return response.text().then(function (text) { return { text: text, contentType: contentType, redirectedUrl: response.redirected && response.url ? response.url : "", }; }); }); } function prefetch(anchor) { if (!isLocalLink(anchor) || anchor.hasAttribute("data-no-prefetch")) return; var url = anchor.href; if (url === location.href || prefetched.has(url)) return; prefetched.set(url, requestDocument(url, true)); while (prefetched.size > 20) prefetched.delete(prefetched.keys().next().value); } // Prefetch only on explicit pointer intent. Delegated pointerover fires when // scrolling moves links underneath a stationary pointer, which can otherwise // download every link on a long index page. document.addEventListener("pointerdown", function (event) { var anchor = event.target && event.target.closest ? event.target.closest("a") : null; prefetch(anchor); }, { passive: true }); document.addEventListener("focusin", function (event) { var anchor = event.target && event.target.closest ? event.target.closest("a") : null; prefetch(anchor); }); document.addEventListener( "click", function (event) { if ( event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ) { return; } var anchor = event.target && event.target.closest ? event.target.closest("a") : null; if (!isLocalLink(anchor)) { return; } if (anchor.href === location.href) { event.preventDefault(); return; } event.preventDefault(); navigate(anchor.href, false); }, false, ); window.addEventListener( "popstate", function () { navigate(location.href, true); }, ); /** * Programmatic navigation for forms, actions and application code. */ window.__wrnexusNavigate = function (url) { navigate( new URL(url, location.href).href, false, ); }; /** Re-render the current route without adding a duplicate history entry. */ window.__wrnexusRefresh = function () { navigate(location.href, true); }; })(); `.trim();