diff --git a/apps/browser/src/autofill/background/abstractions/overlay.background.ts b/apps/browser/src/autofill/background/abstractions/overlay.background.ts index 7887658a9a..70151719d4 100644 --- a/apps/browser/src/autofill/background/abstractions/overlay.background.ts +++ b/apps/browser/src/autofill/background/abstractions/overlay.background.ts @@ -12,10 +12,11 @@ export type PageDetailsForTab = Record< >; export type SubFrameOffsetData = { - frameId?: number; - url?: string; top: number; left: number; + url?: string; + frameId?: number; + parentFrameIds?: number[]; } | null; export type SubFrameOffsetsForTab = Record< @@ -116,6 +117,8 @@ export type OverlayBackgroundExtensionMessageHandlers = { updateAutofillInlineMenuHidden: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; checkIsAutofillInlineMenuButtonVisible: ({ sender }: BackgroundSenderParam) => void; checkIsAutofillInlineMenuListVisible: ({ sender }: BackgroundSenderParam) => void; + checkShouldRepositionInlineMenu: ({ sender }: BackgroundSenderParam) => boolean; + getCurrentTabFrameId: ({ sender }: BackgroundSenderParam) => number; updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; rebuildSubFrameOffsets: ({ sender }: BackgroundSenderParam) => void; collectPageDetailsResponse: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 05eff398ba..7b124da1e1 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -88,6 +88,8 @@ export class OverlayBackground implements OverlayBackgroundInterface { this.checkIsAutofillInlineMenuButtonVisible(sender), checkIsAutofillInlineMenuListVisible: ({ sender }) => this.checkIsAutofillInlineMenuListVisible(sender), + checkShouldRepositionInlineMenu: ({ sender }) => this.checkShouldRepositionInlineMenu(sender), + getCurrentTabFrameId: ({ sender }) => this.getCurrentFrameId(sender), updateSubFrameData: ({ message, sender }) => this.updateSubFrameData(message, sender), rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender), collectPageDetailsResponse: ({ message, sender }) => this.storePageDetails(message, sender), @@ -256,6 +258,10 @@ export class OverlayBackground implements OverlayBackgroundInterface { pageDetailsMap.set(sender.frameId, pageDetails); } + private getCurrentFrameId(sender: chrome.runtime.MessageSender) { + return sender.frameId; + } + /** * Handles sub frame offset calculations for the given tab and frame id. * Is used in setting the position of the inline menu list and button. @@ -293,7 +299,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { return; } - const subFrameData = { url, top: 0, left: 0 }; + const subFrameData: SubFrameOffsetData = { url, top: 0, left: 0, parentFrameIds: [] }; let frameDetails = await BrowserApi.getFrameDetails({ tabId, frameId }); while (frameDetails && frameDetails.parentFrameId > -1) { @@ -319,6 +325,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { subFrameData.top += subFrameOffset.top; subFrameData.left += subFrameOffset.left; + subFrameData.parentFrameIds.push(frameDetails.parentFrameId); frameDetails = await BrowserApi.getFrameDetails({ tabId, @@ -1005,6 +1012,34 @@ export class OverlayBackground implements OverlayBackgroundInterface { ); } + private checkShouldRepositionInlineMenu(sender: chrome.runtime.MessageSender): boolean { + if ( + !this.focusedFieldData || + sender.tab.id !== this.focusedFieldData.tabId || + !this.isFieldCurrentlyFocused + ) { + return false; + } + + if (this.focusedFieldData.frameId === sender.frameId) { + return true; + } + + const subFrameOffsetsForTab = this.subFrameOffsetsForTab[sender.tab.id]; + if (!subFrameOffsetsForTab) { + return false; + } + + const parentFrameIds = new Set(); + subFrameOffsetsForTab.forEach((subFrameOffsetData) => + subFrameOffsetData.parentFrameIds.forEach((parentFrameId) => + parentFrameIds.add(parentFrameId), + ), + ); + + return parentFrameIds.has(sender.frameId); + } + /** * Responds to the content script's request to check if the inline menu ciphers are populated. * This will return true only if the sender is the focused field's tab and the inline menu 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 d23faf3fab..d265d84652 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts @@ -765,17 +765,18 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ globalThis.removeEventListener(EVENTS.RESIZE, this.handleOverlayRepositionEvent); } + private overlayRepositionTimeout: number | NodeJS.Timeout; + /** * Handles the resize or scroll events that enact * repositioning of existing overlay elements. */ private handleOverlayRepositionEvent = async () => { - this.rebuildSubFrameOffsets(); - - if (!(await this.isInlineMenuButtonVisible()) && !(await this.isInlineMenuListVisible())) { + if (!(await this.sendExtensionMessage("checkShouldRepositionInlineMenu"))) { return; } + this.rebuildSubFrameOffsets(); this.toggleAutofillInlineMenuHidden(true); this.clearUserInteractionEventTimeout(); this.userInteractionEventTimeout = setTimeout(this.triggerOverlayRepositionUpdates, 750); @@ -957,6 +958,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ frameId: message.subFrameId, left: 0, top: 0, + parentFrameIds: [], }, }, "*", @@ -968,10 +970,10 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ return; } - this.calculateSubFramePositioning(event); + void this.calculateSubFramePositioning(event); }; - private calculateSubFramePositioning = (event: MessageEvent) => { + private calculateSubFramePositioning = async (event: MessageEvent) => { const subFrameData = event.data.subFrameData; let subFrameOffsets: SubFrameOffsetData; const iframes = document.querySelectorAll("iframe"); @@ -983,9 +985,11 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ subFrameData.url, subFrameData.frameId, ); + const parentFrameId = await this.sendExtensionMessage("getCurrentTabFrameId"); subFrameData.top += subFrameOffsets.top; subFrameData.left += subFrameOffsets.left; + subFrameData.parentFrameIds.push(parentFrameId); break; }