Morph page updates instead of replacing them
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
377f534f6b
commit
3df9f29b1d
2 changed files with 50 additions and 5 deletions
1
game.py
1
game.py
|
|
@ -6753,6 +6753,7 @@ ORDER_RECIPES, ORDER_RAW = _order_sources()
|
||||||
# line here (new / balance / fix), and a new release a new entry on top.
|
# line here (new / balance / fix), and a new release a new entry on top.
|
||||||
PATCH_NOTES = [
|
PATCH_NOTES = [
|
||||||
{"date": "2026-10-28", "title": "Queue", "notes": [
|
{"date": "2026-10-28", "title": "Queue", "notes": [
|
||||||
|
("fix", "The page no longer redraws itself when an action finishes or a poll lands: scroll, hovers and tooltips stay put."),
|
||||||
("fix", "Crafting cards: buttons stay on one row on phones and narrow cards."),
|
("fix", "Crafting cards: buttons stay on one row on phones and narrow cards."),
|
||||||
("new", "\"Out of:\" lists every missing reagent."),
|
("new", "\"Out of:\" lists every missing reagent."),
|
||||||
("new", "Updated guild roster layout"),
|
("new", "Updated guild roster layout"),
|
||||||
|
|
|
||||||
|
|
@ -680,14 +680,58 @@ function render() {
|
||||||
animate();
|
animate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only touch the DOM when the markup changed. Replacing an element mid-swipe
|
// Only touch the DOM when the markup changed, and then only the nodes that did:
|
||||||
// cancels the swipe on iOS, and polls arrive every few seconds.
|
// swapping the whole page flickers, drops hovers and scroll, and replacing an
|
||||||
|
// element mid-swipe cancels the swipe on iOS. Polls arrive every few seconds.
|
||||||
function setHtml(el, html) {
|
function setHtml(el, html) {
|
||||||
if (el.dataset.html === html) return;
|
if (el.dataset.html === html) return;
|
||||||
const scroll = el.scrollTop;
|
const next = document.createElement("template");
|
||||||
el.innerHTML = html;
|
next.innerHTML = html;
|
||||||
|
morphChildren(el, next.content);
|
||||||
el.dataset.html = html;
|
el.dataset.html = html;
|
||||||
el.scrollTop = scroll;
|
}
|
||||||
|
|
||||||
|
// Patch `from`'s children into `to`'s, pairing them up by position.
|
||||||
|
function morphChildren(from, to) {
|
||||||
|
let old = from.firstChild, fresh = to.firstChild;
|
||||||
|
while (fresh) {
|
||||||
|
const after = fresh.nextSibling;
|
||||||
|
if (!old) from.appendChild(fresh);
|
||||||
|
else if (old.nodeType === fresh.nodeType && old.nodeName === fresh.nodeName) {
|
||||||
|
morphNode(old, fresh);
|
||||||
|
old = old.nextSibling;
|
||||||
|
} else {
|
||||||
|
const gone = old;
|
||||||
|
old = old.nextSibling;
|
||||||
|
from.replaceChild(fresh, gone);
|
||||||
|
}
|
||||||
|
fresh = after;
|
||||||
|
}
|
||||||
|
while (old) {
|
||||||
|
const gone = old;
|
||||||
|
old = old.nextSibling;
|
||||||
|
gone.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function morphNode(old, fresh) {
|
||||||
|
if (old.nodeType !== Node.ELEMENT_NODE) {
|
||||||
|
if (old.nodeValue !== fresh.nodeValue) old.nodeValue = fresh.nodeValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// A fire's canvas sizes itself and holds its drawing: setting its size clears it.
|
||||||
|
if (old.nodeName === "CANVAS" && old.dataset.flame === fresh.dataset.flame) return;
|
||||||
|
for (const { name } of [...old.attributes]) if (!fresh.hasAttribute(name)) old.removeAttribute(name);
|
||||||
|
for (const { name, value } of fresh.attributes) if (old.getAttribute(name) !== value) old.setAttribute(name, value);
|
||||||
|
morphChildren(old, fresh);
|
||||||
|
// What's typed or picked lives in properties, not attributes. Kept fields keep theirs (see render).
|
||||||
|
if (old.dataset.keep === undefined) {
|
||||||
|
if (old.nodeName === "INPUT") {
|
||||||
|
old.checked = fresh.checked;
|
||||||
|
if (old.value !== fresh.value) old.value = fresh.value;
|
||||||
|
} else if (old.nodeName === "TEXTAREA" && old.value !== fresh.value) old.value = fresh.value;
|
||||||
|
else if (old.nodeName === "SELECT") old.value = fresh.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMenu(open) {
|
function setMenu(open) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue