From 738bd7e7e573f5c3c25d725a1fdc00f271a84cd6 Mon Sep 17 00:00:00 2001 From: Cesar Gonzalez Date: Tue, 25 Jun 2024 15:08:20 -0500 Subject: [PATCH] [PM-5189] Fixing issue within Safari relating to repositioning elements from outer frame --- .../autofill-overlay-content.service.ts | 29 +++++++++++++++---- apps/browser/src/autofill/utils/index.ts | 17 +++++++++++ libs/common/src/autofill/constants/index.ts | 2 ++ 3 files changed, 42 insertions(+), 6 deletions(-) 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 1061e3bf3aa..ab673c5d849 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,11 @@ 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_HANDLE_REPOSITION, +} from "@bitwarden/common/autofill/constants"; import { FocusedFieldData, @@ -18,7 +22,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, @@ -1048,10 +1057,15 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ * the overlay elements on scroll or resize. */ private setOverlayRepositionEventListeners() { - globalThis.addEventListener(EVENTS.SCROLL, this.handleOverlayRepositionEvent, { + const handler = this.useEventHandlersMemo( + throttle(this.handleOverlayRepositionEvent, 800), + AUTOFILL_OVERLAY_HANDLE_REPOSITION, + ); + globalThis.addEventListener(EVENTS.SCROLL, handler, { capture: true, + passive: true, }); - globalThis.addEventListener(EVENTS.RESIZE, this.handleOverlayRepositionEvent); + globalThis.addEventListener(EVENTS.RESIZE, handler); } /** @@ -1059,10 +1073,13 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ * the overlay elements on scroll or resize. */ private removeOverlayRepositionEventListeners() { - globalThis.removeEventListener(EVENTS.SCROLL, this.handleOverlayRepositionEvent, { + const handler = this.eventHandlersMemo[AUTOFILL_OVERLAY_HANDLE_REPOSITION]; + globalThis.removeEventListener(EVENTS.SCROLL, handler, { capture: true, }); - globalThis.removeEventListener(EVENTS.RESIZE, this.handleOverlayRepositionEvent); + globalThis.removeEventListener(EVENTS.RESIZE, handler); + + delete this.eventHandlersMemo[AUTOFILL_OVERLAY_HANDLE_REPOSITION]; } /** diff --git a/apps/browser/src/autofill/utils/index.ts b/apps/browser/src/autofill/utils/index.ts index 26f984d85ac..08ce1314b5f 100644 --- a/apps/browser/src/autofill/utils/index.ts +++ b/apps/browser/src/autofill/utils/index.ts @@ -330,3 +330,20 @@ export function getPropertyOrAttribute(element: HTMLElement, attributeName: stri return element.getAttribute(attributeName); } + +/** + * Throttles a callback function to run at most once every `limit` milliseconds. + * + * @param callback - The callback function to throttle. + * @param limit - The time in milliseconds to throttle the callback. + */ +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); + } + }; +} diff --git a/libs/common/src/autofill/constants/index.ts b/libs/common/src/autofill/constants/index.ts index 93815be55df..efbd0896428 100644 --- a/libs/common/src/autofill/constants/index.ts +++ b/libs/common/src/autofill/constants/index.ts @@ -54,6 +54,8 @@ export const SEPARATOR_ID = "separator"; export const NOTIFICATION_BAR_LIFESPAN_MS = 150000; // 150 seconds +export const AUTOFILL_OVERLAY_HANDLE_REPOSITION = "autofill-overlay-handle-reposition-event"; + export const AutofillOverlayVisibility = { Off: 0, OnButtonClick: 1,