1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-23 16:13:21 +00:00

refactor mutation record processing

This commit is contained in:
Jonathan Prusik
2025-07-21 11:24:26 -04:00
parent 5290e0a63b
commit 4f3075f8b8

View File

@@ -1033,8 +1033,8 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
private processMutationRecords(mutations: MutationRecord[]) {
for (let mutationIndex = 0; mutationIndex < mutations.length; mutationIndex++) {
const mutation: MutationRecord = mutations[mutationIndex];
const processMutationRecord = () => this.processMutationRecord(mutation);
requestIdleCallbackPolyfill(processMutationRecord, { timeout: 500 });
const processMutationRecordCallback = () => this.processMutationRecord(mutation);
requestIdleCallbackPolyfill(processMutationRecordCallback, { timeout: 500 });
}
}
@@ -1043,6 +1043,77 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
* @param mutation
* @private
*/
private newProcessMutationRecord(mutation: MutationRecord) {
if (mutation.type === "childList") {
const removedAutofillElementNodes = this.getMutatedAutofillElements(mutation.removedNodes);
for (const elementNode of removedAutofillElementNodes) {
this.deleteCachedAutofillElement(
elementNode as ElementWithOpId<HTMLFormElement> | ElementWithOpId<FormFieldElement>,
);
}
const addedAutofillElementNodes = this.getMutatedAutofillElements(mutation.addedNodes);
if (addedAutofillElementNodes.size && this.autofillOverlayContentService) {
this.setupOverlayListenersOnMutatedElements(
// @TODO temp conversion
Array.from(addedAutofillElementNodes.values()),
);
}
if (removedAutofillElementNodes.size || addedAutofillElementNodes.size) {
this.flagPageDetailsUpdateIsRequired();
}
return;
}
if (mutation.type === "attributes") {
this.handleAutofillElementAttributeMutation(mutation);
}
}
private getMutatedAutofillElements(nodes: NodeList): Set<Node> {
let mutatedAutofillElements: HTMLElement[] = [];
if (!nodes.length) {
return new Set<Node>(mutatedAutofillElements);
}
for (let index = 0; index < nodes.length; index++) {
const node = nodes[index];
if (!nodeIsElement(node)) {
continue;
}
if (nodeIsFormElement(node) || this.isNodeFormFieldElement(node)) {
mutatedAutofillElements = [...mutatedAutofillElements, node as HTMLElement];
}
const autofillElements = this.domQueryService.query<HTMLElement>(
node,
`form, ${this.formFieldQueryString}`,
(walkerNode: Node) =>
nodeIsFormElement(walkerNode) || this.isNodeFormFieldElement(walkerNode),
this.mutationObserver,
true,
);
if (autofillElements.length) {
mutatedAutofillElements = [...mutatedAutofillElements, ...autofillElements];
}
}
return new Set<Node>(mutatedAutofillElements);
}
/**
* @deprecated Use {@link newProcessMutationRecord} and handle desired side-effects as a separate concern
* Processes a single mutation record and updates the autofill elements if necessary.
* @param mutation
* @private
*/
private processMutationRecord(mutation: MutationRecord) {
if (
mutation.type === "childList" &&
@@ -1059,6 +1130,7 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
}
/**
* @deprecated Use {@link getMutatedAutofillElements} and handle desired side-effects as a separate concern
* Checks if the passed nodes either contain or are autofill elements.
*
* @param nodes - The nodes to check
@@ -1123,7 +1195,7 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
private setupOverlayListenersOnMutatedElements(mutatedElements: Node[]) {
for (let elementIndex = 0; elementIndex < mutatedElements.length; elementIndex++) {
const node = mutatedElements[elementIndex];
const buildAutofillFieldItem = () => {
const buildAutofillFieldItemCallback = () => {
if (
!this.isNodeFormFieldElement(node) ||
this.autofillFieldElements.get(node as ElementWithOpId<FormFieldElement>)
@@ -1136,7 +1208,7 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
void this.buildAutofillFieldItem(node as ElementWithOpId<FormFieldElement>, -1);
};
requestIdleCallbackPolyfill(buildAutofillFieldItem, { timeout: 1000 });
requestIdleCallbackPolyfill(buildAutofillFieldItemCallback, { timeout: 1000 });
}
}
@@ -1411,6 +1483,7 @@ export class CollectAutofillContentService implements CollectAutofillContentServ
* Validates whether a password field is within the document.
*/
isPasswordFieldWithinDocument(): boolean {
// console.log('🚀 🚀 CollectAutofillContentService 🚀 isPasswordFieldWithinDocument 🚀 isPasswordFieldWithinDocument');
return (
this.domQueryService.query<HTMLInputElement>(
globalThis.document.documentElement,