fix: inspector reload hoepfully?
This commit is contained in:
parent
ffba038b35
commit
e9f235505f
1 changed files with 93 additions and 3 deletions
|
|
@ -97,9 +97,99 @@
|
|||
}
|
||||
}
|
||||
|
||||
async function replaceBody(html) {
|
||||
const ui = [...document.body.querySelectorAll(":scope > [data-bliss-ui]")];
|
||||
function nodeKey(node) {
|
||||
if (node.nodeType !== Node.ELEMENT_NODE) return null;
|
||||
if (node.id) return `id:${node.id}`;
|
||||
if (node.dataset.messageId) return `message:${node.dataset.messageId}`;
|
||||
if (node.dataset.blissRouteId) {
|
||||
return `route:${node.dataset.blissRouteId}:${node.dataset.blissRequestUrl || ""}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function sameNodeType(left, right) {
|
||||
return (
|
||||
left.nodeType === right.nodeType &&
|
||||
(left.nodeType !== Node.ELEMENT_NODE || left.tagName === right.tagName)
|
||||
);
|
||||
}
|
||||
|
||||
function syncAttributes(element, next) {
|
||||
for (const attribute of [...element.attributes]) {
|
||||
if (!next.hasAttribute(attribute.name)) element.removeAttribute(attribute.name);
|
||||
}
|
||||
for (const attribute of [...next.attributes]) {
|
||||
if (element.getAttribute(attribute.name) !== attribute.value) {
|
||||
element.setAttribute(attribute.name, attribute.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Live regions can contain data that arrived after the template was first
|
||||
// rendered (a WebSocket chat message is the important case). Those nodes
|
||||
// are not present in the saved render context, so retain them during a
|
||||
// template patch instead of deleting them with the old tree.
|
||||
function keepLiveNode(node) {
|
||||
return (
|
||||
node.nodeType === Node.ELEMENT_NODE &&
|
||||
(node.matches("[data-bliss-ui]") ||
|
||||
node.hasAttribute("data-message-id") ||
|
||||
node.hasAttribute("data-bliss-route-id"))
|
||||
);
|
||||
}
|
||||
|
||||
function morphNode(current, next) {
|
||||
if (!sameNodeType(current, next)) {
|
||||
current.replaceWith(next.cloneNode(true));
|
||||
return;
|
||||
}
|
||||
if (current.nodeType !== Node.ELEMENT_NODE) {
|
||||
if (current.nodeValue !== next.nodeValue) current.nodeValue = next.nodeValue;
|
||||
return;
|
||||
}
|
||||
|
||||
syncAttributes(current, next);
|
||||
const currentChildren = [...current.childNodes];
|
||||
const keyed = new Map();
|
||||
for (const child of currentChildren) {
|
||||
const key = nodeKey(child);
|
||||
if (key && !keyed.has(key)) keyed.set(key, child);
|
||||
}
|
||||
|
||||
const used = new Set();
|
||||
let cursor = current.firstChild;
|
||||
for (const nextChild of [...next.childNodes]) {
|
||||
const key = nodeKey(nextChild);
|
||||
let child = key ? keyed.get(key) : null;
|
||||
if (child && used.has(child)) child = null;
|
||||
if (!child) {
|
||||
child = currentChildren.find(
|
||||
(candidate) =>
|
||||
!used.has(candidate) &&
|
||||
!nodeKey(candidate) &&
|
||||
sameNodeType(candidate, nextChild),
|
||||
);
|
||||
}
|
||||
if (!child) child = nextChild.cloneNode(false);
|
||||
if (child !== cursor) current.insertBefore(child, cursor);
|
||||
used.add(child);
|
||||
morphNode(child, nextChild);
|
||||
cursor = child.nextSibling;
|
||||
}
|
||||
|
||||
for (const child of currentChildren) {
|
||||
if (!used.has(child) && child.isConnected && !keepLiveNode(child)) child.remove();
|
||||
}
|
||||
}
|
||||
|
||||
async function replaceBody(html, { morph = false } = {}) {
|
||||
const next = new DOMParser().parseFromString(html, "text/html");
|
||||
if (morph) {
|
||||
morphNode(document.body, next.body);
|
||||
htmx.process(document.body);
|
||||
return;
|
||||
}
|
||||
const ui = [...document.body.querySelectorAll(":scope > [data-bliss-ui]")];
|
||||
for (const attribute of [...document.body.attributes]) {
|
||||
document.body.removeAttribute(attribute.name);
|
||||
}
|
||||
|
|
@ -154,7 +244,7 @@
|
|||
throw new Error(`Template ${templateId} returned ${response.status}`);
|
||||
}
|
||||
const html = await response.text();
|
||||
if (element === document.body) return replaceBody(html);
|
||||
if (element === document.body) return replaceBody(html, { morph: true });
|
||||
const fragment = document.createElement("template");
|
||||
fragment.innerHTML = html;
|
||||
// A template may legally have several top-level nodes. They share one
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue