mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-24 21:41:33 +01:00
[PM-5189] Working through further issues on positioning of inline menu
This commit is contained in:
parent
582cdf17dd
commit
4114b538e5
@ -65,6 +65,7 @@ export type OverlayBackgroundExtensionMessage = {
|
|||||||
details?: AutofillPageDetails;
|
details?: AutofillPageDetails;
|
||||||
isFieldCurrentlyFocused?: boolean;
|
isFieldCurrentlyFocused?: boolean;
|
||||||
isFieldCurrentlyFilling?: boolean;
|
isFieldCurrentlyFilling?: boolean;
|
||||||
|
isInlineMenuElementVisible?: boolean;
|
||||||
subFrameData?: SubFrameOffsetData;
|
subFrameData?: SubFrameOffsetData;
|
||||||
focusedFieldData?: FocusedFieldData;
|
focusedFieldData?: FocusedFieldData;
|
||||||
styles?: Partial<CSSStyleDeclaration>;
|
styles?: Partial<CSSStyleDeclaration>;
|
||||||
@ -119,9 +120,12 @@ export type OverlayBackgroundExtensionMessageHandlers = {
|
|||||||
message,
|
message,
|
||||||
sender,
|
sender,
|
||||||
}: BackgroundOnMessageHandlerParams) => Promise<void>;
|
}: BackgroundOnMessageHandlerParams) => Promise<void>;
|
||||||
toggleAutofillInlineMenuHidden: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
|
updateAutofillInlineMenuElementIsVisibleStatus: ({
|
||||||
checkIsAutofillInlineMenuButtonVisible: ({ sender }: BackgroundSenderParam) => void;
|
message,
|
||||||
checkIsAutofillInlineMenuListVisible: ({ sender }: BackgroundSenderParam) => void;
|
sender,
|
||||||
|
}: BackgroundOnMessageHandlerParams) => void;
|
||||||
|
checkIsAutofillInlineMenuButtonVisible: () => void;
|
||||||
|
checkIsAutofillInlineMenuListVisible: () => void;
|
||||||
getCurrentTabFrameId: ({ sender }: BackgroundSenderParam) => number;
|
getCurrentTabFrameId: ({ sender }: BackgroundSenderParam) => number;
|
||||||
updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
|
updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
|
||||||
triggerSubFrameFocusInRebuild: ({ sender }: BackgroundSenderParam) => void;
|
triggerSubFrameFocusInRebuild: ({ sender }: BackgroundSenderParam) => void;
|
||||||
|
@ -519,9 +519,10 @@ describe("OverlayBackground", () => {
|
|||||||
await flushPromises();
|
await flushPromises();
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
sender = mock<chrome.runtime.MessageSender>({ tab, frameId: middleFrameId });
|
sender = mock<chrome.runtime.MessageSender>({ tab, frameId: middleFrameId });
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
|
await initOverlayElementPorts();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips updating the position of either inline menu element if a field is not currently focused", async () => {
|
it("skips updating the position of either inline menu element if a field is not currently focused", async () => {
|
||||||
@ -559,11 +560,10 @@ describe("OverlayBackground", () => {
|
|||||||
sendMockExtensionMessage({ command: "triggerAutofillOverlayReposition" }, sender);
|
sendMockExtensionMessage({ command: "triggerAutofillOverlayReposition" }, sender);
|
||||||
await flushUpdateInlineMenuPromises();
|
await flushUpdateInlineMenuPromises();
|
||||||
|
|
||||||
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({
|
||||||
sender.tab,
|
command: "toggleAutofillInlineMenuHidden",
|
||||||
{ command: "toggleAutofillInlineMenuHidden", isInlineMenuHidden: true },
|
styles: { display: "none" },
|
||||||
{ frameId: 0 },
|
});
|
||||||
);
|
|
||||||
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
||||||
sender.tab,
|
sender.tab,
|
||||||
{
|
{
|
||||||
@ -1312,73 +1312,35 @@ describe("OverlayBackground", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("toggleAutofillInlineMenuHidden message handler", () => {
|
describe("checkIsAutofillInlineMenuButtonVisible message handler", () => {
|
||||||
beforeEach(async () => {
|
it("returns true when the inline menu button is visible", async () => {
|
||||||
await initOverlayElementPorts();
|
overlayBackground["isInlineMenuButtonVisible"] = true;
|
||||||
});
|
|
||||||
|
|
||||||
it("returns early if the sender tab is not equal to the focused field tab", async () => {
|
|
||||||
const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
|
const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
|
||||||
const focusedFieldData = createFocusedFieldDataMock({ tabId: 2 });
|
|
||||||
sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData });
|
|
||||||
|
|
||||||
sendMockExtensionMessage({ command: "toggleAutofillInlineMenuHidden" }, sender);
|
sendMockExtensionMessage(
|
||||||
|
{ command: "checkIsAutofillInlineMenuButtonVisible" },
|
||||||
expect(tabsSendMessageSpy).not.toHaveBeenCalled();
|
sender,
|
||||||
});
|
sendResponse,
|
||||||
|
);
|
||||||
it("posts a message to the overlay button and list which hides the menu", async () => {
|
|
||||||
const message = {
|
|
||||||
command: "toggleAutofillInlineMenuHidden",
|
|
||||||
isInlineMenuHidden: true,
|
|
||||||
setTransparentInlineMenu: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
sendMockExtensionMessage(message);
|
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({
|
expect(sendResponse).toHaveBeenCalledWith(true);
|
||||||
command: "toggleAutofillInlineMenuHidden",
|
|
||||||
styles: {
|
|
||||||
display: "none",
|
|
||||||
opacity: "1",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(listPortSpy.postMessage).toHaveBeenCalledWith({
|
|
||||||
command: "toggleAutofillInlineMenuHidden",
|
|
||||||
styles: {
|
|
||||||
display: "none",
|
|
||||||
opacity: "1",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("checkIsAutofillInlineMenuButtonVisible", () => {
|
|
||||||
it("sends a message to the top frame of the tab to identify if the inline menu button is visible", () => {
|
|
||||||
const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
|
|
||||||
|
|
||||||
sendMockExtensionMessage({ command: "checkIsAutofillInlineMenuButtonVisible" }, sender);
|
|
||||||
|
|
||||||
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
|
||||||
sender.tab,
|
|
||||||
{ command: "checkIsAutofillInlineMenuButtonVisible" },
|
|
||||||
{ frameId: 0 },
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("checkIsAutofillInlineMenuListVisible message handler", () => {
|
describe("checkIsAutofillInlineMenuListVisible message handler", () => {
|
||||||
it("sends a message to the top frame of the tab to identify if the inline menu list is visible", () => {
|
it("returns true when the inline menu list is visible", async () => {
|
||||||
|
overlayBackground["isInlineMenuListVisible"] = true;
|
||||||
const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
|
const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
|
||||||
|
|
||||||
sendMockExtensionMessage({ command: "checkIsAutofillInlineMenuListVisible" }, sender);
|
sendMockExtensionMessage(
|
||||||
|
|
||||||
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
|
||||||
sender.tab,
|
|
||||||
{ command: "checkIsAutofillInlineMenuListVisible" },
|
{ command: "checkIsAutofillInlineMenuListVisible" },
|
||||||
{ frameId: 0 },
|
sender,
|
||||||
|
sendResponse,
|
||||||
);
|
);
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
expect(sendResponse).toHaveBeenCalledWith(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -74,6 +74,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
private focusedFieldData: FocusedFieldData;
|
private focusedFieldData: FocusedFieldData;
|
||||||
private isFieldCurrentlyFocused: boolean = false;
|
private isFieldCurrentlyFocused: boolean = false;
|
||||||
private isFieldCurrentlyFilling: boolean = false;
|
private isFieldCurrentlyFilling: boolean = false;
|
||||||
|
private isInlineMenuButtonVisible: boolean = false;
|
||||||
|
private isInlineMenuListVisible: boolean = false;
|
||||||
private iconsServerUrl: string;
|
private iconsServerUrl: string;
|
||||||
private readonly extensionMessageHandlers: OverlayBackgroundExtensionMessageHandlers = {
|
private readonly extensionMessageHandlers: OverlayBackgroundExtensionMessageHandlers = {
|
||||||
autofillOverlayElementClosed: ({ message, sender }) =>
|
autofillOverlayElementClosed: ({ message, sender }) =>
|
||||||
@ -94,11 +96,10 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
focusAutofillInlineMenuList: () => this.focusInlineMenuList(),
|
focusAutofillInlineMenuList: () => this.focusInlineMenuList(),
|
||||||
updateAutofillInlineMenuPosition: ({ message, sender }) =>
|
updateAutofillInlineMenuPosition: ({ message, sender }) =>
|
||||||
this.updateInlineMenuPosition(message, sender),
|
this.updateInlineMenuPosition(message, sender),
|
||||||
toggleAutofillInlineMenuHidden: ({ message, sender }) =>
|
updateAutofillInlineMenuElementIsVisibleStatus: ({ message, sender }) =>
|
||||||
this.toggleInlineMenuHidden(message, sender),
|
this.updateInlineMenuElementIsVisibleStatus(message, sender),
|
||||||
checkIsAutofillInlineMenuButtonVisible: ({ sender }) =>
|
checkIsAutofillInlineMenuButtonVisible: () => this.checkIsInlineMenuButtonVisible(),
|
||||||
this.checkIsInlineMenuButtonVisible(sender),
|
checkIsAutofillInlineMenuListVisible: () => this.checkIsInlineMenuListVisible(),
|
||||||
checkIsAutofillInlineMenuListVisible: ({ sender }) => this.checkIsInlineMenuListVisible(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),
|
||||||
triggerSubFrameFocusInRebuild: ({ sender }) => this.triggerSubFrameFocusInRebuild(sender),
|
triggerSubFrameFocusInRebuild: ({ sender }) => this.triggerSubFrameFocusInRebuild(sender),
|
||||||
@ -453,7 +454,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await this.checkIsInlineMenuButtonVisible(sender))) {
|
if (!this.checkIsInlineMenuButtonVisible()) {
|
||||||
void this.toggleInlineMenuHidden(
|
void this.toggleInlineMenuHidden(
|
||||||
{ isInlineMenuHidden: false, setTransparentInlineMenu: true },
|
{ isInlineMenuHidden: false, setTransparentInlineMenu: true },
|
||||||
sender,
|
sender,
|
||||||
@ -519,7 +520,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
* if it is open, otherwise it will check the inline menu button.
|
* if it is open, otherwise it will check the inline menu button.
|
||||||
*/
|
*/
|
||||||
private checkInlineMenuFocused(sender: chrome.runtime.MessageSender) {
|
private checkInlineMenuFocused(sender: chrome.runtime.MessageSender) {
|
||||||
if (sender.tab.id !== this.focusedFieldData?.tabId) {
|
if (!this.senderTabHasFocusedField(sender)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,6 +562,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
const sendOptions = { frameId: 0 };
|
const sendOptions = { frameId: 0 };
|
||||||
if (forceCloseInlineMenu) {
|
if (forceCloseInlineMenu) {
|
||||||
void BrowserApi.tabSendMessage(sender.tab, { command, overlayElement }, sendOptions);
|
void BrowserApi.tabSendMessage(sender.tab, { command, overlayElement }, sendOptions);
|
||||||
|
this.isInlineMenuButtonVisible = false;
|
||||||
|
this.isInlineMenuListVisible = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,9 +577,18 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
{ command, overlayElement: AutofillOverlayElement.List },
|
{ command, overlayElement: AutofillOverlayElement.List },
|
||||||
sendOptions,
|
sendOptions,
|
||||||
);
|
);
|
||||||
|
this.isInlineMenuListVisible = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (overlayElement === AutofillOverlayElement.Button) {
|
||||||
|
this.isInlineMenuButtonVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overlayElement === AutofillOverlayElement.List) {
|
||||||
|
this.isInlineMenuListVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
void BrowserApi.tabSendMessage(sender.tab, { command, overlayElement }, sendOptions);
|
void BrowserApi.tabSendMessage(sender.tab, { command, overlayElement }, sendOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,21 +631,24 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
{ overlayElement }: OverlayBackgroundExtensionMessage,
|
{ overlayElement }: OverlayBackgroundExtensionMessage,
|
||||||
sender: chrome.runtime.MessageSender,
|
sender: chrome.runtime.MessageSender,
|
||||||
) {
|
) {
|
||||||
if (sender.tab.id !== this.focusedFieldData?.tabId) {
|
if (!this.senderTabHasFocusedField(sender)) {
|
||||||
this.expiredPorts.forEach((port) => port.disconnect());
|
this.expiredPorts.forEach((port) => port.disconnect());
|
||||||
this.expiredPorts = [];
|
this.expiredPorts = [];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlayElement === AutofillOverlayElement.Button) {
|
if (overlayElement === AutofillOverlayElement.Button) {
|
||||||
this.inlineMenuButtonPort?.disconnect();
|
this.inlineMenuButtonPort?.disconnect();
|
||||||
this.inlineMenuButtonPort = null;
|
this.inlineMenuButtonPort = null;
|
||||||
|
this.isInlineMenuButtonVisible = false;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.inlineMenuListPort?.disconnect();
|
this.inlineMenuListPort?.disconnect();
|
||||||
this.inlineMenuListPort = null;
|
this.inlineMenuListPort = null;
|
||||||
|
this.isInlineMenuListVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -647,7 +662,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
{ overlayElement }: { overlayElement?: string },
|
{ overlayElement }: { overlayElement?: string },
|
||||||
sender: chrome.runtime.MessageSender,
|
sender: chrome.runtime.MessageSender,
|
||||||
) {
|
) {
|
||||||
if (!overlayElement || sender.tab.id !== this.focusedFieldData?.tabId) {
|
if (!overlayElement || !this.senderTabHasFocusedField(sender)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,6 +701,32 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
this.startInlineMenuFadeIn();
|
this.startInlineMenuFadeIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers an update of the inline menu's visibility after the top level frame
|
||||||
|
* appends the element to the DOM.
|
||||||
|
*
|
||||||
|
* @param message - The message received from the content script
|
||||||
|
* @param sender - The sender of the port message
|
||||||
|
*/
|
||||||
|
private updateInlineMenuElementIsVisibleStatus(
|
||||||
|
message: OverlayBackgroundExtensionMessage,
|
||||||
|
sender: chrome.runtime.MessageSender,
|
||||||
|
) {
|
||||||
|
if (!this.senderTabHasFocusedField(sender)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { overlayElement, isInlineMenuElementVisible } = message;
|
||||||
|
if (overlayElement === AutofillOverlayElement.Button) {
|
||||||
|
this.isInlineMenuButtonVisible = isInlineMenuElementVisible;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overlayElement === AutofillOverlayElement.List) {
|
||||||
|
this.isInlineMenuListVisible = isInlineMenuElementVisible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles updating the opacity of both the inline menu button and list.
|
* Handles updating the opacity of both the inline menu button and list.
|
||||||
* This is used to simultaneously fade in the inline menu elements.
|
* This is used to simultaneously fade in the inline menu elements.
|
||||||
@ -797,7 +838,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
{ isInlineMenuHidden, setTransparentInlineMenu }: ToggleInlineMenuHiddenMessage,
|
{ isInlineMenuHidden, setTransparentInlineMenu }: ToggleInlineMenuHiddenMessage,
|
||||||
sender: chrome.runtime.MessageSender,
|
sender: chrome.runtime.MessageSender,
|
||||||
) {
|
) {
|
||||||
if (sender.tab.id !== this.focusedFieldData?.tabId) {
|
if (!this.senderTabHasFocusedField(sender)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -810,15 +851,16 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
styles = { ...styles, opacity };
|
styles = { ...styles, opacity };
|
||||||
}
|
}
|
||||||
|
|
||||||
await BrowserApi.tabSendMessage(
|
|
||||||
sender.tab,
|
|
||||||
{ command: "toggleAutofillInlineMenuHidden", isInlineMenuHidden },
|
|
||||||
{ frameId: 0 },
|
|
||||||
);
|
|
||||||
|
|
||||||
const portMessage = { command: "toggleAutofillInlineMenuHidden", styles };
|
const portMessage = { command: "toggleAutofillInlineMenuHidden", styles };
|
||||||
this.inlineMenuButtonPort?.postMessage(portMessage);
|
if (this.inlineMenuButtonPort) {
|
||||||
this.inlineMenuListPort?.postMessage(portMessage);
|
this.isInlineMenuButtonVisible = !isInlineMenuHidden;
|
||||||
|
this.inlineMenuButtonPort.postMessage(portMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.inlineMenuListPort) {
|
||||||
|
this.isInlineMenuListVisible = !isInlineMenuHidden;
|
||||||
|
this.inlineMenuListPort.postMessage(portMessage);
|
||||||
|
}
|
||||||
|
|
||||||
if (setTransparentInlineMenu) {
|
if (setTransparentInlineMenu) {
|
||||||
this.startInlineMenuFadeIn();
|
this.startInlineMenuFadeIn();
|
||||||
@ -1010,7 +1052,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
* @param sender - The sender of the port message
|
* @param sender - The sender of the port message
|
||||||
*/
|
*/
|
||||||
private getNewVaultItemDetails({ sender }: chrome.runtime.Port) {
|
private getNewVaultItemDetails({ sender }: chrome.runtime.Port) {
|
||||||
if (sender.tab.id !== this.focusedFieldData.tabId) {
|
if (!this.senderTabHasFocusedField(sender)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1095,33 +1137,17 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message to the top level frame of the sender to check if the inline menu button is visible.
|
* Returns the visibility status of the inline menu button.
|
||||||
*
|
|
||||||
* @param sender - The sender of the message
|
|
||||||
*/
|
*/
|
||||||
private async checkIsInlineMenuButtonVisible(
|
private checkIsInlineMenuButtonVisible(): boolean {
|
||||||
sender: chrome.runtime.MessageSender,
|
return this.isInlineMenuButtonVisible;
|
||||||
): Promise<boolean> {
|
|
||||||
return await BrowserApi.tabSendMessage(
|
|
||||||
sender.tab,
|
|
||||||
{ command: "checkIsAutofillInlineMenuButtonVisible" },
|
|
||||||
{ frameId: 0 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message to the top level frame of the sender to check if the inline menu list is visible.
|
* Returns the visibility status of the inline menu list.
|
||||||
*
|
|
||||||
* @param sender - The sender of the message
|
|
||||||
*/
|
*/
|
||||||
private async checkIsInlineMenuListVisible(
|
private checkIsInlineMenuListVisible(): boolean {
|
||||||
sender: chrome.runtime.MessageSender,
|
return this.isInlineMenuListVisible;
|
||||||
): Promise<boolean> {
|
|
||||||
return await BrowserApi.tabSendMessage(
|
|
||||||
sender.tab,
|
|
||||||
{ command: "checkIsAutofillInlineMenuListVisible" },
|
|
||||||
{ frameId: 0 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1132,7 +1158,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
* @param sender - The sender of the message
|
* @param sender - The sender of the message
|
||||||
*/
|
*/
|
||||||
private checkIsInlineMenuCiphersPopulated(sender: chrome.runtime.MessageSender) {
|
private checkIsInlineMenuCiphersPopulated(sender: chrome.runtime.MessageSender) {
|
||||||
return sender.tab.id === this.focusedFieldData.tabId && this.inlineMenuCiphers.size > 0;
|
return this.senderTabHasFocusedField(sender) && this.inlineMenuCiphers.size > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1166,7 +1192,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
* @param sender - The sender of the message
|
* @param sender - The sender of the message
|
||||||
*/
|
*/
|
||||||
private checkShouldRepositionInlineMenu(sender: chrome.runtime.MessageSender): boolean {
|
private checkShouldRepositionInlineMenu(sender: chrome.runtime.MessageSender): boolean {
|
||||||
if (!this.focusedFieldData || sender.tab.id !== this.focusedFieldData.tabId) {
|
if (!this.focusedFieldData || !this.senderTabHasFocusedField(sender)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1186,6 +1212,15 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies if the sender tab is the same as the focused field's tab.
|
||||||
|
*
|
||||||
|
* @param sender - The sender of the message
|
||||||
|
*/
|
||||||
|
private senderTabHasFocusedField(sender: chrome.runtime.MessageSender) {
|
||||||
|
return sender.tab.id === this.focusedFieldData?.tabId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers when a scroll or resize event occurs within a tab. Will reposition the inline menu
|
* Triggers when a scroll or resize event occurs within a tab. Will reposition the inline menu
|
||||||
* if the focused field is within the viewport.
|
* if the focused field is within the viewport.
|
||||||
@ -1448,10 +1483,12 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
private handlePortOnDisconnect = (port: chrome.runtime.Port) => {
|
private handlePortOnDisconnect = (port: chrome.runtime.Port) => {
|
||||||
if (port.name === AutofillOverlayPort.List) {
|
if (port.name === AutofillOverlayPort.List) {
|
||||||
this.inlineMenuListPort = null;
|
this.inlineMenuListPort = null;
|
||||||
|
this.isInlineMenuListVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port.name === AutofillOverlayPort.Button) {
|
if (port.name === AutofillOverlayPort.Button) {
|
||||||
this.inlineMenuButtonPort = null;
|
this.inlineMenuButtonPort = null;
|
||||||
|
this.isInlineMenuButtonVisible = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
|
|
||||||
|
import { AutofillOverlayElementType } from "../../enums/autofill-overlay.enum";
|
||||||
import AutofillScript from "../../models/autofill-script";
|
import AutofillScript from "../../models/autofill-script";
|
||||||
|
|
||||||
export type AutofillExtensionMessage = {
|
export type AutofillExtensionMessage = {
|
||||||
@ -13,7 +14,7 @@ export type AutofillExtensionMessage = {
|
|||||||
pageDetailsUrl?: string;
|
pageDetailsUrl?: string;
|
||||||
ciphers?: any;
|
ciphers?: any;
|
||||||
isInlineMenuHidden?: boolean;
|
isInlineMenuHidden?: boolean;
|
||||||
overlayElement?: string;
|
overlayElement?: AutofillOverlayElementType;
|
||||||
isFocusingFieldElement?: boolean;
|
isFocusingFieldElement?: boolean;
|
||||||
authStatus?: AuthenticationStatus;
|
authStatus?: AuthenticationStatus;
|
||||||
isOpeningFullInlineMenu?: boolean;
|
isOpeningFullInlineMenu?: boolean;
|
||||||
|
@ -3,6 +3,9 @@ export const AutofillOverlayElement = {
|
|||||||
List: "autofill-inline-menu-list",
|
List: "autofill-inline-menu-list",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export type AutofillOverlayElementType =
|
||||||
|
(typeof AutofillOverlayElement)[keyof typeof AutofillOverlayElement];
|
||||||
|
|
||||||
export const AutofillOverlayPort = {
|
export const AutofillOverlayPort = {
|
||||||
Button: "autofill-inline-menu-button-port",
|
Button: "autofill-inline-menu-button-port",
|
||||||
ButtonMessageConnector: "autofill-inline-menu-button-message-connector",
|
ButtonMessageConnector: "autofill-inline-menu-button-message-connector",
|
||||||
|
@ -4,9 +4,6 @@ export type InlineMenuExtensionMessageHandlers = {
|
|||||||
[key: string]: CallableFunction;
|
[key: string]: CallableFunction;
|
||||||
closeAutofillInlineMenu: ({ message }: AutofillExtensionMessageParam) => void;
|
closeAutofillInlineMenu: ({ message }: AutofillExtensionMessageParam) => void;
|
||||||
appendAutofillInlineMenuToDom: ({ message }: AutofillExtensionMessageParam) => Promise<void>;
|
appendAutofillInlineMenuToDom: ({ message }: AutofillExtensionMessageParam) => Promise<void>;
|
||||||
toggleAutofillInlineMenuHidden: ({ message }: AutofillExtensionMessageParam) => void;
|
|
||||||
checkIsAutofillInlineMenuButtonVisible: () => boolean;
|
|
||||||
checkIsAutofillInlineMenuListVisible: () => boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface AutofillInlineMenuContentService {
|
export interface AutofillInlineMenuContentService {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { mock } from "jest-mock-extended";
|
|
||||||
|
|
||||||
import AutofillInit from "../../../content/autofill-init";
|
import AutofillInit from "../../../content/autofill-init";
|
||||||
import { AutofillOverlayElement } from "../../../enums/autofill-overlay.enum";
|
import { AutofillOverlayElement } from "../../../enums/autofill-overlay.enum";
|
||||||
import { createMutationRecordMock } from "../../../spec/autofill-mocks";
|
import { createMutationRecordMock } from "../../../spec/autofill-mocks";
|
||||||
@ -13,7 +11,6 @@ describe("AutofillInlineMenuContentService", () => {
|
|||||||
let autofillInit: AutofillInit;
|
let autofillInit: AutofillInit;
|
||||||
let sendExtensionMessageSpy: jest.SpyInstance;
|
let sendExtensionMessageSpy: jest.SpyInstance;
|
||||||
let observeBodyMutationsSpy: jest.SpyInstance;
|
let observeBodyMutationsSpy: jest.SpyInstance;
|
||||||
const sendResponseSpy = jest.fn();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
globalThis.document.body.innerHTML = "";
|
globalThis.document.body.innerHTML = "";
|
||||||
@ -141,76 +138,6 @@ describe("AutofillInlineMenuContentService", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("toggleAutofillInlineMenuHidden message handler", () => {
|
|
||||||
it("sets the inline elements as hidden if the elements do not exist", () => {
|
|
||||||
sendMockExtensionMessage({
|
|
||||||
command: "toggleAutofillInlineMenuHidden",
|
|
||||||
isInlineMenuHidden: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(autofillInlineMenuContentService["isButtonVisible"]).toBe(false);
|
|
||||||
expect(autofillInlineMenuContentService["isListVisible"]).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets the inline elements as visible", () => {
|
|
||||||
autofillInlineMenuContentService["buttonElement"] = document.createElement("div");
|
|
||||||
autofillInlineMenuContentService["listElement"] = document.createElement("div");
|
|
||||||
|
|
||||||
sendMockExtensionMessage({
|
|
||||||
command: "toggleAutofillInlineMenuHidden",
|
|
||||||
isInlineMenuHidden: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(autofillInlineMenuContentService["isButtonVisible"]).toBe(true);
|
|
||||||
expect(autofillInlineMenuContentService["isListVisible"]).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets the inline elements as hidden", () => {
|
|
||||||
autofillInlineMenuContentService["buttonElement"] = document.createElement("div");
|
|
||||||
autofillInlineMenuContentService["listElement"] = document.createElement("div");
|
|
||||||
autofillInlineMenuContentService["isButtonVisible"] = true;
|
|
||||||
autofillInlineMenuContentService["isListVisible"] = true;
|
|
||||||
|
|
||||||
sendMockExtensionMessage({
|
|
||||||
command: "toggleAutofillInlineMenuHidden",
|
|
||||||
isInlineMenuHidden: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(autofillInlineMenuContentService["isButtonVisible"]).toBe(false);
|
|
||||||
expect(autofillInlineMenuContentService["isListVisible"]).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("checkIsAutofillInlineMenuButtonVisible message handler", () => {
|
|
||||||
it("returns true if the inline menu button is visible", async () => {
|
|
||||||
autofillInlineMenuContentService["isButtonVisible"] = true;
|
|
||||||
|
|
||||||
sendMockExtensionMessage(
|
|
||||||
{ command: "checkIsAutofillInlineMenuButtonVisible" },
|
|
||||||
mock<chrome.runtime.MessageSender>(),
|
|
||||||
sendResponseSpy,
|
|
||||||
);
|
|
||||||
await flushPromises();
|
|
||||||
|
|
||||||
expect(sendResponseSpy).toHaveBeenCalledWith(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("checkIsAutofillInlineMenuListVisible message handler", () => {
|
|
||||||
it("returns true if the inline menu list is visible", async () => {
|
|
||||||
autofillInlineMenuContentService["isListVisible"] = true;
|
|
||||||
|
|
||||||
sendMockExtensionMessage(
|
|
||||||
{ command: "checkIsAutofillInlineMenuListVisible" },
|
|
||||||
mock<chrome.runtime.MessageSender>(),
|
|
||||||
sendResponseSpy,
|
|
||||||
);
|
|
||||||
await flushPromises();
|
|
||||||
|
|
||||||
expect(sendResponseSpy).toHaveBeenCalledWith(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("handleInlineMenuElementMutationObserverUpdate", () => {
|
describe("handleInlineMenuElementMutationObserverUpdate", () => {
|
||||||
@ -295,6 +222,7 @@ describe("AutofillInlineMenuContentService", () => {
|
|||||||
describe("handleBodyElementMutationObserverUpdate", () => {
|
describe("handleBodyElementMutationObserverUpdate", () => {
|
||||||
let buttonElement: HTMLElement;
|
let buttonElement: HTMLElement;
|
||||||
let listElement: HTMLElement;
|
let listElement: HTMLElement;
|
||||||
|
let isInlineMenuListVisibleSpy: jest.SpyInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.body.innerHTML = `
|
document.body.innerHTML = `
|
||||||
@ -305,7 +233,9 @@ describe("AutofillInlineMenuContentService", () => {
|
|||||||
listElement = document.querySelector(".overlay-list") as HTMLElement;
|
listElement = document.querySelector(".overlay-list") as HTMLElement;
|
||||||
autofillInlineMenuContentService["buttonElement"] = buttonElement;
|
autofillInlineMenuContentService["buttonElement"] = buttonElement;
|
||||||
autofillInlineMenuContentService["listElement"] = listElement;
|
autofillInlineMenuContentService["listElement"] = listElement;
|
||||||
autofillInlineMenuContentService["isListVisible"] = true;
|
isInlineMenuListVisibleSpy = jest
|
||||||
|
.spyOn(autofillInlineMenuContentService as any, "isInlineMenuListVisible")
|
||||||
|
.mockResolvedValue(true);
|
||||||
jest.spyOn(globalThis.document.body, "insertBefore");
|
jest.spyOn(globalThis.document.body, "insertBefore");
|
||||||
jest
|
jest
|
||||||
.spyOn(
|
.spyOn(
|
||||||
@ -315,16 +245,16 @@ describe("AutofillInlineMenuContentService", () => {
|
|||||||
.mockReturnValue(false);
|
.mockReturnValue(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips handling the mutation if the overlay elements are not present in the DOM", () => {
|
it("skips handling the mutation if the overlay elements are not present in the DOM", async () => {
|
||||||
autofillInlineMenuContentService["buttonElement"] = undefined;
|
autofillInlineMenuContentService["buttonElement"] = undefined;
|
||||||
autofillInlineMenuContentService["listElement"] = undefined;
|
autofillInlineMenuContentService["listElement"] = undefined;
|
||||||
|
|
||||||
autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
await autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
||||||
|
|
||||||
expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled();
|
expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips handling the mutation if excessive mutations are being triggered", () => {
|
it("skips handling the mutation if excessive mutations are being triggered", async () => {
|
||||||
jest
|
jest
|
||||||
.spyOn(
|
.spyOn(
|
||||||
autofillInlineMenuContentService as any,
|
autofillInlineMenuContentService as any,
|
||||||
@ -332,31 +262,31 @@ describe("AutofillInlineMenuContentService", () => {
|
|||||||
)
|
)
|
||||||
.mockReturnValue(true);
|
.mockReturnValue(true);
|
||||||
|
|
||||||
autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
await autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
||||||
|
|
||||||
expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled();
|
expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips re-arranging the DOM elements if the last child of the body is the overlay list and the second to last child of the body is the overlay button", () => {
|
it("skips re-arranging the DOM elements if the last child of the body is the overlay list and the second to last child of the body is the overlay button", async () => {
|
||||||
autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
await autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
||||||
|
|
||||||
expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled();
|
expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips re-arranging the DOM elements if the last child is the overlay button and the overlay list is not visible", () => {
|
it("skips re-arranging the DOM elements if the last child is the overlay button and the overlay list is not visible", async () => {
|
||||||
listElement.remove();
|
listElement.remove();
|
||||||
autofillInlineMenuContentService["isListVisible"] = false;
|
isInlineMenuListVisibleSpy.mockResolvedValue(false);
|
||||||
|
|
||||||
autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
await autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
||||||
|
|
||||||
expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled();
|
expect(globalThis.document.body.insertBefore).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("positions the overlay button before the overlay list if an element has inserted itself after the button element", () => {
|
it("positions the overlay button before the overlay list if an element has inserted itself after the button element", async () => {
|
||||||
const injectedElement = document.createElement("div");
|
const injectedElement = document.createElement("div");
|
||||||
document.body.insertBefore(injectedElement, listElement);
|
document.body.insertBefore(injectedElement, listElement);
|
||||||
|
|
||||||
autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
await autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
||||||
|
|
||||||
expect(globalThis.document.body.insertBefore).toHaveBeenCalledWith(
|
expect(globalThis.document.body.insertBefore).toHaveBeenCalledWith(
|
||||||
buttonElement,
|
buttonElement,
|
||||||
@ -364,10 +294,10 @@ describe("AutofillInlineMenuContentService", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("positions the overlay button before the overlay list if the elements have inserted in incorrect order", () => {
|
it("positions the overlay button before the overlay list if the elements have inserted in incorrect order", async () => {
|
||||||
document.body.appendChild(buttonElement);
|
document.body.appendChild(buttonElement);
|
||||||
|
|
||||||
autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
await autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
||||||
|
|
||||||
expect(globalThis.document.body.insertBefore).toHaveBeenCalledWith(
|
expect(globalThis.document.body.insertBefore).toHaveBeenCalledWith(
|
||||||
buttonElement,
|
buttonElement,
|
||||||
@ -375,11 +305,11 @@ describe("AutofillInlineMenuContentService", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("positions the last child before the overlay button if it is not the overlay list", () => {
|
it("positions the last child before the overlay button if it is not the overlay list", async () => {
|
||||||
const injectedElement = document.createElement("div");
|
const injectedElement = document.createElement("div");
|
||||||
document.body.appendChild(injectedElement);
|
document.body.appendChild(injectedElement);
|
||||||
|
|
||||||
autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
await autofillInlineMenuContentService["handleBodyElementMutationObserverUpdate"]();
|
||||||
|
|
||||||
expect(globalThis.document.body.insertBefore).toHaveBeenCalledWith(
|
expect(globalThis.document.body.insertBefore).toHaveBeenCalledWith(
|
||||||
injectedElement,
|
injectedElement,
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { AutofillExtensionMessage } from "../../../content/abstractions/autofill-init";
|
import { AutofillExtensionMessage } from "../../../content/abstractions/autofill-init";
|
||||||
import { AutofillOverlayElement } from "../../../enums/autofill-overlay.enum";
|
import {
|
||||||
|
AutofillOverlayElement,
|
||||||
|
AutofillOverlayElementType,
|
||||||
|
} from "../../../enums/autofill-overlay.enum";
|
||||||
import {
|
import {
|
||||||
sendExtensionMessage,
|
sendExtensionMessage,
|
||||||
generateRandomCustomElementName,
|
generateRandomCustomElementName,
|
||||||
@ -21,8 +24,6 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
globalThis.navigator.userAgent.indexOf(" Gecko/") !== -1;
|
globalThis.navigator.userAgent.indexOf(" Gecko/") !== -1;
|
||||||
private buttonElement: HTMLElement;
|
private buttonElement: HTMLElement;
|
||||||
private listElement: HTMLElement;
|
private listElement: HTMLElement;
|
||||||
private isButtonVisible = false;
|
|
||||||
private isListVisible = false;
|
|
||||||
private inlineMenuElementsMutationObserver: MutationObserver;
|
private inlineMenuElementsMutationObserver: MutationObserver;
|
||||||
private bodyElementMutationObserver: MutationObserver;
|
private bodyElementMutationObserver: MutationObserver;
|
||||||
private mutationObserverIterations = 0;
|
private mutationObserverIterations = 0;
|
||||||
@ -36,9 +37,6 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
private readonly extensionMessageHandlers: InlineMenuExtensionMessageHandlers = {
|
private readonly extensionMessageHandlers: InlineMenuExtensionMessageHandlers = {
|
||||||
closeAutofillInlineMenu: ({ message }) => this.closeInlineMenu(message),
|
closeAutofillInlineMenu: ({ message }) => this.closeInlineMenu(message),
|
||||||
appendAutofillInlineMenuToDom: ({ message }) => this.appendInlineMenuElements(message),
|
appendAutofillInlineMenuToDom: ({ message }) => this.appendInlineMenuElements(message),
|
||||||
toggleAutofillInlineMenuHidden: ({ message }) => this.toggleInlineMenuHidden(message),
|
|
||||||
checkIsAutofillInlineMenuButtonVisible: () => this.isInlineMenuButtonVisible(),
|
|
||||||
checkIsAutofillInlineMenuListVisible: () => this.isInlineMenuListVisible(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -62,28 +60,23 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies if the inline menu button is currently visible.
|
* Checks if the inline menu button is visible at the top frame.
|
||||||
*/
|
*/
|
||||||
private isInlineMenuButtonVisible() {
|
private async isInlineMenuButtonVisible() {
|
||||||
return this.isButtonVisible;
|
return (
|
||||||
|
!!this.buttonElement &&
|
||||||
|
(await this.sendExtensionMessage("checkIsAutofillInlineMenuButtonVisible")) === true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies if the inline menu list is currently visible.
|
* Checks if the inline menu list if visible at the top frame.
|
||||||
*/
|
*/
|
||||||
private isInlineMenuListVisible() {
|
private async isInlineMenuListVisible() {
|
||||||
return this.isListVisible;
|
return (
|
||||||
}
|
!!this.listElement &&
|
||||||
|
(await this.sendExtensionMessage("checkIsAutofillInlineMenuListVisible")) === true
|
||||||
/**
|
);
|
||||||
* Sends a message that facilitates hiding the inline menu elements.
|
|
||||||
*
|
|
||||||
* @param message - The message that contains the visibility state of the inline menu elements.
|
|
||||||
*/
|
|
||||||
private toggleInlineMenuHidden(message: AutofillExtensionMessage) {
|
|
||||||
const { isInlineMenuHidden } = message;
|
|
||||||
this.isButtonVisible = !!this.buttonElement && !isInlineMenuHidden;
|
|
||||||
this.isListVisible = !!this.listElement && !isInlineMenuHidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,7 +107,6 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
private closeInlineMenuButton() {
|
private closeInlineMenuButton() {
|
||||||
if (this.buttonElement) {
|
if (this.buttonElement) {
|
||||||
this.buttonElement.remove();
|
this.buttonElement.remove();
|
||||||
this.isButtonVisible = false;
|
|
||||||
void this.sendExtensionMessage("autofillOverlayElementClosed", {
|
void this.sendExtensionMessage("autofillOverlayElementClosed", {
|
||||||
overlayElement: AutofillOverlayElement.Button,
|
overlayElement: AutofillOverlayElement.Button,
|
||||||
});
|
});
|
||||||
@ -127,7 +119,6 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
private closeInlineMenuList() {
|
private closeInlineMenuList() {
|
||||||
if (this.listElement) {
|
if (this.listElement) {
|
||||||
this.listElement.remove();
|
this.listElement.remove();
|
||||||
this.isListVisible = false;
|
|
||||||
void this.sendExtensionMessage("autofillOverlayElementClosed", {
|
void this.sendExtensionMessage("autofillOverlayElementClosed", {
|
||||||
overlayElement: AutofillOverlayElement.List,
|
overlayElement: AutofillOverlayElement.List,
|
||||||
});
|
});
|
||||||
@ -154,9 +145,9 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
this.updateCustomElementDefaultStyles(this.buttonElement);
|
this.updateCustomElementDefaultStyles(this.buttonElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isButtonVisible) {
|
if (!(await this.isInlineMenuButtonVisible())) {
|
||||||
this.appendInlineMenuElementToBody(this.buttonElement);
|
this.appendInlineMenuElementToBody(this.buttonElement);
|
||||||
this.isButtonVisible = true;
|
this.updateInlineMenuElementIsVisibleStatus(AutofillOverlayElement.Button, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,12 +160,28 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
this.updateCustomElementDefaultStyles(this.listElement);
|
this.updateCustomElementDefaultStyles(this.listElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isListVisible) {
|
if (!(await this.isInlineMenuListVisible())) {
|
||||||
this.appendInlineMenuElementToBody(this.listElement);
|
this.appendInlineMenuElementToBody(this.listElement);
|
||||||
this.isListVisible = true;
|
this.updateInlineMenuElementIsVisibleStatus(AutofillOverlayElement.List, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the visibility status of the inline menu element within the background script.
|
||||||
|
*
|
||||||
|
* @param overlayElement - The inline menu element to update the visibility status for.
|
||||||
|
* @param isInlineMenuElementVisible - The visibility status to update the inline menu element to.
|
||||||
|
*/
|
||||||
|
private updateInlineMenuElementIsVisibleStatus(
|
||||||
|
overlayElement: AutofillOverlayElementType,
|
||||||
|
isInlineMenuElementVisible: boolean,
|
||||||
|
) {
|
||||||
|
void this.sendExtensionMessage("updateAutofillInlineMenuElementIsVisibleStatus", {
|
||||||
|
overlayElement,
|
||||||
|
isInlineMenuElementVisible,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends the inline menu element to the body element. This method will also
|
* Appends the inline menu element to the body element. This method will also
|
||||||
* observe the body element to ensure that the inline menu element is not
|
* observe the body element to ensure that the inline menu element is not
|
||||||
@ -360,7 +367,7 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
* ensure that the inline menu elements are always present at the bottom of the
|
* ensure that the inline menu elements are always present at the bottom of the
|
||||||
* body element.
|
* body element.
|
||||||
*/
|
*/
|
||||||
private handleBodyElementMutationObserverUpdate = () => {
|
private handleBodyElementMutationObserverUpdate = async () => {
|
||||||
if (
|
if (
|
||||||
(!this.buttonElement && !this.listElement) ||
|
(!this.buttonElement && !this.listElement) ||
|
||||||
this.isTriggeringExcessiveMutationObserverIterations()
|
this.isTriggeringExcessiveMutationObserverIterations()
|
||||||
@ -377,14 +384,14 @@ export class AutofillInlineMenuContentService implements AutofillInlineMenuConte
|
|||||||
if (
|
if (
|
||||||
!lastChild ||
|
!lastChild ||
|
||||||
(lastChildIsInlineMenuList && secondToLastChildIsInlineMenuButton) ||
|
(lastChildIsInlineMenuList && secondToLastChildIsInlineMenuButton) ||
|
||||||
(lastChildIsInlineMenuButton && !this.isListVisible)
|
(lastChildIsInlineMenuButton && !(await this.isInlineMenuListVisible()))
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(lastChildIsInlineMenuList && !secondToLastChildIsInlineMenuButton) ||
|
(lastChildIsInlineMenuList && !secondToLastChildIsInlineMenuButton) ||
|
||||||
(lastChildIsInlineMenuButton && this.isListVisible)
|
(lastChildIsInlineMenuButton && (await this.isInlineMenuListVisible()))
|
||||||
) {
|
) {
|
||||||
globalThis.document.body.insertBefore(this.buttonElement, this.listElement);
|
globalThis.document.body.insertBefore(this.buttonElement, this.listElement);
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user