fix: retain child provenance in htmx page swaps
This commit is contained in:
parent
e9f235505f
commit
c8e50cb629
3 changed files with 116 additions and 3 deletions
29
index.js
29
index.js
|
|
@ -441,6 +441,28 @@ function decorateFragment(html, { headInjection, source } = {}) {
|
|||
);
|
||||
}
|
||||
|
||||
// `res.render()` commonly returns a complete document even when it is serving
|
||||
// an HTMX request. HTMX swaps that document's body into the current page, so
|
||||
// preserve the template provenance from its body on every swapped root before
|
||||
// reducing it to a fragment. Without this, templates from an hx-get child
|
||||
// appear to belong to the outer page; saving `message-raw` in /sheepgpt then
|
||||
// incorrectly refreshes /sheepgpt instead of the embedded /chat instance.
|
||||
function fragmentFromPage(html) {
|
||||
const $ = cheerio.load(html);
|
||||
const body = $("body");
|
||||
const templateAttrs = Object.fromEntries(
|
||||
Object.entries(body[0]?.attribs || {}).filter(([name]) =>
|
||||
name.startsWith("data-bliss-template"),
|
||||
),
|
||||
);
|
||||
if (Object.keys(templateAttrs).length) {
|
||||
for (const child of body.children().toArray()) {
|
||||
Object.assign(child.attribs, templateAttrs);
|
||||
}
|
||||
}
|
||||
return body.html();
|
||||
}
|
||||
|
||||
// Single entry point for turning rendered HTML into a response body. A full
|
||||
// document (or any non-htmx request) becomes a decorated page; an htmx partial
|
||||
// carrying provenance becomes a decorated fragment; anything else passes through.
|
||||
|
|
@ -448,11 +470,12 @@ function decorate(html, { headInjection, source, fragment } = {}) {
|
|||
const lower = html.toLowerCase();
|
||||
const isFullDoc =
|
||||
lower.startsWith("<html>") || lower.startsWith("<!doctype");
|
||||
if (isFullDoc || !fragment) {
|
||||
if (!fragment) {
|
||||
return decoratePage(html, { headInjection, source });
|
||||
}
|
||||
if (source) return decorateFragment(html, { headInjection, source });
|
||||
return html;
|
||||
const fragmentHtml = isFullDoc ? fragmentFromPage(html) : html;
|
||||
if (source) return decorateFragment(fragmentHtml, { headInjection, source });
|
||||
return fragmentHtml;
|
||||
}
|
||||
|
||||
// One prefix-bound route() helper per structure, shared by every render site.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue