feat(runtime): add URL-state GET navigation
This commit is contained in:
+39
-4
@@ -190,6 +190,36 @@
|
||||
return url.href;
|
||||
}
|
||||
|
||||
function pageRequestUrl(form, source) {
|
||||
const url = new URL((form && form.action) || location.href, location.href);
|
||||
url.search = urlEncoded(successfulFormData(form, source)).toString();
|
||||
return url.href;
|
||||
}
|
||||
|
||||
function successfulFormData(form, source) {
|
||||
try {
|
||||
return source && source !== form ? new FormData(form, source) : new FormData(form);
|
||||
} catch (_) {
|
||||
return new FormData(form);
|
||||
}
|
||||
}
|
||||
|
||||
function pageFormHistoryMode(source, form) {
|
||||
return historyMode(source, null) || historyMode(form, null) || historyMode(boostRoot(form), null);
|
||||
}
|
||||
|
||||
function boostRoot(el) {
|
||||
return el && closestInRoot(el.parentElement, rootOf(el), (node) => node.hasAttribute("data-hemx-boost"));
|
||||
}
|
||||
|
||||
function historyMode(el, fallback) {
|
||||
if (!el) return fallback;
|
||||
const value = el.getAttribute("data-hemx-history") || el.getAttribute("data-hemx-nav") || "";
|
||||
if (value === "push" || value === "replace" || value === "none") return value;
|
||||
if (el.hasAttribute("data-hemx-history") || el.hasAttribute("data-hemx-nav")) return fallback || "push";
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function httpError(response) {
|
||||
const error = new Error(`HTTP ${response.status}`);
|
||||
error.status = response.status;
|
||||
@@ -233,6 +263,7 @@
|
||||
let finish;
|
||||
const done = new Promise((resolve) => { finish = resolve; });
|
||||
const method = String((form && form.getAttribute("method")) || "POST").toUpperCase();
|
||||
const mode = method === "GET" && form && pageFormHistoryMode(source, form);
|
||||
const body = method === "GET" || method === "HEAD" ? undefined : requestBody(data, multipart);
|
||||
const headers = { "X-HEMX-Partial": "1", "Accept": "application/hemx, text/html" };
|
||||
if (body instanceof URLSearchParams) headers["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8";
|
||||
@@ -240,6 +271,10 @@
|
||||
showError(target, null);
|
||||
showPending(target, true);
|
||||
try {
|
||||
if (mode) {
|
||||
await navigateUrl(pageRequestUrl(form, source), rootOf(form) || rootOf(el), mode);
|
||||
return;
|
||||
}
|
||||
const response = await fetch(requestUrl(form, data, method), {
|
||||
method,
|
||||
body,
|
||||
@@ -629,7 +664,7 @@
|
||||
);
|
||||
if (name === "click" && nav && sameOriginNav(event, nav)) {
|
||||
event.preventDefault();
|
||||
navigate(nav);
|
||||
navigate(nav, historyMode(nav, "push"));
|
||||
return;
|
||||
}
|
||||
if (name === "click") {
|
||||
@@ -646,7 +681,7 @@
|
||||
(el.tagName === "INPUT" && el.getAttribute("type") === "submit")
|
||||
);
|
||||
const form = formOwner(submitter);
|
||||
if (form && root.contains(form) && formHandleId(form)) {
|
||||
if (form && root.contains(form) && (formHandleId(form) || pageFormHistoryMode(submitter, form))) {
|
||||
if (form.reportValidity && !form.reportValidity()) return;
|
||||
event.preventDefault();
|
||||
schedule(form, "submit", submitter);
|
||||
@@ -655,9 +690,9 @@
|
||||
}
|
||||
let el = closestInRoot(event.target, root, (node) =>
|
||||
node.hasAttribute(HID) ||
|
||||
(node.tagName === "FORM" && closestInRoot(node.parentElement, root, (parent) => parent.hasAttribute("data-hemx-boost")))
|
||||
(node.tagName === "FORM" && (pageFormHistoryMode(event.submitter || node, node) || boostRoot(node)))
|
||||
);
|
||||
if (name === "submit" && !el && event.target && event.target.tagName === "FORM" && formHandleId(event.target)) el = event.target;
|
||||
if (name === "submit" && !el && event.target && event.target.tagName === "FORM" && (formHandleId(event.target) || pageFormHistoryMode(event.submitter || event.target, event.target))) el = event.target;
|
||||
if (!el || defaultEvent(el) !== name) return;
|
||||
event.preventDefault();
|
||||
schedule(el, name, event.submitter || el);
|
||||
|
||||
Reference in New Issue
Block a user