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 4f6ee8b813..3aa50757f3 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts @@ -3,7 +3,12 @@ import "lit/polyfill-support.js"; import { FocusableElement, tabbable } from "tabbable"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { EVENTS, AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; +import { + EVENTS, + AutofillOverlayVisibility, + AUTOFILL_OVERLAY_ON_SCROLL, + AUTOFILL_OVERLAY_ON_RESIZE, +} from "@bitwarden/common/autofill/constants"; import { FocusedFieldData, @@ -18,7 +23,12 @@ import { import AutofillField from "../models/autofill-field"; import AutofillPageDetails from "../models/autofill-page-details"; import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types"; -import { elementIsFillableFormField, getAttributeBoolean, sendExtensionMessage } from "../utils"; +import { + elementIsFillableFormField, + getAttributeBoolean, + sendExtensionMessage, + throttle, +} from "../utils"; import { AutofillOverlayContentExtensionMessageHandlers, @@ -1011,10 +1021,23 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ * the overlay elements on scroll or resize. */ private setOverlayRepositionEventListeners() { - globalThis.addEventListener(EVENTS.SCROLL, this.handleOverlayRepositionEvent, { - capture: true, - }); - globalThis.addEventListener(EVENTS.RESIZE, this.handleOverlayRepositionEvent); + globalThis.addEventListener( + EVENTS.SCROLL, + this.useEventHandlersMemo( + throttle(this.handleOverlayRepositionEvent, 150), + AUTOFILL_OVERLAY_ON_SCROLL, + ), + { + capture: true, + }, + ); + globalThis.addEventListener( + EVENTS.RESIZE, + this.useEventHandlersMemo( + throttle(this.handleOverlayRepositionEvent, 150), + AUTOFILL_OVERLAY_ON_RESIZE, + ), + ); } /** @@ -1022,10 +1045,20 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ * the overlay elements on scroll or resize. */ private removeOverlayRepositionEventListeners() { - globalThis.removeEventListener(EVENTS.SCROLL, this.handleOverlayRepositionEvent, { - capture: true, - }); - globalThis.removeEventListener(EVENTS.RESIZE, this.handleOverlayRepositionEvent); + globalThis.removeEventListener( + EVENTS.SCROLL, + this.eventHandlersMemo[AUTOFILL_OVERLAY_ON_SCROLL], + { + capture: true, + }, + ); + globalThis.removeEventListener( + EVENTS.RESIZE, + this.eventHandlersMemo[AUTOFILL_OVERLAY_ON_RESIZE], + ); + + delete this.eventHandlersMemo[AUTOFILL_OVERLAY_ON_SCROLL]; + delete this.eventHandlersMemo[AUTOFILL_OVERLAY_ON_RESIZE]; } /** diff --git a/apps/browser/src/autofill/utils/index.ts b/apps/browser/src/autofill/utils/index.ts index 26f984d85a..829cb8a4ee 100644 --- a/apps/browser/src/autofill/utils/index.ts +++ b/apps/browser/src/autofill/utils/index.ts @@ -330,3 +330,14 @@ export function getPropertyOrAttribute(element: HTMLElement, attributeName: stri return element.getAttribute(attributeName); } + +export function throttle(callback: () => void, limit: number) { + let waitingDelay = false; + return function (...args: unknown[]) { + if (!waitingDelay) { + callback.apply(this, args); + waitingDelay = true; + globalThis.setTimeout(() => (waitingDelay = false), limit); + } + }; +}