fix(core): scope duplicate getElementById lookups (#655)

This commit is contained in:
Miguel Ángel
2026-05-07 02:49:30 +02:00
committed by GitHub
parent a327e13a1e
commit ea3f7273e7
2 changed files with 69 additions and 6 deletions
@@ -158,6 +158,56 @@ window.__timelines.scene = tl;
expect(gsapTargets).toEqual([["Scene"], ["Scene"]]);
});
it("scopes getElementById when duplicate IDs exist across composition roots", () => {
const { document } = parseHTML(`
<div data-composition-id="scene-a"><canvas id="gl-canvas"></canvas></div>
<div data-composition-id="scene-b"><canvas id="gl-canvas"></canvas></div>
`);
const fakeWindow = {
document,
__selectedComp: "",
__timelines: {},
};
const wrapped = wrapScopedCompositionScript(
`
window.__selectedComp =
document.getElementById("gl-canvas")
?.closest("[data-composition-id]")
?.getAttribute("data-composition-id") || "null";
`,
"scene-b",
);
new Function("window", wrapped)(fakeWindow);
expect(fakeWindow.__selectedComp).toBe("scene-b");
});
it("scopes getElementById for IDs that need CSS selector escaping", () => {
const { document } = parseHTML(`
<div data-composition-id="scene-a"><div id="clip:1"></div></div>
<div data-composition-id="scene-b"><div id="clip:1"></div></div>
`);
const fakeWindow = {
document,
__selectedComp: "",
__timelines: {},
};
const wrapped = wrapScopedCompositionScript(
`
window.__selectedComp =
document.getElementById("clip:1")
?.closest("[data-composition-id]")
?.getAttribute("data-composition-id") || "null";
`,
"scene-b",
);
new Function("window", wrapped)(fakeWindow);
expect(fakeWindow.__selectedComp).toBe("scene-b");
});
it("reads scoped proxy accessors with the original target receiver", () => {
const root = {
contains(node: unknown) {
@@ -141,17 +141,30 @@ export function wrapScopedCompositionScript(
var matches = __hfQueryAll(selector);
return matches[0] || null;
};
var __hfGetElementById = function(id) {
var found = window.document.getElementById(id);
if (found && __hfContains(found)) return found;
var root = __hfFindRoot();
if (!root) return found || null;
var idValue = id + "";
if (root.id === idValue) return root;
if (typeof root.querySelector !== "function") return null;
if (typeof CSS !== "undefined" && CSS && typeof CSS.escape === "function") {
try {
return root.querySelector("#" + CSS.escape(idValue)) || null;
} catch {}
}
try {
return root.querySelector('[id="' + __hfEscapeAttr(idValue) + '"]') || null;
} catch {}
return null;
};
var __hfScopedDocument = typeof Proxy === "function"
? new Proxy(window.document, {
get: function(target, prop, receiver) {
if (prop === "querySelector") return __hfQueryOne;
if (prop === "querySelectorAll") return __hfQueryAll;
if (prop === "getElementById") {
return function(id) {
var found = target.getElementById(id);
return found && __hfContains(found) ? found : null;
};
}
if (prop === "getElementById") return __hfGetElementById;
var value = Reflect.get(target, prop, target);
return typeof value === "function" ? value.bind(target) : value;
},