Closed kpietraszko closed 1 year ago
we can try!
I was curious to morph the whole document too, but running into errors.
let html = "<html><head><title>hello</title></head><body>World</body></html>"
document.write(html);
Idiomorph.morph(document.documentElement, html);
TypeError: Cannot read properties of null (reading 'replaceChild')
at morphOldNodeTo
yeah, to make this work we definitely need to handle a document, rather than element, root
@ryanflorence any interest in taking a look at what that would mean?
I started looking at a head-tag merging extension for htmx here:
https://github.com/bigskysoftware/htmx/blob/master/src/ext/head-support.js
not sure I want to bring all that in to idiomorph, I think we could just use the existing morphing algorithm w/ a few tweaks to make things work, but not sure...
OK, did some quick digging on this and the problem is here:
https://github.com/bigskysoftware/idiomorph/blob/main/src/idiomorph.js#L421
where we are parsing the content in terms of a template tag. This approach is great for handling arbitrary in-body HTML because it handles the nightmare that is table-related tags cleanly. However, it doesn't handle html, head or body tags.
To do that, we'll need to do something more like what the head-support extension in htmx does:
https://github.com/bigskysoftware/htmx/blob/master/src/ext/head-support.js#L17
So I think the right thing here is to detect if the source starts w/ html, head or body, and switch to this mode of parsing the content, if we want to be able to handle full documents.
@ryanflorence lmk what you think and if you are interested in contributing on this.
OK, had some time to play with this, and it looks like this change makes full page merging work:
function parseContent(newContent) {
let parser = new DOMParser();
// if it is content containing an html tag, a head tag or a body, we can simply parse it w/o wrapping
// it in a template
if (newContent.match(/<html>/) || newContent.match(/<head>/) || newContent.match(/<body>/)) {
let content = parser.parseFromString(newContent, "text/html");
content.generatedByIdiomorph = true;
return content;
} else {
// if it is partial HTML, wrap it in a template tag to provide a parent element and also to help
// deal with touchy tags like tr, tbody, etc.
let responseDoc = parser.parseFromString("<body><template>" + newContent + "</template></body>", "text/html");
let content = responseDoc.body.querySelector('template').content;
content.generatedByIdiomorph = true;
return content
}
}
I need to think about what the head merging algorithm needs to look like (e.g. we would likely want to re-execute at least some JS in the head to mimic normal page loading) but it's a start.
Hey just came back here. Honestly I'm just playing around and exploring a bit right now so not likely to dig in and contribute 😬
Don't forget that usually you've got attributes on html and body (like <html lang="en">
and <body class="flex-col">
etc.) so gotta be more careful on the regexes there.
Ok spent some time this afternoon thinking and playing with the code. I think we want head merging to work specially, rather than the standard morph setup, because:
I have started to port the head-support code over and I think it will work properly. Hope to have something useful by the end of the weekend.
Full page morphing + special head tag handling is now in dev:
https://github.com/bigskysoftware/idiomorph/commit/372471f2f8f45a6bada1ad04b6550681d9eddc0a
I need to test it and then I'll cut a release, hopefully this weekend
just released idiomorph v0.0.8, with support for full document merging, as well as special handling for the head
tag, since it acts kinda different than the body content:
Will morphing whole pages be supported? I'd love a library where you can throw anything at it, and it would "just work". Even including the
head
tag.