mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-14 01:01:31 +01:00
[PM-8027] Reworking inline menu to qualify and setup the listeners for each form field after page deatils have been collected
This commit is contained in:
parent
43246056a3
commit
f3d41f91aa
@ -1,6 +1,5 @@
|
||||
import AutofillPageDetails from "../models/autofill-page-details";
|
||||
import { AutofillOverlayContentService } from "../services/abstractions/autofill-overlay-content.service";
|
||||
import { AutofillFieldQualificationService } from "../services/autofill-field-qualification.service";
|
||||
import CollectAutofillContentService from "../services/collect-autofill-content.service";
|
||||
import DomElementVisibilityService from "../services/dom-element-visibility.service";
|
||||
import InsertAutofillContentService from "../services/insert-autofill-content.service";
|
||||
@ -13,7 +12,6 @@ import {
|
||||
} from "./abstractions/autofill-init";
|
||||
|
||||
class AutofillInit implements AutofillInitInterface {
|
||||
private readonly autofillFieldQualificationService: AutofillFieldQualificationService;
|
||||
private readonly autofillOverlayContentService: AutofillOverlayContentService | undefined;
|
||||
private readonly domElementVisibilityService: DomElementVisibilityService;
|
||||
private readonly collectAutofillContentService: CollectAutofillContentService;
|
||||
@ -40,7 +38,6 @@ class AutofillInit implements AutofillInitInterface {
|
||||
* @param autofillOverlayContentService - The autofill overlay content service, potentially undefined.
|
||||
*/
|
||||
constructor(autofillOverlayContentService?: AutofillOverlayContentService) {
|
||||
this.autofillFieldQualificationService = new AutofillFieldQualificationService();
|
||||
this.autofillOverlayContentService = autofillOverlayContentService;
|
||||
this.domElementVisibilityService = new DomElementVisibilityService();
|
||||
this.collectAutofillContentService = new CollectAutofillContentService(
|
||||
@ -102,16 +99,6 @@ class AutofillInit implements AutofillInitInterface {
|
||||
const pageDetails: AutofillPageDetails =
|
||||
await this.collectAutofillContentService.getPageDetails();
|
||||
|
||||
// console.log(pageDetails);
|
||||
// pageDetails.fields.forEach((field) => {
|
||||
// const isLoginField = this.autofillFieldQualificationService.isFieldForLoginForm(
|
||||
// field,
|
||||
// pageDetails,
|
||||
// );
|
||||
//
|
||||
// console.log(isLoginField, field);
|
||||
// });
|
||||
|
||||
if (sendDetailsInResponse) {
|
||||
return pageDetails;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
|
||||
import AutofillField from "../../models/autofill-field";
|
||||
import AutofillPageDetails from "../../models/autofill-page-details";
|
||||
import { ElementWithOpId, FormFieldElement } from "../../types";
|
||||
|
||||
type OpenAutofillOverlayOptions = {
|
||||
@ -19,6 +20,7 @@ interface AutofillOverlayContentService {
|
||||
setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement: ElementWithOpId<FormFieldElement>,
|
||||
autofillFieldData: AutofillField,
|
||||
pageDetails: AutofillPageDetails,
|
||||
): Promise<void>;
|
||||
openAutofillOverlay(options: OpenAutofillOverlayOptions): void;
|
||||
removeAutofillOverlay(): void;
|
||||
|
@ -4,6 +4,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
|
||||
import { EVENTS, AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
||||
|
||||
import AutofillField from "../models/autofill-field";
|
||||
import AutofillPageDetails from "../models/autofill-page-details";
|
||||
import { createAutofillFieldMock } from "../spec/autofill-mocks";
|
||||
import { flushPromises } from "../spec/testing-utils";
|
||||
import { ElementWithOpId, FormFieldElement } from "../types";
|
||||
@ -27,6 +28,8 @@ function createMutationRecordMock(customFields = {}): MutationRecord {
|
||||
};
|
||||
}
|
||||
|
||||
const temporaryPageDetailsMock = mock<AutofillPageDetails>();
|
||||
|
||||
const defaultWindowReadyState = document.readyState;
|
||||
const defaultDocumentVisibilityState = document.visibilityState;
|
||||
describe("AutofillOverlayContentService", () => {
|
||||
@ -179,6 +182,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||
@ -190,6 +194,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||
@ -201,6 +206,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||
@ -213,6 +219,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||
@ -225,6 +232,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||
@ -236,6 +244,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||
@ -247,6 +256,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||
@ -259,6 +269,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled();
|
||||
@ -272,6 +283,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("getAutofillOverlayVisibility");
|
||||
@ -287,6 +299,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillOverlayContentService["autofillOverlayVisibility"]).toEqual(
|
||||
@ -310,6 +323,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillFieldElement.removeEventListener).toHaveBeenNthCalledWith(
|
||||
@ -334,6 +348,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
});
|
||||
|
||||
@ -357,6 +372,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
jest.spyOn(globalThis.customElements, "define").mockImplementation();
|
||||
});
|
||||
@ -440,6 +456,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
spanAutofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
spanAutofillFieldElement.dispatchEvent(new Event("input"));
|
||||
@ -451,6 +468,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
autofillFieldElement.dispatchEvent(new Event("input"));
|
||||
|
||||
@ -467,6 +485,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
passwordFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
passwordFieldElement.dispatchEvent(new Event("input"));
|
||||
|
||||
@ -486,6 +505,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
autofillFieldElement.dispatchEvent(new Event("input"));
|
||||
|
||||
@ -504,6 +524,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
autofillFieldElement.dispatchEvent(new Event("input"));
|
||||
|
||||
@ -517,6 +538,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
autofillFieldElement.dispatchEvent(new Event("input"));
|
||||
|
||||
@ -531,6 +553,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
autofillFieldElement.dispatchEvent(new Event("input"));
|
||||
|
||||
@ -546,6 +569,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
autofillFieldElement.dispatchEvent(new Event("input"));
|
||||
|
||||
@ -563,6 +587,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
});
|
||||
|
||||
@ -613,6 +638,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
autofillFieldElement.dispatchEvent(new Event("focus"));
|
||||
@ -624,6 +650,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
autofillFieldElement.dispatchEvent(new Event("focus"));
|
||||
@ -641,6 +668,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
autofillFieldElement.dispatchEvent(new Event("focus"));
|
||||
@ -660,6 +688,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
autofillFieldElement.dispatchEvent(new Event("focus"));
|
||||
@ -678,6 +707,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
autofillFieldElement.dispatchEvent(new Event("focus"));
|
||||
@ -695,6 +725,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
autofillFieldElement.dispatchEvent(new Event("focus"));
|
||||
@ -711,6 +742,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
autofillFieldElement.dispatchEvent(new Event("focus"));
|
||||
@ -733,6 +765,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("openAutofillOverlay");
|
||||
@ -747,6 +780,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
|
||||
expect(autofillOverlayContentService["mostRecentlyFocusedField"]).toEqual(
|
||||
@ -1613,6 +1647,7 @@ describe("AutofillOverlayContentService", () => {
|
||||
autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
autofillFieldElement,
|
||||
autofillFieldData,
|
||||
temporaryPageDetailsMock,
|
||||
);
|
||||
autofillOverlayContentService["mostRecentlyFocusedField"] = autofillFieldElement;
|
||||
});
|
||||
|
@ -7,6 +7,7 @@ import { EVENTS, AutofillOverlayVisibility } from "@bitwarden/common/autofill/co
|
||||
|
||||
import { FocusedFieldData } from "../background/abstractions/overlay.background";
|
||||
import AutofillField from "../models/autofill-field";
|
||||
import AutofillPageDetails from "../models/autofill-page-details";
|
||||
import AutofillOverlayButtonIframe from "../overlay/iframe-content/autofill-overlay-button-iframe";
|
||||
import AutofillOverlayListIframe from "../overlay/iframe-content/autofill-overlay-list-iframe";
|
||||
import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types";
|
||||
@ -23,8 +24,10 @@ import {
|
||||
OpenAutofillOverlayOptions,
|
||||
} from "./abstractions/autofill-overlay-content.service";
|
||||
import { AutoFillConstants } from "./autofill-constants";
|
||||
import { InlineMenuFieldQualificationService } from "./inline-menu-field-qualification.service";
|
||||
|
||||
class AutofillOverlayContentService implements AutofillOverlayContentServiceInterface {
|
||||
private readonly inlineMenuFieldQualificationService: InlineMenuFieldQualificationService;
|
||||
isFieldCurrentlyFocused = false;
|
||||
isCurrentlyFilling = false;
|
||||
isOverlayCiphersPopulated = false;
|
||||
@ -62,6 +65,10 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
||||
zIndex: "2147483647",
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.inlineMenuFieldQualificationService = new InlineMenuFieldQualificationService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the autofill overlay content service by setting up the mutation observers.
|
||||
* The observers will be instantiated on DOMContentLoaded if the page is current loading.
|
||||
@ -81,12 +88,17 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
||||
*
|
||||
* @param formFieldElement - Form field elements identified during the page details collection process.
|
||||
* @param autofillFieldData - Autofill field data captured from the form field element.
|
||||
* @param pageDetails - The collected page details from the tab.
|
||||
*/
|
||||
async setupAutofillOverlayListenerOnField(
|
||||
formFieldElement: ElementWithOpId<FormFieldElement>,
|
||||
autofillFieldData: AutofillField,
|
||||
pageDetails: AutofillPageDetails,
|
||||
) {
|
||||
if (this.isIgnoredField(autofillFieldData) || this.formFieldElements.has(formFieldElement)) {
|
||||
if (
|
||||
this.formFieldElements.has(formFieldElement) ||
|
||||
!this.inlineMenuFieldQualificationService.isFieldForLoginForm(autofillFieldData, pageDetails)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -745,15 +757,15 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
||||
autofillFieldData.readonly ||
|
||||
autofillFieldData.disabled ||
|
||||
!autofillFieldData.viewable ||
|
||||
this.ignoredFieldTypes.has(autofillFieldData.type) ||
|
||||
this.keywordsFoundInFieldData(autofillFieldData, ["search", "captcha"])
|
||||
this.ignoredFieldTypes.has(autofillFieldData.type)
|
||||
// || this.keywordsFoundInFieldData(autofillFieldData, ["search", "captcha"])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const isLoginCipherField =
|
||||
autofillFieldData.type === "password" ||
|
||||
this.keywordsFoundInFieldData(autofillFieldData, AutoFillConstants.UsernameFieldNames);
|
||||
this.inlineMenuFieldQualificationService.isCurrentPasswordField(autofillFieldData) ||
|
||||
this.inlineMenuFieldQualificationService.isUsernameField(autofillFieldData);
|
||||
|
||||
return !isLoginCipherField;
|
||||
}
|
||||
|
@ -72,14 +72,17 @@ describe("CollectAutofillContentService", () => {
|
||||
it("returns an object with empty forms and fields if no fields were found on a previous iteration", async () => {
|
||||
collectAutofillContentService["domRecentlyMutated"] = false;
|
||||
collectAutofillContentService["noFieldsFound"] = true;
|
||||
jest.spyOn(collectAutofillContentService as any, "getFormattedPageDetails");
|
||||
jest.spyOn(collectAutofillContentService as any, "buildFormattedPageDetails");
|
||||
jest.spyOn(collectAutofillContentService as any, "queryAutofillFormAndFieldElements");
|
||||
jest.spyOn(collectAutofillContentService as any, "buildAutofillFormsData");
|
||||
jest.spyOn(collectAutofillContentService as any, "buildAutofillFieldsData");
|
||||
|
||||
await collectAutofillContentService.getPageDetails();
|
||||
|
||||
expect(collectAutofillContentService["getFormattedPageDetails"]).toHaveBeenCalledWith({}, []);
|
||||
expect(collectAutofillContentService["buildFormattedPageDetails"]).toHaveBeenCalledWith(
|
||||
{},
|
||||
[],
|
||||
);
|
||||
expect(
|
||||
collectAutofillContentService["queryAutofillFormAndFieldElements"],
|
||||
).not.toHaveBeenCalled();
|
||||
@ -156,7 +159,7 @@ describe("CollectAutofillContentService", () => {
|
||||
collectAutofillContentService["autofillFieldElements"] = new Map([
|
||||
[fieldElement, autofillField],
|
||||
]);
|
||||
jest.spyOn(collectAutofillContentService as any, "getFormattedPageDetails");
|
||||
jest.spyOn(collectAutofillContentService as any, "buildFormattedPageDetails");
|
||||
jest.spyOn(collectAutofillContentService as any, "getFormattedAutofillFormsData");
|
||||
jest.spyOn(collectAutofillContentService as any, "getFormattedAutofillFieldsData");
|
||||
jest.spyOn(collectAutofillContentService as any, "queryAutofillFormAndFieldElements");
|
||||
@ -165,7 +168,7 @@ describe("CollectAutofillContentService", () => {
|
||||
|
||||
await collectAutofillContentService.getPageDetails();
|
||||
|
||||
expect(collectAutofillContentService["getFormattedPageDetails"]).toHaveBeenCalled();
|
||||
expect(collectAutofillContentService["buildFormattedPageDetails"]).toHaveBeenCalled();
|
||||
expect(collectAutofillContentService["getFormattedAutofillFormsData"]).toHaveBeenCalled();
|
||||
expect(collectAutofillContentService["getFormattedAutofillFieldsData"]).toHaveBeenCalled();
|
||||
expect(
|
||||
|
@ -17,7 +17,6 @@ import {
|
||||
elementIsSelectElement,
|
||||
elementIsSpanElement,
|
||||
nodeIsElement,
|
||||
elementIsInputElement,
|
||||
elementIsTextAreaElement,
|
||||
nodeIsFormElement,
|
||||
nodeIsInputElement,
|
||||
@ -46,6 +45,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
||||
private mutationObserver: MutationObserver;
|
||||
private updateAutofillElementsAfterMutationTimeout: number | NodeJS.Timeout;
|
||||
private mutationsQueue: MutationRecord[][] = [];
|
||||
private cachedAutofillPageDetails: AutofillPageDetails;
|
||||
private readonly updateAfterMutationTimeoutDelay = 1000;
|
||||
private readonly formFieldQueryString;
|
||||
private readonly nonInputFormFieldTags = new Set(["textarea", "select"]);
|
||||
@ -95,13 +95,13 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
||||
}
|
||||
|
||||
if (!this.domRecentlyMutated && this.noFieldsFound) {
|
||||
return this.getFormattedPageDetails({}, []);
|
||||
return this.buildFormattedPageDetails({}, []);
|
||||
}
|
||||
|
||||
if (!this.domRecentlyMutated && this.autofillFieldElements.size) {
|
||||
this.updateCachedAutofillFieldVisibility();
|
||||
|
||||
return this.getFormattedPageDetails(
|
||||
return this.buildFormattedPageDetails(
|
||||
this.getFormattedAutofillFormsData(),
|
||||
this.getFormattedAutofillFieldsData(),
|
||||
);
|
||||
@ -120,7 +120,25 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
||||
}
|
||||
|
||||
this.domRecentlyMutated = false;
|
||||
return this.getFormattedPageDetails(autofillFormsData, autofillFieldsData);
|
||||
const pageDetails = this.buildFormattedPageDetails(autofillFormsData, autofillFieldsData);
|
||||
this.setupInlineMenuListeners(pageDetails);
|
||||
|
||||
return pageDetails;
|
||||
}
|
||||
|
||||
private setupInlineMenuListeners(pageDetails: AutofillPageDetails) {
|
||||
if (!this.autofillOverlayContentService) {
|
||||
return;
|
||||
}
|
||||
|
||||
const formFieldElements = Array.from(this.autofillFieldElements.keys());
|
||||
for (const element of formFieldElements) {
|
||||
void this.autofillOverlayContentService.setupAutofillOverlayListenerOnField(
|
||||
element,
|
||||
this.autofillFieldElements.get(element),
|
||||
pageDetails,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -256,11 +274,11 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
||||
* @param autofillFormsData - The data for all the forms found in the page
|
||||
* @param autofillFieldsData - The data for all the fields found in the page
|
||||
*/
|
||||
private getFormattedPageDetails(
|
||||
private buildFormattedPageDetails(
|
||||
autofillFormsData: Record<string, AutofillForm>,
|
||||
autofillFieldsData: AutofillField[],
|
||||
): AutofillPageDetails {
|
||||
return {
|
||||
this.cachedAutofillPageDetails = {
|
||||
title: document.title,
|
||||
url: (document.defaultView || globalThis).location.href,
|
||||
documentUrl: document.location.href,
|
||||
@ -268,6 +286,8 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
||||
fields: autofillFieldsData,
|
||||
collectedTimestamp: Date.now(),
|
||||
};
|
||||
|
||||
return this.cachedAutofillPageDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,10 +473,10 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
||||
|
||||
if (elementIsSpanElement(element)) {
|
||||
this.cacheAutofillFieldElement(index, element, autofillFieldBase);
|
||||
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
||||
element,
|
||||
autofillFieldBase,
|
||||
);
|
||||
// void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
||||
// element,
|
||||
// autofillFieldBase,
|
||||
// );
|
||||
return autofillFieldBase;
|
||||
}
|
||||
|
||||
@ -496,10 +516,10 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
||||
};
|
||||
|
||||
this.cacheAutofillFieldElement(index, element, autofillField);
|
||||
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
||||
element,
|
||||
autofillField,
|
||||
);
|
||||
// void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
||||
// element,
|
||||
// autofillField,
|
||||
// );
|
||||
return autofillField;
|
||||
};
|
||||
|
||||
@ -1428,6 +1448,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
|
||||
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
|
||||
formFieldElement,
|
||||
cachedAutofillFieldElement,
|
||||
this.cachedAutofillPageDetails,
|
||||
);
|
||||
|
||||
this.intersectionObserver?.unobserve(entry.target);
|
||||
|
@ -3,7 +3,7 @@ import AutofillPageDetails from "../models/autofill-page-details";
|
||||
|
||||
import { AutoFillConstants } from "./autofill-constants";
|
||||
|
||||
export class AutofillFieldQualificationService {
|
||||
export class InlineMenuFieldQualificationService {
|
||||
private searchFieldNamesSet = new Set(AutoFillConstants.SearchFieldNames);
|
||||
private excludedAutofillLoginTypesSet = new Set(AutoFillConstants.ExcludedAutofillLoginTypes);
|
||||
private usernameFieldTypes = new Set(["text", "email", "tel"]);
|
||||
@ -13,13 +13,8 @@ export class AutofillFieldQualificationService {
|
||||
private invalidAutocompleteValuesSet = new Set(["off", "false"]);
|
||||
|
||||
isFieldForLoginForm(field: AutofillField, pageDetails: AutofillPageDetails): boolean {
|
||||
// TODO: Determine whether it makes sense to even incorporate this.
|
||||
if (!field.viewable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isExistingPasswordField = this.isExistingPasswordField(field);
|
||||
if (isExistingPasswordField) {
|
||||
const isCurrentPasswordField = this.isCurrentPasswordField(field);
|
||||
if (isCurrentPasswordField) {
|
||||
return this.isPasswordFieldForLoginForm(field, pageDetails);
|
||||
}
|
||||
|
||||
@ -43,7 +38,7 @@ export class AutofillFieldQualificationService {
|
||||
// Check if the field has a form parent
|
||||
const parentForm = pageDetails.forms[field.form];
|
||||
const usernameFieldsInPageDetails = pageDetails.fields.filter(this.isUsernameField);
|
||||
const passwordFieldsInPageDetails = pageDetails.fields.filter(this.isExistingPasswordField);
|
||||
const passwordFieldsInPageDetails = pageDetails.fields.filter(this.isCurrentPasswordField);
|
||||
// If no form parent is found, check if a username field exists and no other password fields are found in the page details, if so treat this as a password field
|
||||
if (
|
||||
!parentForm &&
|
||||
@ -100,7 +95,7 @@ export class AutofillFieldQualificationService {
|
||||
|
||||
// Check if the field has a form parent
|
||||
const parentForm = pageDetails.forms[field.form];
|
||||
const passwordFieldsInPageDetails = pageDetails.fields.filter(this.isExistingPasswordField);
|
||||
const passwordFieldsInPageDetails = pageDetails.fields.filter(this.isCurrentPasswordField);
|
||||
// console.log(passwordFieldsInPageDetails);
|
||||
|
||||
// If no form parent is found, check if a single password field is found in the page details, if so treat this as a username field
|
||||
@ -177,7 +172,7 @@ export class AutofillFieldQualificationService {
|
||||
return this.keywordsFoundInFieldData(field, AutoFillConstants.UsernameFieldNames);
|
||||
};
|
||||
|
||||
isExistingPasswordField = (field: AutofillField): boolean => {
|
||||
isCurrentPasswordField = (field: AutofillField): boolean => {
|
||||
if (field.autoCompleteType === "new-password") {
|
||||
return false;
|
||||
}
|
Loading…
Reference in New Issue
Block a user