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 c265ca53b5..43780cc264 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts @@ -8,6 +8,10 @@ import { AutofillOverlayVisibility, AUTOFILL_OVERLAY_ON_SCROLL, AUTOFILL_OVERLAY_ON_RESIZE, + AUTOFILL_OVERLAY_SUB_FRAME_ON_FOCUS, + AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_ENTER, + AUTOFILL_OVERLAY_SUB_FRAME_ON_BLUR, + AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_LEAVE, } from "@bitwarden/common/autofill/constants"; import { @@ -1053,9 +1057,67 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ if (globalThis.window.top === globalThis.window || this.formFieldElements.size < 1) { return; } + this.removeSubFrameFocusOutListeners(); - globalThis.addEventListener(EVENTS.FOCUS, this.handleSubFrameFocusInEvent); - globalThis.document.body.addEventListener(EVENTS.MOUSEENTER, this.handleSubFrameFocusInEvent); + globalThis.addEventListener( + EVENTS.FOCUS, + this.useEventHandlersMemo( + throttle(this.handleSubFrameFocusInEvent, 100), + AUTOFILL_OVERLAY_SUB_FRAME_ON_FOCUS, + ), + ); + globalThis.document.body.addEventListener( + EVENTS.MOUSEENTER, + this.useEventHandlersMemo( + throttle(this.handleSubFrameFocusInEvent, 100), + AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_ENTER, + ), + ); + }; + + private removeRebuildSubFrameOffsetsListeners = () => { + globalThis.removeEventListener( + EVENTS.FOCUS, + this.eventHandlersMemo[AUTOFILL_OVERLAY_SUB_FRAME_ON_FOCUS], + ); + globalThis.document.body.removeEventListener( + EVENTS.MOUSEENTER, + this.eventHandlersMemo[AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_ENTER], + ); + + delete this.eventHandlersMemo[AUTOFILL_OVERLAY_SUB_FRAME_ON_FOCUS]; + delete this.eventHandlersMemo[AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_ENTER]; + }; + + private setupSubFrameFocusOutListeners = () => { + globalThis.addEventListener( + EVENTS.BLUR, + this.useEventHandlersMemo( + throttle(this.setupRebuildSubFrameOffsetsListeners, 100), + AUTOFILL_OVERLAY_SUB_FRAME_ON_BLUR, + ), + ); + globalThis.document.body.addEventListener( + EVENTS.MOUSELEAVE, + this.useEventHandlersMemo( + throttle(this.setupRebuildSubFrameOffsetsListeners, 100), + AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_LEAVE, + ), + ); + }; + + private removeSubFrameFocusOutListeners = () => { + globalThis.removeEventListener( + EVENTS.BLUR, + this.eventHandlersMemo[AUTOFILL_OVERLAY_SUB_FRAME_ON_BLUR], + ); + globalThis.document.body.removeEventListener( + EVENTS.MOUSELEAVE, + this.eventHandlersMemo[AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_LEAVE], + ); + + delete this.eventHandlersMemo[AUTOFILL_OVERLAY_SUB_FRAME_ON_BLUR]; + delete this.eventHandlersMemo[AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_LEAVE]; }; /** @@ -1066,16 +1128,8 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ private handleSubFrameFocusInEvent = () => { void this.sendExtensionMessage("triggerSubFrameFocusInRebuild"); - globalThis.removeEventListener(EVENTS.FOCUS, this.handleSubFrameFocusInEvent); - globalThis.document.body.removeEventListener( - EVENTS.MOUSEENTER, - this.handleSubFrameFocusInEvent, - ); - globalThis.addEventListener(EVENTS.BLUR, this.setupRebuildSubFrameOffsetsListeners); - globalThis.document.body.addEventListener( - EVENTS.MOUSELEAVE, - this.setupRebuildSubFrameOffsetsListeners, - ); + this.removeRebuildSubFrameOffsetsListeners(); + this.setupSubFrameFocusOutListeners(); }; /** @@ -1135,11 +1189,8 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ this.handleVisibilityChangeEvent, ); globalThis.removeEventListener(EVENTS.FOCUSOUT, this.handleFormFieldBlurEvent); - globalThis.removeEventListener(EVENTS.FOCUS, this.handleSubFrameFocusInEvent); - globalThis.document.body.removeEventListener( - EVENTS.MOUSEENTER, - this.handleSubFrameFocusInEvent, - ); this.removeOverlayRepositionEventListeners(); + this.removeRebuildSubFrameOffsetsListeners(); + this.removeSubFrameFocusOutListeners(); } } diff --git a/libs/common/src/autofill/constants/index.ts b/libs/common/src/autofill/constants/index.ts index a4c47925f9..0bbd58a91b 100644 --- a/libs/common/src/autofill/constants/index.ts +++ b/libs/common/src/autofill/constants/index.ts @@ -54,11 +54,17 @@ export const SEPARATOR_ID = "separator"; export const NOTIFICATION_BAR_LIFESPAN_MS = 150000; // 150 seconds +export const AUTOFILL_OVERLAY_ON_SCROLL = "autofill-overlay-scroll-event"; +export const AUTOFILL_OVERLAY_ON_RESIZE = "autofill-overlay-resize-event"; +export const AUTOFILL_OVERLAY_SUB_FRAME_ON_FOCUS = "autofill-overlay-sub-frame-focus-event"; +export const AUTOFILL_OVERLAY_SUB_FRAME_ON_BLUR = "autofill-overlay-sub-frame-blur-event"; +export const AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_ENTER = + "autofill-overlay-sub-frame-on-mouse-enter-event"; +export const AUTOFILL_OVERLAY_SUB_FRAME_ON_MOUSE_LEAVE = + "autofill-overlay-sub-frame-on-mouse-leave-event"; + export const AutofillOverlayVisibility = { Off: 0, OnButtonClick: 1, OnFieldFocus: 2, } as const; - -export const AUTOFILL_OVERLAY_ON_SCROLL = "autofill-overlay-scroll-event"; -export const AUTOFILL_OVERLAY_ON_RESIZE = "autofill-overlay-resize-event";