1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-20 18:23:31 +00:00

[PM-5189] Implementing a methodology for triggering subframe updates from layout-shift

This commit is contained in:
Cesar Gonzalez
2024-06-13 10:44:32 -05:00
parent a30dcbb880
commit 3413450d56
3 changed files with 24 additions and 10 deletions

View File

@@ -65,6 +65,7 @@ export type OverlayBackgroundExtensionMessage = {
subFrameData?: SubFrameOffsetData; subFrameData?: SubFrameOffsetData;
focusedFieldData?: FocusedFieldData; focusedFieldData?: FocusedFieldData;
styles?: Partial<CSSStyleDeclaration>; styles?: Partial<CSSStyleDeclaration>;
triggerInlineMenuPositionUpdate?: boolean;
data?: LockedVaultPendingNotificationsData; data?: LockedVaultPendingNotificationsData;
} & OverlayAddNewItemMessage & } & OverlayAddNewItemMessage &
CloseInlineMenuMessage; CloseInlineMenuMessage;
@@ -120,7 +121,7 @@ export type OverlayBackgroundExtensionMessageHandlers = {
checkShouldRepositionInlineMenu: ({ sender }: BackgroundSenderParam) => boolean; checkShouldRepositionInlineMenu: ({ sender }: BackgroundSenderParam) => boolean;
getCurrentTabFrameId: ({ sender }: BackgroundSenderParam) => number; getCurrentTabFrameId: ({ sender }: BackgroundSenderParam) => number;
updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
rebuildSubFrameOffsets: ({ sender }: BackgroundSenderParam) => void; rebuildSubFrameOffsets: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
destroyAutofillInlineMenuListeners: ({ destroyAutofillInlineMenuListeners: ({
message, message,
sender, sender,

View File

@@ -95,7 +95,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
checkShouldRepositionInlineMenu: ({ sender }) => this.checkShouldRepositionInlineMenu(sender), checkShouldRepositionInlineMenu: ({ sender }) => this.checkShouldRepositionInlineMenu(sender),
getCurrentTabFrameId: ({ sender }) => this.getSenderFrameId(sender), getCurrentTabFrameId: ({ sender }) => this.getSenderFrameId(sender),
updateSubFrameData: ({ message, sender }) => this.updateSubFrameData(message, sender), updateSubFrameData: ({ message, sender }) => this.updateSubFrameData(message, sender),
rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender), rebuildSubFrameOffsets: ({ message, sender }) => this.rebuildSubFrameOffsets(message, sender),
destroyAutofillInlineMenuListeners: ({ message, sender }) => destroyAutofillInlineMenuListeners: ({ message, sender }) =>
this.triggerDestroyInlineMenuListeners(sender.tab, message.subFrameData.frameId), this.triggerDestroyInlineMenuListeners(sender.tab, message.subFrameData.frameId),
collectPageDetailsResponse: ({ message, sender }) => this.storePageDetails(message, sender), collectPageDetailsResponse: ({ message, sender }) => this.storePageDetails(message, sender),
@@ -382,9 +382,13 @@ export class OverlayBackground implements OverlayBackgroundInterface {
* the field currently focused. We trigger a re-calculation of the field's position * the field currently focused. We trigger a re-calculation of the field's position
* and as a result, the sub frame offsets of that frame will be updated. * and as a result, the sub frame offsets of that frame will be updated.
* *
* @param message - The message received from the `rebuildSubFrameOffsets` command
* @param sender - The sender of the message * @param sender - The sender of the message
*/ */
private async rebuildSubFrameOffsets(sender: chrome.runtime.MessageSender) { private async rebuildSubFrameOffsets(
message: OverlayBackgroundExtensionMessage,
sender: chrome.runtime.MessageSender,
) {
if (sender.frameId === this.focusedFieldData?.frameId) { if (sender.frameId === this.focusedFieldData?.frameId) {
return; return;
} }
@@ -406,10 +410,12 @@ export class OverlayBackground implements OverlayBackgroundInterface {
} }
} }
this.updateInlineMenuPositionTimeout = globalThis.setTimeout( if (message.triggerInlineMenuPositionUpdate) {
() => this.updateInlineMenuPositionAfterSubFrameRebuild(sender), this.updateInlineMenuPositionTimeout = globalThis.setTimeout(
650, () => this.updateInlineMenuPositionAfterSubFrameRebuild(sender),
); 650,
);
}
} }
/** /**

View File

@@ -43,6 +43,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
private focusedFieldData: FocusedFieldData; private focusedFieldData: FocusedFieldData;
private userInteractionEventTimeout: number | NodeJS.Timeout; private userInteractionEventTimeout: number | NodeJS.Timeout;
private recalculateSubFrameOffsetsTimeout: number | NodeJS.Timeout; private recalculateSubFrameOffsetsTimeout: number | NodeJS.Timeout;
private performanceObserver: PerformanceObserver;
private autofillFieldKeywordsMap: WeakMap<AutofillField, string> = new WeakMap(); private autofillFieldKeywordsMap: WeakMap<AutofillField, string> = new WeakMap();
private eventHandlersMemo: { [key: string]: EventListener } = {}; private eventHandlersMemo: { [key: string]: EventListener } = {};
private readonly extensionMessageHandlers: AutofillOverlayContentExtensionMessageHandlers = { private readonly extensionMessageHandlers: AutofillOverlayContentExtensionMessageHandlers = {
@@ -786,6 +787,8 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
capture: true, capture: true,
}); });
globalThis.addEventListener(EVENTS.RESIZE, this.handleOverlayRepositionEvent); globalThis.addEventListener(EVENTS.RESIZE, this.handleOverlayRepositionEvent);
this.performanceObserver = new PerformanceObserver(() => this.rebuildSubFrameOffsets(0, false));
this.performanceObserver.observe({ type: "layout-shift", buffered: true });
} }
/** /**
@@ -820,11 +823,14 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
/** /**
* Triggers a rebuild of a sub frame's offsets within the tab. * Triggers a rebuild of a sub frame's offsets within the tab.
*/ */
private rebuildSubFrameOffsets() { private rebuildSubFrameOffsets(delay: number = 150, triggerInlineMenuPositionUpdate = true) {
this.clearRecalculateSubFrameOffsetsTimeout(); this.clearRecalculateSubFrameOffsetsTimeout();
this.recalculateSubFrameOffsetsTimeout = globalThis.setTimeout( this.recalculateSubFrameOffsetsTimeout = globalThis.setTimeout(
() => void this.sendExtensionMessage("rebuildSubFrameOffsets"), () =>
150, void this.sendExtensionMessage("rebuildSubFrameOffsets", {
triggerInlineMenuPositionUpdate,
}),
delay,
); );
} }
@@ -1161,6 +1167,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
this.handleVisibilityChangeEvent, this.handleVisibilityChangeEvent,
); );
globalThis.removeEventListener(EVENTS.FOCUSOUT, this.handleFormFieldBlurEvent); globalThis.removeEventListener(EVENTS.FOCUSOUT, this.handleFormFieldBlurEvent);
this.performanceObserver?.disconnect();
this.removeOverlayRepositionEventListeners(); this.removeOverlayRepositionEventListeners();
} }
} }