1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 14:23:32 +00:00

Revert "Lets shadow DOM check signal page update (#16114)" (commit 6129ca5366) (#17503)

Signed-off-by: Ben Brooks <bbrooks@bitwarden.com>
This commit is contained in:
Ben Brooks
2025-11-25 08:06:03 -08:00
committed by GitHub
parent 540da69daf
commit c04c1757ea
5 changed files with 13 additions and 44 deletions

View File

@@ -6,5 +6,5 @@ export interface DomQueryService {
mutationObserver?: MutationObserver, mutationObserver?: MutationObserver,
forceDeepQueryAttempt?: boolean, forceDeepQueryAttempt?: boolean,
): T[]; ): T[];
checkPageContainsShadowDom(): boolean; checkPageContainsShadowDom(): void;
} }

View File

@@ -395,7 +395,7 @@ describe("CollectAutofillContentService", () => {
}); });
}); });
it("sets the noFieldsFound property to true if the page has no forms or fields", async function () { it("sets the noFieldsFond property to true if the page has no forms or fields", async function () {
document.body.innerHTML = ""; document.body.innerHTML = "";
collectAutofillContentService["noFieldsFound"] = false; collectAutofillContentService["noFieldsFound"] = false;
jest.spyOn(collectAutofillContentService as any, "buildAutofillFormsData"); jest.spyOn(collectAutofillContentService as any, "buildAutofillFormsData");
@@ -2649,33 +2649,4 @@ describe("CollectAutofillContentService", () => {
); );
}); });
}); });
describe("processMutations", () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
it("will require an update to page details if shadow DOM is present", () => {
jest
.spyOn(domQueryService as any, "checkPageContainsShadowDom")
.mockImplementationOnce(() => true);
collectAutofillContentService["requirePageDetailsUpdate"] = jest.fn();
collectAutofillContentService["mutationsQueue"] = [[], []];
collectAutofillContentService["processMutations"]();
jest.runOnlyPendingTimers();
expect(domQueryService.checkPageContainsShadowDom).toHaveBeenCalled();
expect(collectAutofillContentService["mutationsQueue"]).toHaveLength(0);
expect(collectAutofillContentService["requirePageDetailsUpdate"]).toHaveBeenCalled();
});
});
}); });

View File

@@ -997,13 +997,6 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
* within an idle callback to help with performance and prevent excessive updates. * within an idle callback to help with performance and prevent excessive updates.
*/ */
private processMutations = () => { private processMutations = () => {
// If the page contains shadow DOM, we require a page details update from the autofill service.
// Will wait for an idle moment on main thread to execute, unless timeout has passed.
requestIdleCallbackPolyfill(
() => this.domQueryService.checkPageContainsShadowDom() && this.requirePageDetailsUpdate(),
{ timeout: 500 },
);
const queueLength = this.mutationsQueue.length; const queueLength = this.mutationsQueue.length;
for (let queueIndex = 0; queueIndex < queueLength; queueIndex++) { for (let queueIndex = 0; queueIndex < queueLength; queueIndex++) {
@@ -1026,13 +1019,13 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
* Triggers several flags that indicate that a collection of page details should * Triggers several flags that indicate that a collection of page details should
* occur again on a subsequent call after a mutation has been observed in the DOM. * occur again on a subsequent call after a mutation has been observed in the DOM.
*/ */
private requirePageDetailsUpdate = () => { private flagPageDetailsUpdateIsRequired() {
this.domRecentlyMutated = true; this.domRecentlyMutated = true;
if (this.autofillOverlayContentService) { if (this.autofillOverlayContentService) {
this.autofillOverlayContentService.pageDetailsUpdateRequired = true; this.autofillOverlayContentService.pageDetailsUpdateRequired = true;
} }
this.noFieldsFound = false; this.noFieldsFound = false;
}; }
/** /**
* Processes all mutation records encountered by the mutation observer. * Processes all mutation records encountered by the mutation observer.
@@ -1060,7 +1053,7 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
(this.isAutofillElementNodeMutated(mutation.removedNodes, true) || (this.isAutofillElementNodeMutated(mutation.removedNodes, true) ||
this.isAutofillElementNodeMutated(mutation.addedNodes)) this.isAutofillElementNodeMutated(mutation.addedNodes))
) { ) {
this.requirePageDetailsUpdate(); this.flagPageDetailsUpdateIsRequired();
return; return;
} }

View File

@@ -72,6 +72,7 @@ describe("DomQueryService", () => {
}); });
it("queries form field elements that are nested within multiple ShadowDOM elements", () => { it("queries form field elements that are nested within multiple ShadowDOM elements", () => {
domQueryService["pageContainsShadowDom"] = true;
const root = document.createElement("div"); const root = document.createElement("div");
const shadowRoot1 = root.attachShadow({ mode: "open" }); const shadowRoot1 = root.attachShadow({ mode: "open" });
const root2 = document.createElement("div"); const root2 = document.createElement("div");
@@ -94,6 +95,7 @@ describe("DomQueryService", () => {
}); });
it("will fallback to using the TreeWalker API if a depth larger than 4 ShadowDOM elements is encountered", () => { it("will fallback to using the TreeWalker API if a depth larger than 4 ShadowDOM elements is encountered", () => {
domQueryService["pageContainsShadowDom"] = true;
const root = document.createElement("div"); const root = document.createElement("div");
const shadowRoot1 = root.attachShadow({ mode: "open" }); const shadowRoot1 = root.attachShadow({ mode: "open" });
const root2 = document.createElement("div"); const root2 = document.createElement("div");

View File

@@ -78,9 +78,8 @@ export class DomQueryService implements DomQueryServiceInterface {
/** /**
* Checks if the page contains any shadow DOM elements. * Checks if the page contains any shadow DOM elements.
*/ */
checkPageContainsShadowDom = (): boolean => { checkPageContainsShadowDom = (): void => {
this.pageContainsShadowDom = this.queryShadowRoots(globalThis.document.body, true).length > 0; this.pageContainsShadowDom = this.queryShadowRoots(globalThis.document.body, true).length > 0;
return this.pageContainsShadowDom;
}; };
/** /**
@@ -109,7 +108,7 @@ export class DomQueryService implements DomQueryServiceInterface {
): T[] { ): T[] {
let elements = this.queryElements<T>(root, queryString); let elements = this.queryElements<T>(root, queryString);
const shadowRoots = this.pageContainsShadowDom ? this.recursivelyQueryShadowRoots(root) : []; const shadowRoots = this.recursivelyQueryShadowRoots(root);
for (let index = 0; index < shadowRoots.length; index++) { for (let index = 0; index < shadowRoots.length; index++) {
const shadowRoot = shadowRoots[index]; const shadowRoot = shadowRoots[index];
elements = elements.concat(this.queryElements<T>(shadowRoot, queryString)); elements = elements.concat(this.queryElements<T>(shadowRoot, queryString));
@@ -152,6 +151,10 @@ export class DomQueryService implements DomQueryServiceInterface {
root: Document | ShadowRoot | Element, root: Document | ShadowRoot | Element,
depth: number = 0, depth: number = 0,
): ShadowRoot[] { ): ShadowRoot[] {
if (!this.pageContainsShadowDom) {
return [];
}
if (depth >= MAX_DEEP_QUERY_RECURSION_DEPTH) { if (depth >= MAX_DEEP_QUERY_RECURSION_DEPTH) {
throw new Error("Max recursion depth reached"); throw new Error("Max recursion depth reached");
} }