Skip to content

Instantly share code, notes, and snippets.

@metachris
Created April 6, 2021 09:43
Show Gist options
  • Save metachris/765d97328e14d551702a9c7a04c65f73 to your computer and use it in GitHub Desktop.
Save metachris/765d97328e14d551702a9c7a04c65f73 to your computer and use it in GitHub Desktop.
JS function to update HTML body in place (via https://news.ycombinator.com/item?id=26696455)
function update_in_place(old_root, new_root) {
function are_compatible(lhs, rhs) {
return lhs.nodeType === rhs.nodeType && lhs.tagName === rhs.tagName && lhs.id === rhs.id
}
if (old_root.nodeType === 3 && new_root.nodeType === 3) {
old_root.textContent = new_root.textContent;
return old_root
}
if (!are_compatible(old_root, new_root) || old_root.nodeType !== 1) {
old_root.parentElement.replaceChild(new_root, old_root);
return new_root
}
for (var i = 0; i < new_root.attributes.length; i++) {
var a = new_root.attributes[i];
if (a.specified && old_root.getAttribute(a.name) !== a.value) {
old_root.setAttribute(a.name, a.value)
}
}
for (var i = 0; i < old_root.attributes.length; i++) {
var a = old_root.attributes[i];
if (a.specified && !new_root.hasAttribute(a.name)) {
old_root.removeAttribute(a.name)
}
}
var old_children = Array.prototype.slice.call(old_root.childNodes);
var new_children = Array.prototype.slice.call(new_root.childNodes);
var old_start = 0;
var new_start = 0;
var old_end = old_children.length;
var new_end = new_children.length;
while (old_start < old_end || new_start < new_end) {
if (old_start === old_end) {
var target = old_children[old_end];
while (new_start < new_end) {
old_root.insertBefore(new_children[new_start++], target)
}
break
}
if (new_start === new_end) {
while (old_start < old_end) {
old_root.removeChild(old_children[old_start++])
}
break
}
if (old_children[old_start].isEqualNode(new_children[new_start])) {
old_start++;
new_start++;
continue
}
if (old_children[old_end - 1].isEqualNode(new_children[new_end - 1])) {
old_end--;
new_end--;
continue
}
if (old_children[old_start].isEqualNode(new_children[new_start + 1])) {
old_root.insertBefore(new_children[new_start], old_children[old_start]);
new_start += 2;
old_start++;
continue
}
if (old_children[old_end - 1].isEqualNode(new_children[new_end - 2])) {
old_root.insertBefore(new_children[new_end - 1], old_children[old_end]);
new_end -= 2;
old_end--;
continue
}
old_children[old_start] = update_in_place(old_children[old_start], new_children[new_start]);
old_start++;
new_start++
}
return old_root
};
function virtual_refresh() {
xhr("GET", window.location.href, null, function(req) {
var parser = new DOMParser();
var doc = parser.parseFromString(req.response, "text/html");
update_in_place(document.querySelector("body"), doc.body)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment