···2626// This is where we actually morph the nodes. The `morph` function exists to set up the `idMap`.
2727function morphNodes(node, ref, idMap) {
2828 if (isElement(node) && isElement(ref) && node.tagName === ref.tagName) {
2929- // We need to check if the element is an input, option, or textarea here, because they have
3030- // special attributes not covered by the isEqualNode check.
3129 if (node.hasAttributes() || ref.hasAttributes()) morphAttributes(node, ref);
3232- if (node.hasChildNodes() || ref.hasChildNodes()) morphChildNodes(node, ref, idMap);
3030+ if (isHead(node) && isHead(ref)) {
3131+ const refChildNodes = new Map();
3232+ for (const child of ref.children) refChildNodes.set(child.outerHTML, child);
3333+ for (const child of node.children) {
3434+ const key = child.outerHTML;
3535+ const refChild = refChildNodes.get(key);
3636+ refChild ? refChildNodes.delete(key) : child.remove();
3737+ }
3838+ for (const refChild of refChildNodes.values()) node.appendChild(refChild.cloneNode(true));
3939+ } else if (node.hasChildNodes() || ref.hasChildNodes()) morphChildNodes(node, ref, idMap);
3340 } else {
3441 if (isText(node) && isText(ref)) {
3542 if (node.textContent !== ref.textContent) node.textContent = ref.textContent;
···124131}
125132function isTextArea(element) {
126133 return element.localName === "textarea";
134134+}
135135+function isHead(element) {
136136+ return element.localName === "head";
127137}
128138function isParentNode(node) {
129139 return node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11;
+17-1
src/morphlex.ts
···1717 readonly hasAttribute: (name: string) => boolean;
1818 readonly hasAttributes: () => boolean;
1919 readonly hasChildNodes: () => boolean;
2020+ readonly children: ReadOnlyNodeList<Element>;
2021 });
21222223// Maps a node to a read-only node list of nodes of that type
···6566function morphNodes(node: ChildNode, ref: ReadOnlyNode<ChildNode>, idMap: IdMap): void {
6667 if (isElement(node) && isElement(ref) && node.tagName === ref.tagName) {
6768 if (node.hasAttributes() || ref.hasAttributes()) morphAttributes(node, ref);
6868- if (node.hasChildNodes() || ref.hasChildNodes()) morphChildNodes(node, ref, idMap);
6969+ if (isHead(node) && isHead(ref)) {
7070+ const refChildNodes: Map<string, ReadOnlyNode<Element>> = new Map();
7171+ for (const child of ref.children) refChildNodes.set(child.outerHTML, child);
7272+ for (const child of node.children) {
7373+ const key = child.outerHTML;
7474+ const refChild = refChildNodes.get(key);
7575+ refChild ? refChildNodes.delete(key) : child.remove();
7676+ }
7777+ for (const refChild of refChildNodes.values()) node.appendChild(refChild.cloneNode(true));
7878+ } else if (node.hasChildNodes() || ref.hasChildNodes()) morphChildNodes(node, ref, idMap);
6979 } else {
7080 if (isText(node) && isText(ref)) {
7181 if (node.textContent !== ref.textContent) node.textContent = ref.textContent;
···198208function isTextArea(element: ReadOnlyNode<Element>): element is ReadOnlyNode<HTMLTextAreaElement>;
199209function isTextArea(element: Element | ReadOnlyNode<Element>): boolean {
200210 return element.localName === "textarea";
211211+}
212212+213213+function isHead(element: Element): element is HTMLHeadElement;
214214+function isHead(element: ReadOnlyNode<Element>): element is ReadOnlyNode<HTMLHeadElement>;
215215+function isHead(element: Element | ReadOnlyNode<Element>): boolean {
216216+ return element.localName === "head";
201217}
202218203219function isParentNode(node: Node): node is ParentNode;