From 7a912d4a911897c074d48307cf6cd58df7c42e10 Mon Sep 17 00:00:00 2001 From: Micah Geisel Date: Sun, 20 Jul 2025 12:10:01 +0000 Subject: [PATCH 1/2] it turns out that Element.contains is really slow, so big perf win by precomputing the active element parent path and doing an array inclusion check instead. --- src/idiomorph.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/idiomorph.js b/src/idiomorph.js index 83bccf6..3ecea0e 100644 --- a/src/idiomorph.js +++ b/src/idiomorph.js @@ -112,6 +112,7 @@ var Idiomorph = (function () { * @property {ConfigInternal['callbacks']} callbacks * @property {ConfigInternal['head']} head * @property {HTMLDivElement} pantry + * @property {Element[]} activeElementAndParents */ //============================================================================= @@ -424,7 +425,8 @@ var Idiomorph = (function () { // if the current node contains active element, stop looking for better future matches, // because if one is found, this node will be moved to the pantry, reparenting it and thus losing focus - if (cursor.contains(document.activeElement)) break; + // @ts-ignore pretend cursor is Element rather than Node, we're just testing for array inclusion + if (ctx.activeElementAndParents.includes(cursor)) break; cursor = cursor.nextSibling; } @@ -996,6 +998,7 @@ var Idiomorph = (function () { idMap: idMap, persistentIds: persistentIds, pantry: createPantry(), + activeElementAndParents: createActiveElementAndParents(oldNode), callbacks: mergedConfig.callbacks, head: mergedConfig.head, }; @@ -1036,6 +1039,21 @@ var Idiomorph = (function () { return pantry; } + /** + * @param {Element} oldNode + * @returns {Element[]} + */ + function createActiveElementAndParents(oldNode) { + /** @type {Element[]} */ + let activeElementAndParents = []; + let elt = document.activeElement; + while (elt && elt !== oldNode) { + activeElementAndParents.push(elt); + elt = elt.parentElement; + } + return activeElementAndParents; + } + /** * Returns all elements with an ID contained within the root element and its descendants * From 31ace40b6a0eae17235781bc8b9a80290321daa1 Mon Sep 17 00:00:00 2001 From: Micah Geisel Date: Sun, 20 Jul 2025 13:25:14 +0000 Subject: [PATCH 2/2] don't bother with active element preservation if the active element is . --- src/idiomorph.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/idiomorph.js b/src/idiomorph.js index 3ecea0e..e2ab8b6 100644 --- a/src/idiomorph.js +++ b/src/idiomorph.js @@ -1047,9 +1047,12 @@ var Idiomorph = (function () { /** @type {Element[]} */ let activeElementAndParents = []; let elt = document.activeElement; - while (elt && elt !== oldNode) { - activeElementAndParents.push(elt); - elt = elt.parentElement; + if (elt?.tagName !== "BODY" && oldNode.contains(elt)) { + while (elt) { + activeElementAndParents.push(elt); + if (elt === oldNode) break; + elt = elt.parentElement; + } } return activeElementAndParents; }