diff --git a/apps/browser/src/autofill/background/abstractions/overlay.background.ts b/apps/browser/src/autofill/background/abstractions/overlay.background.ts index 8b8ec47e89..3313d3405c 100644 --- a/apps/browser/src/autofill/background/abstractions/overlay.background.ts +++ b/apps/browser/src/autofill/background/abstractions/overlay.background.ts @@ -98,9 +98,7 @@ export type OverlayBackgroundExtensionMessageHandlers = { updateIsFieldCurrentlyFilling: ({ message }: BackgroundMessageParam) => void; checkIsFieldCurrentlyFilling: () => boolean; getAutofillInlineMenuVisibility: () => void; - closeAutofillInlineMenu: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; - checkAutofillInlineMenuFocused: () => void; - focusAutofillInlineMenuList: () => void; + updateAutofillInlineMenuPosition: ({ message, sender, @@ -143,10 +141,14 @@ export type OverlayContentScriptPortMessageHandlers = { updateFocusedFieldData: ({ message, port }: PortOnMessageHandlerParams) => void; updateIsFieldCurrentlyFocused: ({ message }: PortMessageParam) => void; openAutofillInlineMenu: () => void; + closeAutofillInlineMenu: ({ message, port }: PortOnMessageHandlerParams) => void; + checkAutofillInlineMenuFocused: () => void; + focusAutofillInlineMenuList: () => void; }; export type InlineMenuButtonPortMessageHandlers = { [key: string]: CallableFunction; + closeAutofillInlineMenu: ({ message, port }: PortOnMessageHandlerParams) => void; triggerDelayedAutofillInlineMenuClosure: ({ port }: PortConnectionParam) => void; autofillInlineMenuButtonClicked: ({ port }: PortConnectionParam) => void; autofillInlineMenuBlurred: () => void; @@ -156,6 +158,7 @@ export type InlineMenuButtonPortMessageHandlers = { export type InlineMenuListPortMessageHandlers = { [key: string]: CallableFunction; + closeAutofillInlineMenu: ({ message, port }: PortOnMessageHandlerParams) => void; checkAutofillInlineMenuButtonFocused: () => void; autofillInlineMenuBlurred: () => void; unlockVault: ({ port }: PortConnectionParam) => void; diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 38343ff0b4..9d948dd26f 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -81,9 +81,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { updateIsFieldCurrentlyFilling: ({ message }) => this.updateIsFieldCurrentlyFilling(message), checkIsFieldCurrentlyFilling: () => this.checkIsFieldCurrentlyFilling(), getAutofillInlineMenuVisibility: () => this.getInlineMenuVisibility(), - closeAutofillInlineMenu: ({ message, sender }) => this.closeInlineMenu(sender, message), - checkAutofillInlineMenuFocused: () => this.checkInlineMenuFocused(), - focusAutofillInlineMenuList: () => this.focusInlineMenuList(), + updateAutofillInlineMenuPosition: ({ message, sender }) => this.updateInlineMenuPosition(message, sender), toggleAutofillInlineMenuHidden: ({ message, sender }) => @@ -110,8 +108,12 @@ export class OverlayBackground implements OverlayBackgroundInterface { updateFocusedFieldData: ({ message, port }) => this.setFocusedFieldData(message, port), updateIsFieldCurrentlyFocused: ({ message }) => this.updateIsFieldCurrentlyFocused(message), openAutofillInlineMenu: () => this.openInlineMenu(false), + closeAutofillInlineMenu: ({ message, port }) => this.closeInlineMenu(port.sender, message), + checkAutofillInlineMenuFocused: () => this.checkInlineMenuFocused(), + focusAutofillInlineMenuList: () => this.focusInlineMenuList(), }; private readonly inlineMenuButtonPortMessageHandlers: InlineMenuButtonPortMessageHandlers = { + closeAutofillInlineMenu: ({ message, port }) => this.closeInlineMenu(port.sender, message), triggerDelayedAutofillInlineMenuClosure: ({ port }) => this.triggerDelayedInlineMenuClosure(), autofillInlineMenuButtonClicked: ({ port }) => this.handleInlineMenuButtonClicked(port), autofillInlineMenuBlurred: () => this.checkInlineMenuListFocused(), @@ -120,6 +122,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { updateAutofillInlineMenuColorScheme: () => this.updateInlineMenuButtonColorScheme(), }; private readonly inlineMenuListPortMessageHandlers: InlineMenuListPortMessageHandlers = { + closeAutofillInlineMenu: ({ message, port }) => this.closeInlineMenu(port.sender, message), checkAutofillInlineMenuButtonFocused: () => this.checkInlineMenuButtonFocused(), autofillInlineMenuBlurred: () => this.checkInlineMenuButtonFocused(), unlockVault: ({ port }) => this.unlockVault(port), diff --git a/apps/browser/src/autofill/overlay/inline-menu/iframe-content/autofill-inline-menu-iframe.service.ts b/apps/browser/src/autofill/overlay/inline-menu/iframe-content/autofill-inline-menu-iframe.service.ts index a8d4c7354d..997836dd36 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/iframe-content/autofill-inline-menu-iframe.service.ts +++ b/apps/browser/src/autofill/overlay/inline-menu/iframe-content/autofill-inline-menu-iframe.service.ts @@ -1,7 +1,7 @@ import { EVENTS } from "@bitwarden/common/autofill/constants"; import { ThemeType } from "@bitwarden/common/platform/enums"; -import { sendExtensionMessage, setElementStyles } from "../../../utils"; +import { setElementStyles } from "../../../utils"; import { BackgroundPortMessageHandlers, AutofillInlineMenuIframeService as AutofillInlineMenuIframeServiceInterface, @@ -10,7 +10,6 @@ import { export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframeServiceInterface { private readonly setElementStyles = setElementStyles; - private readonly sendExtensionMessage = sendExtensionMessage; private port: chrome.runtime.Port | null = null; private portKey: string; private iframeMutationObserver: MutationObserver; @@ -305,7 +304,7 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe * mutation observer is triggered excessively. */ private forceCloseInlineMenu() { - void this.sendExtensionMessage("closeAutofillInlineMenu", { forceClose: true }); + void this.port.postMessage({ command: "closeAutofillInlineMenu", forceClose: true }); } private handleFadeInInlineMenuIframe() { diff --git a/apps/browser/src/autofill/services/abstractions/autofill-overlay-content.service.ts b/apps/browser/src/autofill/services/abstractions/autofill-overlay-content.service.ts index cceeddbac8..853778ed97 100644 --- a/apps/browser/src/autofill/services/abstractions/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/abstractions/autofill-overlay-content.service.ts @@ -44,6 +44,7 @@ export type AutofillOverlayContentExtensionMessage = { overlayElement?: AutofillOverlayElementType; focusedFieldData?: FocusedFieldData; isFieldCurrentlyFocused?: boolean; + forceCloseInlineMenu?: boolean; } & OverlayAddNewItemMessage; export interface AutofillOverlayContentService { diff --git a/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts b/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts index da9e7f6200..0b77f7e051 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts @@ -905,17 +905,6 @@ describe("AutofillOverlayContentService", () => { }); }); - it("clears the user interaction timeout", async () => { - jest.useFakeTimers(); - const clearTimeoutSpy = jest.spyOn(globalThis, "clearTimeout"); - autofillOverlayContentService["userInteractionEventTimeout"] = setTimeout(jest.fn(), 123); - - globalThis.dispatchEvent(new Event(EVENTS.SCROLL)); - await flushPromises(); - - expect(clearTimeoutSpy).toHaveBeenCalledWith(expect.anything()); - }); - it("removes the overlay completely if the field is not focused", async () => { jest.useFakeTimers(); jest @@ -1695,14 +1684,6 @@ describe("AutofillOverlayContentService", () => { autofillOverlayContentService["mostRecentlyFocusedField"] = autofillFieldElement; }); - it("clears the user interaction event timeout", () => { - jest.spyOn(autofillOverlayContentService as any, "clearUserInteractionEventTimeout"); - - autofillOverlayContentService.destroy(); - - expect(autofillOverlayContentService["clearUserInteractionEventTimeout"]).toHaveBeenCalled(); - }); - it("de-registers all global event listeners", () => { jest.spyOn(globalThis.document, "removeEventListener"); jest.spyOn(globalThis, "removeEventListener"); diff --git a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts index 2fbf281275..07d03b2341 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts @@ -54,11 +54,8 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ private focusableElements: FocusableElement[] = []; private mostRecentlyFocusedField: ElementWithOpId; private focusedFieldData: FocusedFieldData; - private userInteractionEventTimeout: number | NodeJS.Timeout; - private recalculateSubFrameOffsetsTimeout: number | NodeJS.Timeout; private closeInlineMenuOnRedirectTimeout: number | NodeJS.Timeout; private focusInlineMenuListTimeout: number | NodeJS.Timeout; - private closeInlineMenuOnFilledFieldTimeout: number | NodeJS.Timeout; private eventHandlersMemo: { [key: string]: EventListener } = {}; private readonly extensionMessageHandlers: AutofillOverlayContentExtensionMessageHandlers = { openAutofillInlineMenu: ({ message }) => this.openInlineMenu(message), @@ -207,7 +204,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ this.mostRecentlyFocusedField?.blur(); if (isClosingInlineMenu) { - void this.sendExtensionMessage("closeAutofillInlineMenu"); + this.sendPortMessage("closeAutofillInlineMenu"); } } @@ -252,7 +249,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ if (direction === RedirectFocusDirection.Current) { this.focusMostRecentlyFocusedField(); this.closeInlineMenuOnRedirectTimeout = globalThis.setTimeout( - () => void this.sendExtensionMessage("closeAutofillInlineMenu"), + () => this.sendPortMessage("closeAutofillInlineMenu"), 100, ); return; @@ -350,7 +347,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ this.sendPortMessage("updateIsFieldCurrentlyFocused", { isFieldCurrentlyFocused: false, }); - void this.sendExtensionMessage("checkAutofillInlineMenuFocused"); + this.sendPortMessage("checkAutofillInlineMenuFocused"); }; /** @@ -364,7 +361,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ private handleFormFieldKeyupEvent = async (event: KeyboardEvent) => { const eventCode = event.code; if (eventCode === "Escape") { - void this.sendExtensionMessage("closeAutofillInlineMenu", { + this.sendPortMessage("closeAutofillInlineMenu", { forceCloseInlineMenu: true, }); return; @@ -394,13 +391,13 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ await this.updateMostRecentlyFocusedField(this.mostRecentlyFocusedField); this.openInlineMenu({ isOpeningFullInlineMenu: true }); this.focusInlineMenuListTimeout = globalThis.setTimeout( - () => this.sendExtensionMessage("focusAutofillInlineMenuList"), + () => this.sendPortMessage("focusAutofillInlineMenuList"), 125, ); return; } - void this.sendExtensionMessage("focusAutofillInlineMenuList"); + this.sendPortMessage("focusAutofillInlineMenuList"); } /** @@ -430,7 +427,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ this.storeModifiedFormElement(formFieldElement); if (await this.hideInlineMenuListOnFilledField(formFieldElement)) { - void this.sendExtensionMessage("closeAutofillInlineMenu", { + this.sendPortMessage("closeAutofillInlineMenu", { overlayElement: AutofillOverlayElement.List, forceCloseInlineMenu: true, }); @@ -514,13 +511,6 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ this.sendPortMessage("updateIsFieldCurrentlyFocused", { isFieldCurrentlyFocused: true, }); - if (this.userInteractionEventTimeout) { - this.clearUserInteractionEventTimeout(); - void this.toggleInlineMenuHidden(false, true); - void this.sendExtensionMessage("closeAutofillInlineMenu", { - forceCloseInlineMenu: true, - }); - } const initiallyFocusedField = this.mostRecentlyFocusedField; await this.updateMostRecentlyFocusedField(formFieldElement); @@ -529,7 +519,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ (initiallyFocusedField !== this.mostRecentlyFocusedField && (await this.hideInlineMenuListOnFilledField(formFieldElement as FillableFormFieldElement))) ) { - await this.sendExtensionMessage("closeAutofillInlineMenu", { + this.sendPortMessage("closeAutofillInlineMenu", { overlayElement: AutofillOverlayElement.List, forceCloseInlineMenu: true, }); @@ -1017,7 +1007,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ } this.unsetMostRecentlyFocusedField(); - void this.sendExtensionMessage("closeAutofillInlineMenu", { + this.sendPortMessage("closeAutofillInlineMenu", { forceCloseInlineMenu: true, }); }; @@ -1135,32 +1125,6 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ this.port.postMessage({ command, ...message }); } - /** - * Clears the user interaction event timeout. This is used to ensure that - * the overlay is not repositioned while the user is interacting with it. - */ - private clearUserInteractionEventTimeout() { - if (this.userInteractionEventTimeout) { - globalThis.clearTimeout(this.userInteractionEventTimeout); - this.userInteractionEventTimeout = null; - } - } - - private clearCloseInlineMenuOnFilledFieldTimeout() { - if (this.closeInlineMenuOnFilledFieldTimeout) { - globalThis.clearTimeout(this.closeInlineMenuOnFilledFieldTimeout); - } - } - - /** - * Clears the timeout that facilitates recalculating the sub frame offsets. - */ - private clearRecalculateSubFrameOffsetsTimeout() { - if (this.recalculateSubFrameOffsetsTimeout) { - globalThis.clearTimeout(this.recalculateSubFrameOffsetsTimeout); - } - } - private clearFocusInlineMenuListTimeout() { if (this.focusInlineMenuListTimeout) { globalThis.clearTimeout(this.focusInlineMenuListTimeout); @@ -1174,9 +1138,6 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ } private clearAllTimeouts() { - this.clearUserInteractionEventTimeout(); - this.clearCloseInlineMenuOnFilledFieldTimeout(); - this.clearRecalculateSubFrameOffsetsTimeout(); this.clearFocusInlineMenuListTimeout(); this.clearCloseInlineMenuOnRedirectTimeout(); }