Improve page swap fallback

This commit is contained in:
slhx agent
2026-05-10 22:36:51 +02:00
parent 3e0ed95490
commit 9e0342951c
2 changed files with 17 additions and 7 deletions
+15 -7
View File
@@ -144,7 +144,10 @@
async function navigateUrl(href, root, mode = "replace") { async function navigateUrl(href, root, mode = "replace") {
const response = await fetch(href, { headers: { "X-SLHX-Partial": "1", "Accept": "text/html" } }); const response = await fetch(href, { headers: { "X-SLHX-Partial": "1", "Accept": "text/html" } });
await applyResponse(response, root); if (!await applyResponse(response, root) && mode !== "none") {
location.href = href;
return;
}
if (mode === "push") history.pushState({ slhx: true }, "", href); if (mode === "push") history.pushState({ slhx: true }, "", href);
else if (mode === "replace") history.replaceState({ slhx: true }, "", href); else if (mode === "replace") history.replaceState({ slhx: true }, "", href);
} }
@@ -152,15 +155,19 @@
async function applyResponse(response, root) { async function applyResponse(response, root) {
if (response.redirected) { if (response.redirected) {
location.href = response.url; location.href = response.url;
return; return false;
} }
if (!compatibleFingerprint(response, root)) { if (!compatibleFingerprint(response, root)) {
location.reload(); location.reload();
return; return false;
} }
const type = response.headers.get("content-type") || ""; const type = response.headers.get("content-type") || "";
if (type.includes("text/html")) applyHtml(await response.text(), root, response.headers.get("x-slhx-title")); if (type.includes("text/html")) return applyHtml(await response.text(), root, response.headers.get("x-slhx-title"));
else if (type.includes("application/slhx")) applyBatch(await response.arrayBuffer(), root); if (type.includes("application/slhx")) {
applyBatch(await response.arrayBuffer(), root);
return true;
}
return false;
} }
function compatibleFingerprint(response, root) { function compatibleFingerprint(response, root) {
@@ -335,12 +342,13 @@
const doc = new DOMParser().parseFromString(html, "text/html"); const doc = new DOMParser().parseFromString(html, "text/html");
const template = doc.querySelector("template[data-slhx]"); const template = doc.querySelector("template[data-slhx]");
if (!replaceSlot(scope, doc, "content", template ? template.innerHTML : html)) { if (!replaceSlot(scope, doc, "content", template ? template.innerHTML : html)) {
location.reload(); emit(scope, "slhx:missing-content-slot", null);
return; return false;
} }
replaceSlot(scope, doc, "nav"); replaceSlot(scope, doc, "nav");
const nextTitle = title || (doc.querySelector("title") && doc.querySelector("title").textContent); const nextTitle = title || (doc.querySelector("title") && doc.querySelector("title").textContent);
if (nextTitle) document.title = nextTitle; if (nextTitle) document.title = nextTitle;
return true;
} }
function replaceSlot(scope, doc, name, fallback) { function replaceSlot(scope, doc, name, fallback) {
+2
View File
@@ -36,6 +36,8 @@ fn runtime_exposes_page_swap_hooks() {
assert!(source.contains("popstate")); assert!(source.contains("popstate"));
assert!(source.contains("x-slhx-title")); assert!(source.contains("x-slhx-title"));
assert!(source.contains("x-slhx-fingerprint")); assert!(source.contains("x-slhx-fingerprint"));
assert!(source.contains("slhx:missing-content-slot"));
assert!(source.contains("location.href = href"));
} }
#[test] #[test]