mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 16:53:34 +00:00
[PM-5189] Reworking project structure to ensure we can better differentiate the inline menu feature from other features
This commit is contained in:
@@ -2,7 +2,7 @@ import { mock, MockProxy } from "jest-mock-extended";
|
|||||||
|
|
||||||
import AutofillPageDetails from "../models/autofill-page-details";
|
import AutofillPageDetails from "../models/autofill-page-details";
|
||||||
import AutofillScript from "../models/autofill-script";
|
import AutofillScript from "../models/autofill-script";
|
||||||
import { AutofillOverlayInlineMenuElements } from "../overlay/inline-menu/content/autofill-overlay-inline-menu-elements";
|
import { AutofillInlineMenuContentService } from "../overlay/inline-menu/content/autofill-inline-menu-content.service";
|
||||||
import AutofillOverlayContentService from "../services/autofill-overlay-content.service";
|
import AutofillOverlayContentService from "../services/autofill-overlay-content.service";
|
||||||
import { flushPromises, sendMockExtensionMessage } from "../spec/testing-utils";
|
import { flushPromises, sendMockExtensionMessage } from "../spec/testing-utils";
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ import { AutofillExtensionMessage } from "./abstractions/autofill-init";
|
|||||||
import AutofillInit from "./autofill-init";
|
import AutofillInit from "./autofill-init";
|
||||||
|
|
||||||
describe("AutofillInit", () => {
|
describe("AutofillInit", () => {
|
||||||
let inlineMenuElements: MockProxy<AutofillOverlayInlineMenuElements>;
|
let inlineMenuElements: MockProxy<AutofillInlineMenuContentService>;
|
||||||
let autofillOverlayContentService: MockProxy<AutofillOverlayContentService>;
|
let autofillOverlayContentService: MockProxy<AutofillOverlayContentService>;
|
||||||
let autofillInit: AutofillInit;
|
let autofillInit: AutofillInit;
|
||||||
const originalDocumentReadyState = document.readyState;
|
const originalDocumentReadyState = document.readyState;
|
||||||
@@ -22,7 +22,7 @@ describe("AutofillInit", () => {
|
|||||||
addListener: jest.fn(),
|
addListener: jest.fn(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
inlineMenuElements = mock<AutofillOverlayInlineMenuElements>();
|
inlineMenuElements = mock<AutofillInlineMenuContentService>();
|
||||||
autofillOverlayContentService = mock<AutofillOverlayContentService>();
|
autofillOverlayContentService = mock<AutofillOverlayContentService>();
|
||||||
autofillInit = new AutofillInit(autofillOverlayContentService, inlineMenuElements);
|
autofillInit = new AutofillInit(autofillOverlayContentService, inlineMenuElements);
|
||||||
sendExtensionMessageSpy = jest
|
sendExtensionMessageSpy = jest
|
||||||
@@ -237,7 +237,10 @@ describe("AutofillInit", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("removes the overlay when filling the form", async () => {
|
it("removes the overlay when filling the form", async () => {
|
||||||
const blurAndRemoveOverlaySpy = jest.spyOn(autofillInit as any, "blurAndRemoveOverlay");
|
const blurAndRemoveOverlaySpy = jest.spyOn(
|
||||||
|
autofillInit as any,
|
||||||
|
"blurAndRemoveInlineMenu",
|
||||||
|
);
|
||||||
sendMockExtensionMessage({
|
sendMockExtensionMessage({
|
||||||
command: "fillForm",
|
command: "fillForm",
|
||||||
fillScript,
|
fillScript,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { EVENTS } from "@bitwarden/common/autofill/constants";
|
import { EVENTS } from "@bitwarden/common/autofill/constants";
|
||||||
|
|
||||||
import AutofillPageDetails from "../models/autofill-page-details";
|
import AutofillPageDetails from "../models/autofill-page-details";
|
||||||
import { AutofillOverlayInlineMenuElements } from "../overlay/inline-menu/abstractions/autofill-overlay-inline-menu-elements";
|
import { AutofillInlineMenuContentService } from "../overlay/inline-menu/abstractions/autofill-inline-menu-content.service";
|
||||||
import { AutofillOverlayContentService } from "../services/abstractions/autofill-overlay-content.service";
|
import { AutofillOverlayContentService } from "../services/abstractions/autofill-overlay-content.service";
|
||||||
import CollectAutofillContentService from "../services/collect-autofill-content.service";
|
import CollectAutofillContentService from "../services/collect-autofill-content.service";
|
||||||
import DomElementVisibilityService from "../services/dom-element-visibility.service";
|
import DomElementVisibilityService from "../services/dom-element-visibility.service";
|
||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
class AutofillInit implements AutofillInitInterface {
|
class AutofillInit implements AutofillInitInterface {
|
||||||
private readonly sendExtensionMessage = sendExtensionMessage;
|
private readonly sendExtensionMessage = sendExtensionMessage;
|
||||||
private readonly autofillOverlayContentService: AutofillOverlayContentService | undefined;
|
private readonly autofillOverlayContentService: AutofillOverlayContentService | undefined;
|
||||||
private readonly inlineMenuElements: AutofillOverlayInlineMenuElements | undefined;
|
private readonly autofillInlineMenuContentService: AutofillInlineMenuContentService | undefined;
|
||||||
private readonly domElementVisibilityService: DomElementVisibilityService;
|
private readonly domElementVisibilityService: DomElementVisibilityService;
|
||||||
private readonly collectAutofillContentService: CollectAutofillContentService;
|
private readonly collectAutofillContentService: CollectAutofillContentService;
|
||||||
private readonly insertAutofillContentService: InsertAutofillContentService;
|
private readonly insertAutofillContentService: InsertAutofillContentService;
|
||||||
@@ -37,7 +37,7 @@ class AutofillInit implements AutofillInitInterface {
|
|||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
autofillOverlayContentService?: AutofillOverlayContentService,
|
autofillOverlayContentService?: AutofillOverlayContentService,
|
||||||
inlineMenuElements?: AutofillOverlayInlineMenuElements,
|
inlineMenuElements?: AutofillInlineMenuContentService,
|
||||||
) {
|
) {
|
||||||
this.autofillOverlayContentService = autofillOverlayContentService;
|
this.autofillOverlayContentService = autofillOverlayContentService;
|
||||||
if (this.autofillOverlayContentService) {
|
if (this.autofillOverlayContentService) {
|
||||||
@@ -47,15 +47,17 @@ class AutofillInit implements AutofillInitInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.inlineMenuElements = inlineMenuElements;
|
this.autofillInlineMenuContentService = inlineMenuElements;
|
||||||
if (this.inlineMenuElements) {
|
if (this.autofillInlineMenuContentService) {
|
||||||
this.extensionMessageHandlers = Object.assign(
|
this.extensionMessageHandlers = Object.assign(
|
||||||
this.extensionMessageHandlers,
|
this.extensionMessageHandlers,
|
||||||
this.inlineMenuElements.extensionMessageHandlers,
|
this.autofillInlineMenuContentService.extensionMessageHandlers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.domElementVisibilityService = new DomElementVisibilityService(this.inlineMenuElements);
|
this.domElementVisibilityService = new DomElementVisibilityService(
|
||||||
|
this.autofillInlineMenuContentService,
|
||||||
|
);
|
||||||
this.collectAutofillContentService = new CollectAutofillContentService(
|
this.collectAutofillContentService = new CollectAutofillContentService(
|
||||||
this.domElementVisibilityService,
|
this.domElementVisibilityService,
|
||||||
this.autofillOverlayContentService,
|
this.autofillOverlayContentService,
|
||||||
@@ -135,7 +137,7 @@ class AutofillInit implements AutofillInitInterface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.blurAndRemoveOverlay();
|
this.blurAndRemoveInlineMenu();
|
||||||
await this.sendExtensionMessage("updateIsFieldCurrentlyFilling", {
|
await this.sendExtensionMessage("updateIsFieldCurrentlyFilling", {
|
||||||
isFieldCurrentlyFilling: true,
|
isFieldCurrentlyFilling: true,
|
||||||
});
|
});
|
||||||
@@ -155,8 +157,8 @@ class AutofillInit implements AutofillInitInterface {
|
|||||||
* in cases where the background unlock or vault item reprompt popout
|
* in cases where the background unlock or vault item reprompt popout
|
||||||
* is opened.
|
* is opened.
|
||||||
*/
|
*/
|
||||||
private blurAndRemoveOverlay() {
|
private blurAndRemoveInlineMenu() {
|
||||||
this.autofillOverlayContentService?.blurMostRecentOverlayField(true);
|
this.autofillOverlayContentService?.blurMostRecentlyFocusedField(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,7 +213,7 @@ class AutofillInit implements AutofillInitInterface {
|
|||||||
chrome.runtime.onMessage.removeListener(this.handleExtensionMessage);
|
chrome.runtime.onMessage.removeListener(this.handleExtensionMessage);
|
||||||
this.collectAutofillContentService.destroy();
|
this.collectAutofillContentService.destroy();
|
||||||
this.autofillOverlayContentService?.destroy();
|
this.autofillOverlayContentService?.destroy();
|
||||||
this.inlineMenuElements?.destroy();
|
this.autofillInlineMenuContentService?.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AutofillOverlayInlineMenuElements } from "../overlay/inline-menu/content/autofill-overlay-inline-menu-elements";
|
import { AutofillInlineMenuContentService } from "../overlay/inline-menu/content/autofill-inline-menu-content.service";
|
||||||
import AutofillOverlayContentService from "../services/autofill-overlay-content.service";
|
import AutofillOverlayContentService from "../services/autofill-overlay-content.service";
|
||||||
import { setupAutofillInitDisconnectAction } from "../utils";
|
import { setupAutofillInitDisconnectAction } from "../utils";
|
||||||
|
|
||||||
@@ -7,9 +7,9 @@ import AutofillInit from "./autofill-init";
|
|||||||
(function (windowContext) {
|
(function (windowContext) {
|
||||||
if (!windowContext.bitwardenAutofillInit) {
|
if (!windowContext.bitwardenAutofillInit) {
|
||||||
const autofillOverlayContentService = new AutofillOverlayContentService();
|
const autofillOverlayContentService = new AutofillOverlayContentService();
|
||||||
let inlineMenuElements: AutofillOverlayInlineMenuElements;
|
let inlineMenuElements: AutofillInlineMenuContentService;
|
||||||
if (globalThis.self === globalThis.top) {
|
if (globalThis.self === globalThis.top) {
|
||||||
inlineMenuElements = new AutofillOverlayInlineMenuElements();
|
inlineMenuElements = new AutofillInlineMenuContentService();
|
||||||
}
|
}
|
||||||
windowContext.bitwardenAutofillInit = new AutofillInit(
|
windowContext.bitwardenAutofillInit = new AutofillInit(
|
||||||
autofillOverlayContentService,
|
autofillOverlayContentService,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
const AutofillOverlayElement = {
|
const AutofillOverlayElement = {
|
||||||
Button: "autofill-overlay-button",
|
Button: "autofill-inline-menu-button",
|
||||||
List: "autofill-overlay-list",
|
List: "autofill-overlay-list",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const AutofillOverlayPort = {
|
const AutofillOverlayPort = {
|
||||||
Button: "autofill-overlay-button-port",
|
Button: "autofill-inline-menu-button-port",
|
||||||
ButtonMessageConnector: "autofill-overlay-button-message-connector",
|
ButtonMessageConnector: "autofill-inline-menu-button-message-connector",
|
||||||
List: "autofill-overlay-list-port",
|
List: "autofill-overlay-list-port",
|
||||||
ListMessageConnector: "autofill-overlay-list-message-connector",
|
ListMessageConnector: "autofill-overlay-list-message-connector",
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
|
|
||||||
|
type AutofillInlineMenuButtonMessage = { command: string; colorScheme?: string };
|
||||||
|
|
||||||
|
type UpdateAuthStatusMessage = AutofillInlineMenuButtonMessage & {
|
||||||
|
authStatus: AuthenticationStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
type InitAutofillInlineMenuButtonMessage = UpdateAuthStatusMessage & {
|
||||||
|
styleSheetUrl: string;
|
||||||
|
translations: Record<string, string>;
|
||||||
|
portKey: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AutofillInlineMenuButtonWindowMessageHandlers = {
|
||||||
|
[key: string]: CallableFunction;
|
||||||
|
initAutofillInlineMenuButton: ({
|
||||||
|
message,
|
||||||
|
}: {
|
||||||
|
message: InitAutofillInlineMenuButtonMessage;
|
||||||
|
}) => void;
|
||||||
|
checkAutofillInlineMenuButtonFocused: () => void;
|
||||||
|
updateAutofillInlineMenuButtonAuthStatus: ({
|
||||||
|
message,
|
||||||
|
}: {
|
||||||
|
message: UpdateAuthStatusMessage;
|
||||||
|
}) => void;
|
||||||
|
updateAutofillInlineMenuColorScheme: ({
|
||||||
|
message,
|
||||||
|
}: {
|
||||||
|
message: AutofillInlineMenuButtonMessage;
|
||||||
|
}) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
UpdateAuthStatusMessage,
|
||||||
|
AutofillInlineMenuButtonMessage,
|
||||||
|
InitAutofillInlineMenuButtonMessage,
|
||||||
|
AutofillInlineMenuButtonWindowMessageHandlers,
|
||||||
|
};
|
||||||
@@ -9,7 +9,7 @@ export type InlineMenuExtensionMessageHandlers = {
|
|||||||
checkIsAutofillInlineMenuListVisible: () => boolean;
|
checkIsAutofillInlineMenuListVisible: () => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface AutofillOverlayInlineMenuElements {
|
export interface AutofillInlineMenuContentService {
|
||||||
extensionMessageHandlers: InlineMenuExtensionMessageHandlers;
|
extensionMessageHandlers: InlineMenuExtensionMessageHandlers;
|
||||||
isElementInlineMenu(element: HTMLElement): boolean;
|
isElementInlineMenu(element: HTMLElement): boolean;
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
@@ -23,7 +23,7 @@ type BackgroundPortMessageHandlers = {
|
|||||||
updateAutofillInlineMenuColorScheme: () => void;
|
updateAutofillInlineMenuColorScheme: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface AutofillOverlayIframeService {
|
interface AutofillInlineMenuIframeService {
|
||||||
initMenuIframe(): void;
|
initMenuIframe(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,5 +31,5 @@ export {
|
|||||||
AutofillOverlayIframeExtensionMessage,
|
AutofillOverlayIframeExtensionMessage,
|
||||||
AutofillOverlayIframeWindowMessageHandlers,
|
AutofillOverlayIframeWindowMessageHandlers,
|
||||||
BackgroundPortMessageHandlers,
|
BackgroundPortMessageHandlers,
|
||||||
AutofillOverlayIframeService,
|
AutofillInlineMenuIframeService,
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { AutofillInlineMenuButtonWindowMessageHandlers } from "./autofill-inline-menu-button";
|
||||||
|
import { OverlayListWindowMessageHandlers } from "./autofill-inline-menu-list";
|
||||||
|
|
||||||
|
type AutofillInlineMenuPageElementWindowMessageHandlers =
|
||||||
|
| AutofillInlineMenuButtonWindowMessageHandlers
|
||||||
|
| OverlayListWindowMessageHandlers;
|
||||||
|
|
||||||
|
type AutofillInlineMenuPageElementWindowMessage = {
|
||||||
|
[key: string]: any;
|
||||||
|
command: string;
|
||||||
|
overlayCipherId?: string;
|
||||||
|
height?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
AutofillInlineMenuPageElementWindowMessageHandlers,
|
||||||
|
AutofillInlineMenuPageElementWindowMessage,
|
||||||
|
};
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
|
||||||
|
|
||||||
type OverlayButtonMessage = { command: string; colorScheme?: string };
|
|
||||||
|
|
||||||
type UpdateAuthStatusMessage = OverlayButtonMessage & { authStatus: AuthenticationStatus };
|
|
||||||
|
|
||||||
type InitAutofillOverlayButtonMessage = UpdateAuthStatusMessage & {
|
|
||||||
styleSheetUrl: string;
|
|
||||||
translations: Record<string, string>;
|
|
||||||
portKey: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type OverlayButtonWindowMessageHandlers = {
|
|
||||||
[key: string]: CallableFunction;
|
|
||||||
initAutofillInlineMenuButton: ({
|
|
||||||
message,
|
|
||||||
}: {
|
|
||||||
message: InitAutofillOverlayButtonMessage;
|
|
||||||
}) => void;
|
|
||||||
checkAutofillInlineMenuButtonFocused: () => void;
|
|
||||||
updateAutofillOverlayButtonAuthStatus: ({
|
|
||||||
message,
|
|
||||||
}: {
|
|
||||||
message: UpdateAuthStatusMessage;
|
|
||||||
}) => void;
|
|
||||||
updateAutofillInlineMenuColorScheme: ({ message }: { message: OverlayButtonMessage }) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
UpdateAuthStatusMessage,
|
|
||||||
OverlayButtonMessage,
|
|
||||||
InitAutofillOverlayButtonMessage,
|
|
||||||
OverlayButtonWindowMessageHandlers,
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { OverlayButtonWindowMessageHandlers } from "./autofill-overlay-button";
|
|
||||||
import { OverlayListWindowMessageHandlers } from "./autofill-overlay-list";
|
|
||||||
|
|
||||||
type AutofillOverlayPageElementWindowMessageHandlers =
|
|
||||||
| OverlayButtonWindowMessageHandlers
|
|
||||||
| OverlayListWindowMessageHandlers;
|
|
||||||
|
|
||||||
type AutofillOverlayPageElementWindowMessage = {
|
|
||||||
[key: string]: any;
|
|
||||||
command: string;
|
|
||||||
overlayCipherId?: string;
|
|
||||||
height?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { AutofillOverlayPageElementWindowMessageHandlers, AutofillOverlayPageElementWindowMessage };
|
|
||||||
@@ -7,12 +7,12 @@ import {
|
|||||||
} from "../../../utils";
|
} from "../../../utils";
|
||||||
import {
|
import {
|
||||||
InlineMenuExtensionMessageHandlers,
|
InlineMenuExtensionMessageHandlers,
|
||||||
AutofillOverlayInlineMenuElements as InlineMenuElementsInterface,
|
AutofillInlineMenuContentService as AutofillInlineMenuContentServiceInterface,
|
||||||
} from "../abstractions/autofill-overlay-inline-menu-elements";
|
} from "../abstractions/autofill-inline-menu-content.service";
|
||||||
import AutofillOverlayButtonIframe from "../iframe-content/autofill-overlay-button-iframe";
|
import { AutofillInlineMenuButtonIframe } from "../iframe-content/autofill-inline-menu-button-iframe";
|
||||||
import AutofillOverlayListIframe from "../iframe-content/autofill-overlay-list-iframe";
|
import AutofillInlineMenuListIframe from "../iframe-content/autofill-inline-menu-list-iframe";
|
||||||
|
|
||||||
export class AutofillOverlayInlineMenuElements implements InlineMenuElementsInterface {
|
export class AutofillInlineMenuContentService implements AutofillInlineMenuContentServiceInterface {
|
||||||
private readonly sendExtensionMessage = sendExtensionMessage;
|
private readonly sendExtensionMessage = sendExtensionMessage;
|
||||||
private readonly generateRandomCustomElementName = generateRandomCustomElementName;
|
private readonly generateRandomCustomElementName = generateRandomCustomElementName;
|
||||||
private readonly setElementStyles = setElementStyles;
|
private readonly setElementStyles = setElementStyles;
|
||||||
@@ -193,7 +193,7 @@ export class AutofillOverlayInlineMenuElements implements InlineMenuElementsInte
|
|||||||
|
|
||||||
if (this.isFirefoxBrowser) {
|
if (this.isFirefoxBrowser) {
|
||||||
this.buttonElement = globalThis.document.createElement("div");
|
this.buttonElement = globalThis.document.createElement("div");
|
||||||
new AutofillOverlayButtonIframe(this.buttonElement);
|
new AutofillInlineMenuButtonIframe(this.buttonElement);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -204,7 +204,7 @@ export class AutofillOverlayInlineMenuElements implements InlineMenuElementsInte
|
|||||||
class extends HTMLElement {
|
class extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
new AutofillOverlayButtonIframe(this);
|
new AutofillInlineMenuButtonIframe(this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -222,7 +222,7 @@ export class AutofillOverlayInlineMenuElements implements InlineMenuElementsInte
|
|||||||
|
|
||||||
if (this.isFirefoxBrowser) {
|
if (this.isFirefoxBrowser) {
|
||||||
this.listElement = globalThis.document.createElement("div");
|
this.listElement = globalThis.document.createElement("div");
|
||||||
new AutofillOverlayListIframe(this.listElement);
|
new AutofillInlineMenuListIframe(this.listElement);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -233,7 +233,7 @@ export class AutofillOverlayInlineMenuElements implements InlineMenuElementsInte
|
|||||||
class extends HTMLElement {
|
class extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
new AutofillOverlayListIframe(this);
|
new AutofillInlineMenuListIframe(this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -415,7 +415,7 @@ export class AutofillOverlayInlineMenuElements implements InlineMenuElementsInte
|
|||||||
if (this.mutationObserverIterations > 100) {
|
if (this.mutationObserverIterations > 100) {
|
||||||
clearTimeout(this.mutationObserverIterationsResetTimeout);
|
clearTimeout(this.mutationObserverIterationsResetTimeout);
|
||||||
this.mutationObserverIterations = 0;
|
this.mutationObserverIterations = 0;
|
||||||
void this.sendExtensionMessage("blurMostRecentOverlayField");
|
void this.sendExtensionMessage("blurMostRecentlyFocusedField");
|
||||||
this.removeInlineMenu();
|
this.removeInlineMenu();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`AutofillOverlayIframeService initMenuIframe sets up the iframe's attributes 1`] = `
|
||||||
|
<iframe
|
||||||
|
allowtransparency="true"
|
||||||
|
src="chrome-extension://id/overlay/menu.html"
|
||||||
|
style="all: initial !important; position: fixed !important; display: block !important; z-index: 2147483647 !important; line-height: 0 !important; overflow: hidden !important; transition: opacity 125ms ease-out 0s !important; visibility: visible !important; clip-path: none !important; pointer-events: auto !important; margin: 0px !important; padding: 0px !important; color-scheme: normal !important; opacity: 0 !important; height: 0px;"
|
||||||
|
tabindex="-1"
|
||||||
|
title="title"
|
||||||
|
/>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { AutofillInlineMenuButtonIframe } from "./autofill-inline-menu-button-iframe";
|
||||||
|
|
||||||
|
describe("AutofillInlineMenuButtonIframe", () => {
|
||||||
|
window.customElements.define(
|
||||||
|
"autofill-inline-menu-button-iframe",
|
||||||
|
class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
new AutofillInlineMenuButtonIframe(this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("creates a custom element that is an instance of the AutofillIframeElement parent class", () => {
|
||||||
|
document.body.innerHTML =
|
||||||
|
"<autofill-inline-menu-button-iframe></autofill-inline-menu-button-iframe>";
|
||||||
|
|
||||||
|
const iframe = document.querySelector("autofill-inline-menu-button-iframe");
|
||||||
|
|
||||||
|
expect(iframe).toBeInstanceOf(HTMLElement);
|
||||||
|
expect(iframe.shadowRoot).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { AutofillOverlayPort } from "../../../enums/autofill-overlay.enum";
|
import { AutofillOverlayPort } from "../../../enums/autofill-overlay.enum";
|
||||||
|
|
||||||
import AutofillOverlayIframeElement from "./autofill-overlay-iframe-element";
|
import { AutofillInlineMenuIframeElement } from "./autofill-inline-menu-iframe-element";
|
||||||
|
|
||||||
class AutofillOverlayButtonIframe extends AutofillOverlayIframeElement {
|
export class AutofillInlineMenuButtonIframe extends AutofillInlineMenuIframeElement {
|
||||||
constructor(element: HTMLElement) {
|
constructor(element: HTMLElement) {
|
||||||
super(
|
super(
|
||||||
element,
|
element,
|
||||||
@@ -16,5 +16,3 @@ class AutofillOverlayButtonIframe extends AutofillOverlayIframeElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AutofillOverlayButtonIframe;
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
import { AutofillOverlayPort } from "../../../enums/autofill-overlay.enum";
|
import { AutofillOverlayPort } from "../../../enums/autofill-overlay.enum";
|
||||||
|
|
||||||
import AutofillOverlayIframeElement from "./autofill-overlay-iframe-element";
|
import { AutofillInlineMenuIframeElement } from "./autofill-inline-menu-iframe-element";
|
||||||
import AutofillOverlayIframeService from "./autofill-overlay-iframe.service";
|
import { AutofillInlineMenuIframeService } from "./autofill-inline-menu-iframe.service";
|
||||||
|
|
||||||
jest.mock("./autofill-overlay-iframe.service");
|
jest.mock("./autofill-inline-menu-iframe.service");
|
||||||
|
|
||||||
describe("AutofillOverlayIframeElement", () => {
|
describe("AutofillInlineMenuIframeElement", () => {
|
||||||
window.customElements.define(
|
window.customElements.define(
|
||||||
"autofill-overlay-iframe",
|
"autofill-inline-menu-iframe",
|
||||||
class extends HTMLElement {
|
class extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
new AutofillOverlayIframeElement(
|
new AutofillInlineMenuIframeElement(
|
||||||
this,
|
this,
|
||||||
AutofillOverlayPort.Button,
|
AutofillOverlayPort.Button,
|
||||||
{ background: "transparent", border: "none" },
|
{ background: "transparent", border: "none" },
|
||||||
@@ -26,22 +26,22 @@ describe("AutofillOverlayIframeElement", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("creates a custom element that is an instance of the HTMLElement parent class", () => {
|
it("creates a custom element that is an instance of the HTMLElement parent class", () => {
|
||||||
document.body.innerHTML = "<autofill-overlay-iframe></autofill-overlay-iframe>";
|
document.body.innerHTML = "<autofill-inline-menu-iframe></autofill-inline-menu-iframe>";
|
||||||
|
|
||||||
const iframe = document.querySelector("autofill-overlay-iframe");
|
const iframe = document.querySelector("autofill-inline-menu-iframe");
|
||||||
|
|
||||||
expect(iframe).toBeInstanceOf(HTMLElement);
|
expect(iframe).toBeInstanceOf(HTMLElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("attaches a closed shadow DOM", () => {
|
it("attaches a closed shadow DOM", () => {
|
||||||
document.body.innerHTML = "<autofill-overlay-iframe></autofill-overlay-iframe>";
|
document.body.innerHTML = "<autofill-inline-menu-iframe></autofill-inline-menu-iframe>";
|
||||||
|
|
||||||
const iframe = document.querySelector("autofill-overlay-iframe");
|
const iframe = document.querySelector("autofill-inline-menu-iframe");
|
||||||
|
|
||||||
expect(iframe.shadowRoot).toBeNull();
|
expect(iframe.shadowRoot).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("instantiates the autofill overlay iframe service for each attached custom element", () => {
|
it("instantiates the autofill overlay iframe service for each attached custom element", () => {
|
||||||
expect(AutofillOverlayIframeService).toHaveBeenCalledTimes(2);
|
expect(AutofillInlineMenuIframeService).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import AutofillOverlayIframeService from "./autofill-overlay-iframe.service";
|
import { AutofillInlineMenuIframeService } from "./autofill-inline-menu-iframe.service";
|
||||||
|
|
||||||
class AutofillOverlayIframeElement {
|
export class AutofillInlineMenuIframeElement {
|
||||||
constructor(
|
constructor(
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
portName: string,
|
portName: string,
|
||||||
@@ -9,7 +9,7 @@ class AutofillOverlayIframeElement {
|
|||||||
ariaAlert?: string,
|
ariaAlert?: string,
|
||||||
) {
|
) {
|
||||||
const shadow: ShadowRoot = element.attachShadow({ mode: "closed" });
|
const shadow: ShadowRoot = element.attachShadow({ mode: "closed" });
|
||||||
const autofillOverlayIframeService = new AutofillOverlayIframeService(
|
const autofillOverlayIframeService = new AutofillInlineMenuIframeService(
|
||||||
shadow,
|
shadow,
|
||||||
portName,
|
portName,
|
||||||
initStyles,
|
initStyles,
|
||||||
@@ -19,5 +19,3 @@ class AutofillOverlayIframeElement {
|
|||||||
autofillOverlayIframeService.initMenuIframe();
|
autofillOverlayIframeService.initMenuIframe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AutofillOverlayIframeElement;
|
|
||||||
@@ -11,10 +11,10 @@ import {
|
|||||||
triggerPortOnDisconnectEvent,
|
triggerPortOnDisconnectEvent,
|
||||||
} from "../../../spec/testing-utils";
|
} from "../../../spec/testing-utils";
|
||||||
|
|
||||||
import AutofillOverlayIframeService from "./autofill-overlay-iframe.service";
|
import { AutofillInlineMenuIframeService } from "./autofill-inline-menu-iframe.service";
|
||||||
|
|
||||||
describe("AutofillOverlayIframeService", () => {
|
describe("AutofillOverlayIframeService", () => {
|
||||||
let autofillOverlayIframeService: AutofillOverlayIframeService;
|
let autofillOverlayIframeService: AutofillInlineMenuIframeService;
|
||||||
let portSpy: chrome.runtime.Port;
|
let portSpy: chrome.runtime.Port;
|
||||||
let shadowAppendSpy: jest.SpyInstance;
|
let shadowAppendSpy: jest.SpyInstance;
|
||||||
let handlePortDisconnectSpy: jest.SpyInstance;
|
let handlePortDisconnectSpy: jest.SpyInstance;
|
||||||
@@ -23,7 +23,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const shadow = document.createElement("div").attachShadow({ mode: "open" });
|
const shadow = document.createElement("div").attachShadow({ mode: "open" });
|
||||||
autofillOverlayIframeService = new AutofillOverlayIframeService(
|
autofillOverlayIframeService = new AutofillInlineMenuIframeService(
|
||||||
shadow,
|
shadow,
|
||||||
AutofillOverlayPort.Button,
|
AutofillOverlayPort.Button,
|
||||||
{ height: "0px" },
|
{ height: "0px" },
|
||||||
@@ -4,11 +4,11 @@ import { ThemeType } from "@bitwarden/common/platform/enums";
|
|||||||
import { sendExtensionMessage, setElementStyles } from "../../../utils";
|
import { sendExtensionMessage, setElementStyles } from "../../../utils";
|
||||||
import {
|
import {
|
||||||
BackgroundPortMessageHandlers,
|
BackgroundPortMessageHandlers,
|
||||||
AutofillOverlayIframeService as AutofillOverlayIframeServiceInterface,
|
AutofillInlineMenuIframeService as AutofillOverlayIframeServiceInterface,
|
||||||
AutofillOverlayIframeExtensionMessage,
|
AutofillOverlayIframeExtensionMessage,
|
||||||
} from "../abstractions/autofill-overlay-iframe.service";
|
} from "../abstractions/autofill-inline-menu-iframe.service";
|
||||||
|
|
||||||
class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterface {
|
export class AutofillInlineMenuIframeService implements AutofillOverlayIframeServiceInterface {
|
||||||
private sendExtensionMessage = sendExtensionMessage;
|
private sendExtensionMessage = sendExtensionMessage;
|
||||||
private port: chrome.runtime.Port | null = null;
|
private port: chrome.runtime.Port | null = null;
|
||||||
private portKey: string;
|
private portKey: string;
|
||||||
@@ -405,5 +405,3 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AutofillOverlayIframeService;
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import AutofillOverlayListIframe from "./autofill-overlay-list-iframe";
|
import AutofillInlineMenuListIframe from "./autofill-inline-menu-list-iframe";
|
||||||
|
|
||||||
describe("AutofillOverlayListIframe", () => {
|
describe("AutofillOverlayListIframe", () => {
|
||||||
window.customElements.define(
|
window.customElements.define(
|
||||||
@@ -6,7 +6,7 @@ describe("AutofillOverlayListIframe", () => {
|
|||||||
class extends HTMLElement {
|
class extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
new AutofillOverlayListIframe(this);
|
new AutofillInlineMenuListIframe(this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { AutofillOverlayPort } from "../../../enums/autofill-overlay.enum";
|
import { AutofillOverlayPort } from "../../../enums/autofill-overlay.enum";
|
||||||
|
|
||||||
import AutofillOverlayIframeElement from "./autofill-overlay-iframe-element";
|
import { AutofillInlineMenuIframeElement } from "./autofill-inline-menu-iframe-element";
|
||||||
|
|
||||||
class AutofillOverlayListIframe extends AutofillOverlayIframeElement {
|
class AutofillInlineMenuListIframe extends AutofillInlineMenuIframeElement {
|
||||||
constructor(element: HTMLElement) {
|
constructor(element: HTMLElement) {
|
||||||
super(
|
super(
|
||||||
element,
|
element,
|
||||||
@@ -22,4 +22,4 @@ class AutofillOverlayListIframe extends AutofillOverlayIframeElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AutofillOverlayListIframe;
|
export default AutofillInlineMenuListIframe;
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import AutofillOverlayButtonIframe from "./autofill-overlay-button-iframe";
|
|
||||||
|
|
||||||
describe("AutofillOverlayButtonIframe", () => {
|
|
||||||
window.customElements.define(
|
|
||||||
"autofill-overlay-button-iframe",
|
|
||||||
class extends HTMLElement {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
new AutofillOverlayButtonIframe(this);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("creates a custom element that is an instance of the AutofillIframeElement parent class", () => {
|
|
||||||
document.body.innerHTML = "<autofill-overlay-button-iframe></autofill-overlay-button-iframe>";
|
|
||||||
|
|
||||||
const iframe = document.querySelector("autofill-overlay-button-iframe");
|
|
||||||
|
|
||||||
expect(iframe).toBeInstanceOf(HTMLElement);
|
|
||||||
expect(iframe.shadowRoot).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`AutofillInlineMenuButton initAutofillInlineMenuButton creates the button element with the locked icon when the user's auth status is not Unlocked 1`] = `
|
||||||
|
<button
|
||||||
|
aria-label="toggleBitwardenVaultOverlay"
|
||||||
|
class="inline-menu-button"
|
||||||
|
tabindex="-1"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="inline-menu-button-svg-icon logo-locked-icon"
|
||||||
|
fill="none"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.66.175A.566.566 0 0 0 12.25 0H1.75a.559.559 0 0 0-.409.175.561.561 0 0 0-.175.41v7c.002.532.105 1.06.305 1.554.189.488.444.948.756 1.368.322.42.682.81 1.076 1.163.365.335.75.649 1.152.939.35.248.718.483 1.103.706.385.222.656.372.815.45.16.08.29.141.386.182A.53.53 0 0 0 7 14a.509.509 0 0 0 .238-.055c.098-.043.225-.104.387-.182.162-.079.438-.23.816-.45.378-.222.75-.459 1.102-.707.403-.29.788-.604 1.154-.939a8.435 8.435 0 0 0 1.076-1.163c.312-.42.567-.88.757-1.367a4.19 4.19 0 0 0 .304-1.555v-7a.55.55 0 0 0-.174-.407Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7 12.365s4.306-2.18 4.306-4.717V1.5H7v10.865Z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="12.889"
|
||||||
|
cy="12.889"
|
||||||
|
fill="#F8F9FA"
|
||||||
|
r="4.889"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M11.26 11.717h2.37v-.848c0-.313-.116-.58-.348-.8a1.17 1.17 0 0 0-.838-.332c-.327 0-.606.11-.838.332a1.066 1.066 0 0 0-.347.8v.848Zm3.851.424v2.546a.4.4 0 0 1-.13.3.44.44 0 0 1-.314.124h-4.445a.44.44 0 0 1-.315-.124.4.4 0 0 1-.13-.3V12.14a.4.4 0 0 1 .13-.3.44.44 0 0 1 .315-.124h.148v-.848c0-.542.204-1.008.612-1.397a2.044 2.044 0 0 1 1.462-.583c.568 0 1.056.194 1.463.583.408.39.611.855.611 1.397v.848h.149a.44.44 0 0 1 .315.124.4.4 0 0 1 .13.3Z"
|
||||||
|
fill="#555"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
fill="#fff"
|
||||||
|
height="16"
|
||||||
|
rx="2"
|
||||||
|
width="16"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`AutofillInlineMenuButton initAutofillInlineMenuButton creates the button element with the normal icon when the user's auth status is Unlocked 1`] = `
|
||||||
|
<button
|
||||||
|
aria-label="toggleBitwardenVaultOverlay"
|
||||||
|
class="inline-menu-button"
|
||||||
|
tabindex="-1"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="inline-menu-button-svg-icon logo-icon"
|
||||||
|
fill="none"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
width="14"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.66.175A.566.566 0 0 0 12.25 0H1.75a.559.559 0 0 0-.409.175.561.561 0 0 0-.175.41v7c.002.532.105 1.06.305 1.554.189.488.444.948.756 1.368.322.42.682.81 1.076 1.163.365.335.75.649 1.152.939.35.248.718.483 1.103.706.385.222.656.372.815.45.16.08.29.141.386.182A.53.53 0 0 0 7 14a.509.509 0 0 0 .238-.055c.098-.043.225-.104.387-.182.162-.079.438-.23.816-.45.378-.222.75-.459 1.102-.707.403-.29.788-.604 1.154-.939a8.435 8.435 0 0 0 1.076-1.163c.312-.42.567-.88.757-1.367a4.19 4.19 0 0 0 .304-1.555v-7a.55.55 0 0 0-.174-.407Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7 12.365s4.306-2.18 4.306-4.717V1.5H7v10.865Z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`AutofillOverlayButton initAutofillInlineMenuButton creates the button element with the locked icon when the user's auth status is not Unlocked 1`] = `
|
||||||
|
<button
|
||||||
|
aria-label="toggleBitwardenVaultOverlay"
|
||||||
|
class="inline-menu-button"
|
||||||
|
tabindex="-1"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="inline-menu-button-svg-icon logo-locked-icon"
|
||||||
|
fill="none"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.66.175A.566.566 0 0 0 12.25 0H1.75a.559.559 0 0 0-.409.175.561.561 0 0 0-.175.41v7c.002.532.105 1.06.305 1.554.189.488.444.948.756 1.368.322.42.682.81 1.076 1.163.365.335.75.649 1.152.939.35.248.718.483 1.103.706.385.222.656.372.815.45.16.08.29.141.386.182A.53.53 0 0 0 7 14a.509.509 0 0 0 .238-.055c.098-.043.225-.104.387-.182.162-.079.438-.23.816-.45.378-.222.75-.459 1.102-.707.403-.29.788-.604 1.154-.939a8.435 8.435 0 0 0 1.076-1.163c.312-.42.567-.88.757-1.367a4.19 4.19 0 0 0 .304-1.555v-7a.55.55 0 0 0-.174-.407Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7 12.365s4.306-2.18 4.306-4.717V1.5H7v10.865Z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="12.889"
|
||||||
|
cy="12.889"
|
||||||
|
fill="#F8F9FA"
|
||||||
|
r="4.889"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M11.26 11.717h2.37v-.848c0-.313-.116-.58-.348-.8a1.17 1.17 0 0 0-.838-.332c-.327 0-.606.11-.838.332a1.066 1.066 0 0 0-.347.8v.848Zm3.851.424v2.546a.4.4 0 0 1-.13.3.44.44 0 0 1-.314.124h-4.445a.44.44 0 0 1-.315-.124.4.4 0 0 1-.13-.3V12.14a.4.4 0 0 1 .13-.3.44.44 0 0 1 .315-.124h.148v-.848c0-.542.204-1.008.612-1.397a2.044 2.044 0 0 1 1.462-.583c.568 0 1.056.194 1.463.583.408.39.611.855.611 1.397v.848h.149a.44.44 0 0 1 .315.124.4.4 0 0 1 .13.3Z"
|
||||||
|
fill="#555"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
fill="#fff"
|
||||||
|
height="16"
|
||||||
|
rx="2"
|
||||||
|
width="16"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`AutofillOverlayButton initAutofillInlineMenuButton creates the button element with the normal icon when the user's auth status is Unlocked 1`] = `
|
||||||
|
<button
|
||||||
|
aria-label="toggleBitwardenVaultOverlay"
|
||||||
|
class="inline-menu-button"
|
||||||
|
tabindex="-1"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="inline-menu-button-svg-icon logo-icon"
|
||||||
|
fill="none"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
width="14"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.66.175A.566.566 0 0 0 12.25 0H1.75a.559.559 0 0 0-.409.175.561.561 0 0 0-.175.41v7c.002.532.105 1.06.305 1.554.189.488.444.948.756 1.368.322.42.682.81 1.076 1.163.365.335.75.649 1.152.939.35.248.718.483 1.103.706.385.222.656.372.815.45.16.08.29.141.386.182A.53.53 0 0 0 7 14a.509.509 0 0 0 .238-.055c.098-.043.225-.104.387-.182.162-.079.438-.23.816-.45.378-.222.75-.459 1.102-.707.403-.29.788-.604 1.154-.939a8.435 8.435 0 0 0 1.076-1.163c.312-.42.567-.88.757-1.367a4.19 4.19 0 0 0 .304-1.555v-7a.55.55 0 0 0-.174-.407Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7 12.365s4.306-2.18 4.306-4.717V1.5H7v10.865Z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
@@ -3,13 +3,13 @@
|
|||||||
exports[`AutofillOverlayButton initAutofillOverlayButton creates the button element with the locked icon when the user's auth status is not Unlocked 1`] = `
|
exports[`AutofillOverlayButton initAutofillOverlayButton creates the button element with the locked icon when the user's auth status is not Unlocked 1`] = `
|
||||||
<button
|
<button
|
||||||
aria-label="toggleBitwardenVaultOverlay"
|
aria-label="toggleBitwardenVaultOverlay"
|
||||||
class="overlay-button"
|
class="inline-menu-button"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="overlay-button-svg-icon logo-locked-icon"
|
class="inline-menu-button-svg-icon logo-locked-icon"
|
||||||
fill="none"
|
fill="none"
|
||||||
height="16"
|
height="16"
|
||||||
viewBox="0 0 16 16"
|
viewBox="0 0 16 16"
|
||||||
@@ -57,13 +57,13 @@ exports[`AutofillOverlayButton initAutofillOverlayButton creates the button elem
|
|||||||
exports[`AutofillOverlayButton initAutofillOverlayButton creates the button element with the normal icon when the user's auth status is Unlocked 1`] = `
|
exports[`AutofillOverlayButton initAutofillOverlayButton creates the button element with the normal icon when the user's auth status is Unlocked 1`] = `
|
||||||
<button
|
<button
|
||||||
aria-label="toggleBitwardenVaultOverlay"
|
aria-label="toggleBitwardenVaultOverlay"
|
||||||
class="overlay-button"
|
class="inline-menu-button"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="overlay-button-svg-icon logo-icon"
|
class="inline-menu-button-svg-icon logo-icon"
|
||||||
fill="none"
|
fill="none"
|
||||||
height="14"
|
height="14"
|
||||||
viewBox="0 0 14 14"
|
viewBox="0 0 14 14"
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
|
|
||||||
import { createInitAutofillOverlayButtonMessageMock } from "../../../../spec/autofill-mocks";
|
import { createInitAutofillInlineMenuButtonMessageMock } from "../../../../spec/autofill-mocks";
|
||||||
import { flushPromises, postWindowMessage } from "../../../../spec/testing-utils";
|
import { flushPromises, postWindowMessage } from "../../../../spec/testing-utils";
|
||||||
|
|
||||||
import AutofillOverlayButton from "./autofill-overlay-button";
|
import AutofillInlineMenuButton from "./autofill-inline-menu-button";
|
||||||
|
|
||||||
describe("AutofillOverlayButton", () => {
|
describe("AutofillInlineMenuButton", () => {
|
||||||
globalThis.customElements.define("autofill-overlay-button", AutofillOverlayButton);
|
globalThis.customElements.define("autofill-inline-menu-button", AutofillInlineMenuButton);
|
||||||
|
|
||||||
let autofillOverlayButton: AutofillOverlayButton;
|
let autofillInlineMenuButton: AutofillInlineMenuButton;
|
||||||
const portKey: string = "overlayButtonPortKey";
|
const portKey: string = "inlineMenuButtonPortKey";
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.body.innerHTML = `<autofill-overlay-button></autofill-overlay-button>`;
|
document.body.innerHTML = `<autofill-inline-menu-button></autofill-inline-menu-button>`;
|
||||||
autofillOverlayButton = document.querySelector("autofill-overlay-button");
|
autofillInlineMenuButton = document.querySelector("autofill-inline-menu-button");
|
||||||
autofillOverlayButton["messageOrigin"] = "https://localhost/";
|
autofillInlineMenuButton["messageOrigin"] = "https://localhost/";
|
||||||
jest.spyOn(globalThis.document, "createElement");
|
jest.spyOn(globalThis.document, "createElement");
|
||||||
jest.spyOn(globalThis.parent, "postMessage");
|
jest.spyOn(globalThis.parent, "postMessage");
|
||||||
});
|
});
|
||||||
@@ -26,34 +26,34 @@ describe("AutofillOverlayButton", () => {
|
|||||||
describe("initAutofillInlineMenuButton", () => {
|
describe("initAutofillInlineMenuButton", () => {
|
||||||
it("creates the button element with the locked icon when the user's auth status is not Unlocked", async () => {
|
it("creates the button element with the locked icon when the user's auth status is not Unlocked", async () => {
|
||||||
postWindowMessage(
|
postWindowMessage(
|
||||||
createInitAutofillOverlayButtonMessageMock({
|
createInitAutofillInlineMenuButtonMessageMock({
|
||||||
authStatus: AuthenticationStatus.Locked,
|
authStatus: AuthenticationStatus.Locked,
|
||||||
portKey,
|
portKey,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
expect(autofillOverlayButton["buttonElement"]).toMatchSnapshot();
|
expect(autofillInlineMenuButton["buttonElement"]).toMatchSnapshot();
|
||||||
expect(autofillOverlayButton["buttonElement"].querySelector("svg")).toBe(
|
expect(autofillInlineMenuButton["buttonElement"].querySelector("svg")).toBe(
|
||||||
autofillOverlayButton["logoLockedIconElement"],
|
autofillInlineMenuButton["logoLockedIconElement"],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("creates the button element with the normal icon when the user's auth status is Unlocked ", async () => {
|
it("creates the button element with the normal icon when the user's auth status is Unlocked ", async () => {
|
||||||
postWindowMessage(createInitAutofillOverlayButtonMessageMock({ portKey }));
|
postWindowMessage(createInitAutofillInlineMenuButtonMessageMock({ portKey }));
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
expect(autofillOverlayButton["buttonElement"]).toMatchSnapshot();
|
expect(autofillInlineMenuButton["buttonElement"]).toMatchSnapshot();
|
||||||
expect(autofillOverlayButton["buttonElement"].querySelector("svg")).toBe(
|
expect(autofillInlineMenuButton["buttonElement"].querySelector("svg")).toBe(
|
||||||
autofillOverlayButton["logoIconElement"],
|
autofillInlineMenuButton["logoIconElement"],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("posts a message to the background indicating that the icon was clicked", async () => {
|
it("posts a message to the background indicating that the icon was clicked", async () => {
|
||||||
postWindowMessage(createInitAutofillOverlayButtonMessageMock({ portKey }));
|
postWindowMessage(createInitAutofillInlineMenuButtonMessageMock({ portKey }));
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
autofillOverlayButton["buttonElement"].click();
|
autofillInlineMenuButton["buttonElement"].click();
|
||||||
|
|
||||||
expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
|
expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
|
||||||
{ command: "autofillInlineMenuButtonClicked", portKey },
|
{ command: "autofillInlineMenuButtonClicked", portKey },
|
||||||
@@ -64,10 +64,10 @@ describe("AutofillOverlayButton", () => {
|
|||||||
|
|
||||||
describe("global event listeners", () => {
|
describe("global event listeners", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
postWindowMessage(createInitAutofillOverlayButtonMessageMock({ portKey }));
|
postWindowMessage(createInitAutofillInlineMenuButtonMessageMock({ portKey }));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not post a message to close the autofill overlay if the element is focused during the focus check", async () => {
|
it("does not post a message to close the autofill inline menu if the element is focused during the focus check", async () => {
|
||||||
jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(true);
|
jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(true);
|
||||||
|
|
||||||
postWindowMessage({ command: "checkAutofillInlineMenuButtonFocused" });
|
postWindowMessage({ command: "checkAutofillInlineMenuButtonFocused" });
|
||||||
@@ -78,7 +78,7 @@ describe("AutofillOverlayButton", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("posts a message to close the autofill overlay if the element is not focused during the focus check", async () => {
|
it("posts a message to close the autofill inline menu if the element is not focused during the focus check", async () => {
|
||||||
jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(false);
|
jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(false);
|
||||||
|
|
||||||
postWindowMessage({ command: "checkAutofillInlineMenuButtonFocused" });
|
postWindowMessage({ command: "checkAutofillInlineMenuButtonFocused" });
|
||||||
@@ -91,15 +91,15 @@ describe("AutofillOverlayButton", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("updates the user's auth status", async () => {
|
it("updates the user's auth status", async () => {
|
||||||
autofillOverlayButton["authStatus"] = AuthenticationStatus.Locked;
|
autofillInlineMenuButton["authStatus"] = AuthenticationStatus.Locked;
|
||||||
|
|
||||||
postWindowMessage({
|
postWindowMessage({
|
||||||
command: "updateAutofillOverlayButtonAuthStatus",
|
command: "updateAutofillInlineMenuButtonAuthStatus",
|
||||||
authStatus: AuthenticationStatus.Unlocked,
|
authStatus: AuthenticationStatus.Unlocked,
|
||||||
});
|
});
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
expect(autofillOverlayButton["authStatus"]).toBe(AuthenticationStatus.Unlocked);
|
expect(autofillInlineMenuButton["authStatus"]).toBe(AuthenticationStatus.Unlocked);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates the page color scheme meta tag", async () => {
|
it("updates the page color scheme meta tag", async () => {
|
||||||
@@ -6,37 +6,38 @@ import { EVENTS } from "@bitwarden/common/autofill/constants";
|
|||||||
import { buildSvgDomElement } from "../../../../utils";
|
import { buildSvgDomElement } from "../../../../utils";
|
||||||
import { logoIcon, logoLockedIcon } from "../../../../utils/svg-icons";
|
import { logoIcon, logoLockedIcon } from "../../../../utils/svg-icons";
|
||||||
import {
|
import {
|
||||||
InitAutofillOverlayButtonMessage,
|
InitAutofillInlineMenuButtonMessage,
|
||||||
OverlayButtonMessage,
|
AutofillInlineMenuButtonMessage,
|
||||||
OverlayButtonWindowMessageHandlers,
|
AutofillInlineMenuButtonWindowMessageHandlers,
|
||||||
} from "../../abstractions/autofill-overlay-button";
|
} from "../../abstractions/autofill-inline-menu-button";
|
||||||
import AutofillOverlayPageElement from "../shared/autofill-overlay-page-element";
|
import { AutofillInlineMenuPageElement } from "../shared/autofill-inline-menu-page-element";
|
||||||
|
|
||||||
class AutofillOverlayButton extends AutofillOverlayPageElement {
|
class AutofillInlineMenuButton extends AutofillInlineMenuPageElement {
|
||||||
private authStatus: AuthenticationStatus = AuthenticationStatus.LoggedOut;
|
private authStatus: AuthenticationStatus = AuthenticationStatus.LoggedOut;
|
||||||
private readonly buttonElement: HTMLButtonElement;
|
private readonly buttonElement: HTMLButtonElement;
|
||||||
private readonly logoIconElement: HTMLElement;
|
private readonly logoIconElement: HTMLElement;
|
||||||
private readonly logoLockedIconElement: HTMLElement;
|
private readonly logoLockedIconElement: HTMLElement;
|
||||||
private readonly overlayButtonWindowMessageHandlers: OverlayButtonWindowMessageHandlers = {
|
private readonly inlineMenuButtonWindowMessageHandlers: AutofillInlineMenuButtonWindowMessageHandlers =
|
||||||
initAutofillInlineMenuButton: ({ message }) => this.initAutofillInlineMenuButton(message),
|
{
|
||||||
checkAutofillInlineMenuButtonFocused: () => this.checkButtonFocused(),
|
initAutofillInlineMenuButton: ({ message }) => this.initAutofillInlineMenuButton(message),
|
||||||
updateAutofillOverlayButtonAuthStatus: ({ message }) =>
|
checkAutofillInlineMenuButtonFocused: () => this.checkButtonFocused(),
|
||||||
this.updateAuthStatus(message.authStatus),
|
updateAutofillInlineMenuButtonAuthStatus: ({ message }) =>
|
||||||
updateAutofillInlineMenuColorScheme: ({ message }) => this.updatePageColorScheme(message),
|
this.updateAuthStatus(message.authStatus),
|
||||||
};
|
updateAutofillInlineMenuColorScheme: ({ message }) => this.updatePageColorScheme(message),
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.buttonElement = globalThis.document.createElement("button");
|
this.buttonElement = globalThis.document.createElement("button");
|
||||||
|
|
||||||
this.setupGlobalListeners(this.overlayButtonWindowMessageHandlers);
|
this.setupGlobalListeners(this.inlineMenuButtonWindowMessageHandlers);
|
||||||
|
|
||||||
this.logoIconElement = buildSvgDomElement(logoIcon);
|
this.logoIconElement = buildSvgDomElement(logoIcon);
|
||||||
this.logoIconElement.classList.add("overlay-button-svg-icon", "logo-icon");
|
this.logoIconElement.classList.add("inline-menu-button-svg-icon", "logo-icon");
|
||||||
|
|
||||||
this.logoLockedIconElement = buildSvgDomElement(logoLockedIcon);
|
this.logoLockedIconElement = buildSvgDomElement(logoLockedIcon);
|
||||||
this.logoLockedIconElement.classList.add("overlay-button-svg-icon", "logo-locked-icon");
|
this.logoLockedIconElement.classList.add("inline-menu-button-svg-icon", "logo-locked-icon");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,11 +54,16 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
styleSheetUrl,
|
styleSheetUrl,
|
||||||
translations,
|
translations,
|
||||||
portKey,
|
portKey,
|
||||||
}: InitAutofillOverlayButtonMessage) {
|
}: InitAutofillInlineMenuButtonMessage) {
|
||||||
const linkElement = await this.initOverlayPage("button", styleSheetUrl, translations, portKey);
|
const linkElement = await this.initAutofillInlineMenuPage(
|
||||||
|
"button",
|
||||||
|
styleSheetUrl,
|
||||||
|
translations,
|
||||||
|
portKey,
|
||||||
|
);
|
||||||
this.buttonElement.tabIndex = -1;
|
this.buttonElement.tabIndex = -1;
|
||||||
this.buttonElement.type = "button";
|
this.buttonElement.type = "button";
|
||||||
this.buttonElement.classList.add("overlay-button");
|
this.buttonElement.classList.add("inline-menu-button");
|
||||||
this.buttonElement.setAttribute(
|
this.buttonElement.setAttribute(
|
||||||
"aria-label",
|
"aria-label",
|
||||||
this.getTranslation("toggleBitwardenVaultOverlay"),
|
this.getTranslation("toggleBitwardenVaultOverlay"),
|
||||||
@@ -93,7 +99,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
*
|
*
|
||||||
* @param colorScheme - The color scheme of the iframe's parent page
|
* @param colorScheme - The color scheme of the iframe's parent page
|
||||||
*/
|
*/
|
||||||
private updatePageColorScheme({ colorScheme }: OverlayButtonMessage) {
|
private updatePageColorScheme({ colorScheme }: AutofillInlineMenuButtonMessage) {
|
||||||
const colorSchemeMetaTag = globalThis.document.querySelector("meta[name='color-scheme']");
|
const colorSchemeMetaTag = globalThis.document.querySelector("meta[name='color-scheme']");
|
||||||
colorSchemeMetaTag?.setAttribute("content", colorScheme);
|
colorSchemeMetaTag?.setAttribute("content", colorScheme);
|
||||||
}
|
}
|
||||||
@@ -119,4 +125,4 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AutofillOverlayButton;
|
export default AutofillInlineMenuButton;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { AutofillOverlayElement } from "../../../../enums/autofill-overlay.enum";
|
import { AutofillOverlayElement } from "../../../../enums/autofill-overlay.enum";
|
||||||
|
|
||||||
import AutofillOverlayButton from "./autofill-overlay-button";
|
import AutofillInlineMenuButton from "./autofill-inline-menu-button";
|
||||||
|
|
||||||
require("./button.scss");
|
require("./button.scss");
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
globalThis.customElements.define(AutofillOverlayElement.Button, AutofillOverlayButton);
|
globalThis.customElements.define(AutofillOverlayElement.Button, AutofillInlineMenuButton);
|
||||||
})();
|
})();
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Bitwarden overlay button</title>
|
<title>Bitwarden inline menu button</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<meta name="color-scheme" content="normal" />
|
<meta name="color-scheme" content="normal" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<autofill-overlay-button></autofill-overlay-button>
|
<autofill-inline-menu-button></autofill-inline-menu-button>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ body {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
autofill-overlay-button {
|
autofill-inline-menu-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlay-button {
|
.inline-menu-button {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -28,7 +28,7 @@ autofill-overlay-button {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.overlay-button-svg-icon {
|
.inline-menu-button-svg-icon {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|||||||
@@ -1,5 +1,540 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`AutofillOverlayList initAutofillInlineMenuList the list of ciphers for an authenticated user creates the view for a list of ciphers 1`] = `
|
||||||
|
<div
|
||||||
|
class="overlay-list-container theme_light"
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
class="overlay-actions-list"
|
||||||
|
role="list"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="overlay-actions-list-item"
|
||||||
|
role="listitem"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="cipher-container"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-description="partialUsername, username1"
|
||||||
|
aria-label="fillCredentialsFor website login 1"
|
||||||
|
class="fill-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="cipher-icon"
|
||||||
|
style="background-image: url(https://jest-testing-website.com/image.png);"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="cipher-details"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="cipher-name"
|
||||||
|
title="website login 1"
|
||||||
|
>
|
||||||
|
website login 1
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="cipher-user-login"
|
||||||
|
title="username1"
|
||||||
|
>
|
||||||
|
username1
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="view website login 1, opensInANewWindow"
|
||||||
|
class="view-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
width="20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 .113h20v19.773H0z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="overlay-actions-list-item"
|
||||||
|
role="listitem"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="cipher-container"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-description="partialUsername, username2"
|
||||||
|
aria-label="fillCredentialsFor website login 2"
|
||||||
|
class="fill-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="cipher-icon bwi bw-icon"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="cipher-details"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="cipher-name"
|
||||||
|
title="website login 2"
|
||||||
|
>
|
||||||
|
website login 2
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="cipher-user-login"
|
||||||
|
title="username2"
|
||||||
|
>
|
||||||
|
username2
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="view website login 2, opensInANewWindow"
|
||||||
|
class="view-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
width="20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 .113h20v19.773H0z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="overlay-actions-list-item"
|
||||||
|
role="listitem"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="cipher-container"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-description="partialUsername, "
|
||||||
|
aria-label="fillCredentialsFor "
|
||||||
|
class="fill-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="cipher-icon bwi bw-icon"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="cipher-details"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="view , opensInANewWindow"
|
||||||
|
class="view-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
width="20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 .113h20v19.773H0z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="overlay-actions-list-item"
|
||||||
|
role="listitem"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="cipher-container"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-description="partialUsername, username4"
|
||||||
|
aria-label="fillCredentialsFor website login 4"
|
||||||
|
class="fill-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="cipher-icon"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="25"
|
||||||
|
viewBox="0 0 24 25"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M18.026 17.842c-1.418 1.739-3.517 2.84-5.86 2.84a7.364 7.364 0 0 1-3.431-.848l.062-.15.062-.151.063-.157c.081-.203.17-.426.275-.646.133-.28.275-.522.426-.68.026-.028.101-.075.275-.115.165-.037.376-.059.629-.073.138-.008.288-.014.447-.02.399-.016.847-.034 1.266-.092.314-.044.566-.131.755-.271a.884.884 0 0 0 .352-.555c.037-.2.008-.392-.03-.543-.035-.135-.084-.264-.12-.355l-.01-.03a4.26 4.26 0 0 0-.145-.33c-.126-.264-.237-.497-.288-1.085-.03-.344.09-.73.251-1.138l.089-.22c.05-.123.1-.247.14-.355.064-.171.129-.375.129-.566a1.51 1.51 0 0 0-.134-.569 2.573 2.573 0 0 0-.319-.547c-.246-.323-.635-.669-1.093-.669-.44 0-1.006.169-1.487.368-.246.102-.48.216-.68.33-.192.111-.372.235-.492.359-.93.96-1.48 1.239-1.81 1.258-.277.017-.478-.15-.736-.525a9.738 9.738 0 0 1-.19-.29l-.006-.01a11.568 11.568 0 0 0-.198-.305 2.76 2.76 0 0 0-.521-.6 1.39 1.39 0 0 0-1.088-.314 8.302 8.302 0 0 1 1.987-3.936c.055.342.146.626.272.856.23.42.561.64.926.716.406.086.857-.061 1.26-.216.125-.047.248-.097.372-.147.309-.125.618-.25.947-.341.26-.072.581-.057.959.012.264.049.529.118.8.19l.36.091c.379.094.782.178 1.135.148.374-.032.733-.197.934-.623a.874.874 0 0 0 .024-.752c-.087-.197-.24-.355-.35-.47-.26-.267-.412-.427-.412-.685 0-.125.037-.2.09-.263a.982.982 0 0 1 .303-.211c.059-.03.119-.058.183-.089l.036-.016a3.79 3.79 0 0 0 .236-.118c.047-.026.098-.056.148-.093 1.936.747 3.51 2.287 4.368 4.249a7.739 7.739 0 0 0-.031-.004c-.38-.047-.738-.056-1.063.061-.34.123-.603.368-.817.74-.122.211-.284.43-.463.67l-.095.129c-.207.281-.431.595-.58.92-.15.326-.245.705-.142 1.103.104.397.387.738.837 1.036.099.065.225.112.314.145l.02.008c.108.04.195.074.268.117.07.042.106.08.124.114.017.03.037.087.022.206-.047.376-.069.73-.052 1.034.017.292.071.59.218.809.118.174.12.421.108.786v.01a2.46 2.46 0 0 0 .021.518.809.809 0 0 0 .15.35Zm1.357.059a9.654 9.654 0 0 0 1.62-5.386c0-5.155-3.957-9.334-8.836-9.334-4.88 0-8.836 4.179-8.836 9.334 0 3.495 1.82 6.543 4.513 8.142v.093h.161a8.426 8.426 0 0 0 4.162 1.098c2.953 0 5.568-1.53 7.172-3.882a.569.569 0 0 0 .048-.062l-.004-.003ZM8.152 19.495a43.345 43.345 0 0 1 .098-.238l.057-.142c.082-.205.182-.455.297-.698.143-.301.323-.624.552-.864.163-.172.392-.254.602-.302.219-.05.473-.073.732-.088.162-.01.328-.016.495-.023.386-.015.782-.03 1.168-.084.255-.036.392-.099.461-.15.06-.045.076-.084.083-.12a.534.534 0 0 0-.02-.223 2.552 2.552 0 0 0-.095-.278l-.01-.027a3.128 3.128 0 0 0-.104-.232c-.134-.282-.31-.65-.374-1.381-.046-.533.138-1.063.3-1.472.035-.09.069-.172.1-.249.046-.11.086-.21.123-.31.062-.169.083-.264.083-.312a.812.812 0 0 0-.076-.283 1.867 1.867 0 0 0-.23-.394c-.21-.274-.428-.408-.577-.408-.315 0-.788.13-1.246.32a5.292 5.292 0 0 0-.603.293 1.727 1.727 0 0 0-.347.244c-.936.968-1.641 1.421-2.235 1.457-.646.04-1.036-.413-1.31-.813-.07-.103-.139-.21-.203-.311l-.005-.007c-.064-.101-.125-.197-.188-.29a2.098 2.098 0 0 0-.387-.453.748.748 0 0 0-.436-.18c-.1-.006-.22.005-.365.046a8.707 8.707 0 0 0-.056.992c0 2.957 1.488 5.547 3.716 6.98Zm10.362-2.316.003-.192.002-.046c.01-.305.026-.786-.232-1.169-.036-.054-.082-.189-.096-.444-.014-.243.003-.55.047-.9a1.051 1.051 0 0 0-.105-.649.987.987 0 0 0-.374-.374 2.285 2.285 0 0 0-.367-.166h-.003a1.243 1.243 0 0 1-.205-.088c-.369-.244-.505-.46-.549-.629-.044-.168-.015-.364.099-.61.115-.25.297-.511.507-.796l.089-.12c.178-.239.368-.495.512-.745.152-.263.302-.382.466-.441.18-.065.416-.073.77-.03.142.018.275.04.397.063.274.837.423 1.736.423 2.671a8.45 8.45 0 0 1-1.384 4.665Zm-4.632-12.63a7.362 7.362 0 0 0-1.715-.201c-1.89 0-3.621.716-4.965 1.905.025.54.12.887.24 1.105.13.238.295.34.482.38.2.042.484-.027.905-.188l.328-.13c.32-.13.681-.275 1.048-.377.398-.111.833-.075 1.24 0 .289.053.59.132.871.205l.326.084c.383.094.694.151.932.13.216-.017.326-.092.395-.237.039-.083.027-.114.014-.144-.027-.062-.088-.136-.212-.264l-.043-.044c-.218-.222-.567-.578-.567-1.142 0-.305.101-.547.262-.734.137-.159.308-.267.46-.347Z"
|
||||||
|
fill="#777"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="cipher-details"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="cipher-name"
|
||||||
|
title="website login 4"
|
||||||
|
>
|
||||||
|
website login 4
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="cipher-user-login"
|
||||||
|
title="username4"
|
||||||
|
>
|
||||||
|
username4
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="view website login 4, opensInANewWindow"
|
||||||
|
class="view-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
width="20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 .113h20v19.773H0z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="overlay-actions-list-item"
|
||||||
|
role="listitem"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="cipher-container"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-description="partialUsername, username5"
|
||||||
|
aria-label="fillCredentialsFor website login 5"
|
||||||
|
class="fill-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="cipher-icon"
|
||||||
|
style="background-image: url(https://jest-testing-website.com/image.png);"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="cipher-details"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="cipher-name"
|
||||||
|
title="website login 5"
|
||||||
|
>
|
||||||
|
website login 5
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="cipher-user-login"
|
||||||
|
title="username5"
|
||||||
|
>
|
||||||
|
username5
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="view website login 5, opensInANewWindow"
|
||||||
|
class="view-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
width="20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 .113h20v19.773H0z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="overlay-actions-list-item"
|
||||||
|
role="listitem"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="cipher-container"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-description="partialUsername, username6"
|
||||||
|
aria-label="fillCredentialsFor website login 6"
|
||||||
|
class="fill-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="cipher-icon"
|
||||||
|
style="background-image: url(https://jest-testing-website.com/image.png);"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="cipher-details"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="cipher-name"
|
||||||
|
title="website login 6"
|
||||||
|
>
|
||||||
|
website login 6
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="cipher-user-login"
|
||||||
|
title="username6"
|
||||||
|
>
|
||||||
|
username6
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="view website login 6, opensInANewWindow"
|
||||||
|
class="view-cipher-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
width="20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 .113h20v19.773H0z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`AutofillOverlayList initAutofillInlineMenuList the locked overlay for an unauthenticated user creates the views for the locked overlay 1`] = `
|
||||||
|
<div
|
||||||
|
class="overlay-list-container theme_light"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="locked-overlay overlay-list-message"
|
||||||
|
id="locked-overlay-description"
|
||||||
|
>
|
||||||
|
unlockYourAccount
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="overlay-list-button-container"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="unlockAccount, opensInANewWindow"
|
||||||
|
class="unlock-button overlay-list-button"
|
||||||
|
id="unlock-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="17"
|
||||||
|
viewBox="0 0 17 17"
|
||||||
|
width="17"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8.799 11.633a.68.68 0 0 0-.639.422.695.695 0 0 0-.054.264.682.682 0 0 0 .374.6v1.13a.345.345 0 1 0 .693 0v-1.17a.68.68 0 0 0 .315-.56.695.695 0 0 0-.204-.486.682.682 0 0 0-.485-.2Zm4.554-4.657h-7.11a.438.438 0 0 1-.406-.26A3.81 3.81 0 0 1 5.584 4.3c.112-.435.312-.842.588-1.195A3.196 3.196 0 0 1 7.19 2.25a3.468 3.468 0 0 1 3.225-.059A3.62 3.62 0 0 1 11.94 3.71l.327.59a.502.502 0 1 0 .885-.483l-.307-.552a4.689 4.689 0 0 0-2.209-2.078 4.466 4.466 0 0 0-3.936.185A4.197 4.197 0 0 0 5.37 2.49a4.234 4.234 0 0 0-.768 1.565 4.714 4.714 0 0 0 .162 2.682.182.182 0 0 1-.085.22.173.173 0 0 1-.082.02h-.353a1.368 1.368 0 0 0-1.277.842c-.07.168-.107.348-.109.53v7.1a1.392 1.392 0 0 0 .412.974 1.352 1.352 0 0 0 .974.394h9.117c.363.001.711-.142.97-.4a1.39 1.39 0 0 0 .407-.972v-7.1a1.397 1.397 0 0 0-.414-.973 1.368 1.368 0 0 0-.972-.396Zm.37 8.469a.373.373 0 0 1-.11.26.364.364 0 0 1-.26.107H4.246a.366.366 0 0 1-.26-.107.374.374 0 0 1-.11-.261V8.349a.374.374 0 0 1 .11-.26.366.366 0 0 1 .26-.108h9.116a.366.366 0 0 1 .37.367l-.008 7.097Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M.798.817h16v16h-16z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
unlockAccount
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`AutofillOverlayList initAutofillInlineMenuList the overlay with an empty list of ciphers creates the views for the no results overlay 1`] = `
|
||||||
|
<div
|
||||||
|
class="overlay-list-container theme_light"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="no-items overlay-list-message"
|
||||||
|
>
|
||||||
|
noItemsToShow
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="overlay-list-button-container"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="addNewVaultItem, opensInANewWindow"
|
||||||
|
class="add-new-item-button overlay-list-button"
|
||||||
|
id="new-item-button"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="none"
|
||||||
|
height="17"
|
||||||
|
viewBox="0 0 16 17"
|
||||||
|
width="16"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
clip-path="url(#a)"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15.222 7.914H8.963a.471.471 0 0 1-.34-.147.512.512 0 0 1-.142-.353V.99c0-.133-.05-.26-.14-.354a.471.471 0 0 0-.68 0 .51.51 0 0 0-.142.354v6.424c0 .132-.051.26-.142.353a.474.474 0 0 1-.34.147H.777a.47.47 0 0 0-.34.146.5.5 0 0 0-.14.354.522.522 0 0 0 .14.353.48.48 0 0 0 .34.147h6.26c.128 0 .25.052.34.146.09.094.142.221.142.354v6.576c0 .132.05.26.14.353a.471.471 0 0 0 .68 0 .512.512 0 0 0 .142-.353V9.414c0-.133.051-.26.142-.354a.474.474 0 0 1 .34-.146h6.26c.127 0 .25-.053.34-.147a.511.511 0 0 0 0-.707.472.472 0 0 0-.34-.146Z"
|
||||||
|
fill="#175DDC"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clippath
|
||||||
|
id="a"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 .49h16v16H0z"
|
||||||
|
fill="#fff"
|
||||||
|
/>
|
||||||
|
</clippath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
newItem
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`AutofillOverlayList initAutofillOverlayList the list of ciphers for an authenticated user creates the view for a list of ciphers 1`] = `
|
exports[`AutofillOverlayList initAutofillOverlayList the list of ciphers for an authenticated user creates the view for a list of ciphers 1`] = `
|
||||||
<div
|
<div
|
||||||
class="overlay-list-container theme_light"
|
class="overlay-list-container theme_light"
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import { globeIcon, lockIcon, plusIcon, viewCipherIcon } from "../../../../utils
|
|||||||
import {
|
import {
|
||||||
InitAutofillOverlayListMessage,
|
InitAutofillOverlayListMessage,
|
||||||
OverlayListWindowMessageHandlers,
|
OverlayListWindowMessageHandlers,
|
||||||
} from "../../abstractions/autofill-overlay-list";
|
} from "../../abstractions/autofill-inline-menu-list";
|
||||||
import AutofillOverlayPageElement from "../shared/autofill-overlay-page-element";
|
import { AutofillInlineMenuPageElement } from "../shared/autofill-inline-menu-page-element";
|
||||||
|
|
||||||
class AutofillOverlayList extends AutofillOverlayPageElement {
|
class AutofillOverlayList extends AutofillInlineMenuPageElement {
|
||||||
private overlayListContainer: HTMLDivElement;
|
private overlayListContainer: HTMLDivElement;
|
||||||
private resizeObserver: ResizeObserver;
|
private resizeObserver: ResizeObserver;
|
||||||
private eventHandlersMemo: { [key: string]: EventListener } = {};
|
private eventHandlersMemo: { [key: string]: EventListener } = {};
|
||||||
@@ -54,7 +54,12 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
|
|||||||
ciphers,
|
ciphers,
|
||||||
portKey,
|
portKey,
|
||||||
}: InitAutofillOverlayListMessage) {
|
}: InitAutofillOverlayListMessage) {
|
||||||
const linkElement = await this.initOverlayPage("list", styleSheetUrl, translations, portKey);
|
const linkElement = await this.initAutofillInlineMenuPage(
|
||||||
|
"list",
|
||||||
|
styleSheetUrl,
|
||||||
|
translations,
|
||||||
|
portKey,
|
||||||
|
);
|
||||||
|
|
||||||
const themeClass = `theme_${theme}`;
|
const themeClass = `theme_${theme}`;
|
||||||
globalThis.document.documentElement.classList.add(themeClass);
|
globalThis.document.documentElement.classList.add(themeClass);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { setElementStyles } from "../../../../utils";
|
|||||||
import {
|
import {
|
||||||
InitOverlayElementMessage,
|
InitOverlayElementMessage,
|
||||||
AutofillOverlayMenuContainerWindowMessageHandlers,
|
AutofillOverlayMenuContainerWindowMessageHandlers,
|
||||||
} from "../../abstractions/autofill-overlay-menu-container";
|
} from "../../abstractions/autofill-inline-menu-container";
|
||||||
|
|
||||||
export class AutofillOverlayMenuContainer {
|
export class AutofillOverlayMenuContainer {
|
||||||
private extensionOriginsSet: Set<string>;
|
private extensionOriginsSet: Set<string>;
|
||||||
|
|||||||
@@ -2,16 +2,16 @@ import { EVENTS } from "@bitwarden/common/autofill/constants";
|
|||||||
|
|
||||||
import { RedirectFocusDirection } from "../../../../enums/autofill-overlay.enum";
|
import { RedirectFocusDirection } from "../../../../enums/autofill-overlay.enum";
|
||||||
import {
|
import {
|
||||||
AutofillOverlayPageElementWindowMessage,
|
AutofillInlineMenuPageElementWindowMessage,
|
||||||
AutofillOverlayPageElementWindowMessageHandlers,
|
AutofillInlineMenuPageElementWindowMessageHandlers,
|
||||||
} from "../../abstractions/autofill-overlay-page-element";
|
} from "../../abstractions/autofill-inline-menu-page-element";
|
||||||
|
|
||||||
class AutofillOverlayPageElement extends HTMLElement {
|
export class AutofillInlineMenuPageElement extends HTMLElement {
|
||||||
protected shadowDom: ShadowRoot;
|
protected shadowDom: ShadowRoot;
|
||||||
protected messageOrigin: string;
|
protected messageOrigin: string;
|
||||||
protected translations: Record<string, string>;
|
protected translations: Record<string, string>;
|
||||||
private portKey: string;
|
private portKey: string;
|
||||||
protected windowMessageHandlers: AutofillOverlayPageElementWindowMessageHandlers;
|
protected windowMessageHandlers: AutofillInlineMenuPageElementWindowMessageHandlers;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@@ -28,7 +28,7 @@ class AutofillOverlayPageElement extends HTMLElement {
|
|||||||
* @param translations - The translations to apply to the page
|
* @param translations - The translations to apply to the page
|
||||||
* @param portKey - Background generated key that allows the port to communicate with the background
|
* @param portKey - Background generated key that allows the port to communicate with the background
|
||||||
*/
|
*/
|
||||||
protected async initOverlayPage(
|
protected async initAutofillInlineMenuPage(
|
||||||
elementName: "button" | "list",
|
elementName: "button" | "list",
|
||||||
styleSheetUrl: string,
|
styleSheetUrl: string,
|
||||||
translations: Record<string, string>,
|
translations: Record<string, string>,
|
||||||
@@ -53,7 +53,7 @@ class AutofillOverlayPageElement extends HTMLElement {
|
|||||||
*
|
*
|
||||||
* @param message - The message to post
|
* @param message - The message to post
|
||||||
*/
|
*/
|
||||||
protected postMessageToParent(message: AutofillOverlayPageElementWindowMessage) {
|
protected postMessageToParent(message: AutofillInlineMenuPageElementWindowMessage) {
|
||||||
globalThis.parent.postMessage({ portKey: this.portKey, ...message }, "*");
|
globalThis.parent.postMessage({ portKey: this.portKey, ...message }, "*");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ class AutofillOverlayPageElement extends HTMLElement {
|
|||||||
* @param windowMessageHandlers - The window message handlers to use
|
* @param windowMessageHandlers - The window message handlers to use
|
||||||
*/
|
*/
|
||||||
protected setupGlobalListeners(
|
protected setupGlobalListeners(
|
||||||
windowMessageHandlers: AutofillOverlayPageElementWindowMessageHandlers,
|
windowMessageHandlers: AutofillInlineMenuPageElementWindowMessageHandlers,
|
||||||
) {
|
) {
|
||||||
this.windowMessageHandlers = windowMessageHandlers;
|
this.windowMessageHandlers = windowMessageHandlers;
|
||||||
|
|
||||||
@@ -133,25 +133,23 @@ class AutofillOverlayPageElement extends HTMLElement {
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
if (event.code === "Tab") {
|
if (event.code === "Tab") {
|
||||||
this.redirectOverlayFocusOutMessage(
|
this.sendRedirectFocusOutMessage(
|
||||||
event.shiftKey ? RedirectFocusDirection.Previous : RedirectFocusDirection.Next,
|
event.shiftKey ? RedirectFocusDirection.Previous : RedirectFocusDirection.Next,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.redirectOverlayFocusOutMessage(RedirectFocusDirection.Current);
|
this.sendRedirectFocusOutMessage(RedirectFocusDirection.Current);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redirects the overlay focus out to the previous element on KeyDown of the `Tab+Shift` keys.
|
* Redirects the inline menu focus out to the previous element on KeyDown of the `Tab+Shift` keys.
|
||||||
* Redirects the overlay focus out to the next element on KeyDown of the `Tab` key.
|
* Redirects the inline menu focus out to the next element on KeyDown of the `Tab` key.
|
||||||
* Redirects the overlay focus out to the current element on KeyDown of the `Escape` key.
|
* Redirects the inline menu focus out to the current element on KeyDown of the `Escape` key.
|
||||||
*
|
*
|
||||||
* @param direction - The direction to redirect the focus out
|
* @param direction - The direction to redirect the focus out
|
||||||
*/
|
*/
|
||||||
private redirectOverlayFocusOutMessage(direction: string) {
|
private sendRedirectFocusOutMessage(direction: string) {
|
||||||
this.postMessageToParent({ command: "redirectAutofillInlineMenuFocusOut", direction });
|
this.postMessageToParent({ command: "redirectAutofillInlineMenuFocusOut", direction });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AutofillOverlayPageElement;
|
|
||||||
@@ -15,7 +15,7 @@ export type AutofillOverlayContentExtensionMessageHandlers = {
|
|||||||
[key: string]: CallableFunction;
|
[key: string]: CallableFunction;
|
||||||
openAutofillInlineMenu: ({ message }: AutofillExtensionMessageParam) => void;
|
openAutofillInlineMenu: ({ message }: AutofillExtensionMessageParam) => void;
|
||||||
addNewVaultItemFromOverlay: () => void;
|
addNewVaultItemFromOverlay: () => void;
|
||||||
blurMostRecentOverlayField: () => void;
|
blurMostRecentlyFocusedField: () => void;
|
||||||
bgUnlockPopoutOpened: () => void;
|
bgUnlockPopoutOpened: () => void;
|
||||||
bgVaultItemRepromptPopoutOpened: () => void;
|
bgVaultItemRepromptPopoutOpened: () => void;
|
||||||
redirectAutofillInlineMenuFocusOut: ({ message }: AutofillExtensionMessageParam) => void;
|
redirectAutofillInlineMenuFocusOut: ({ message }: AutofillExtensionMessageParam) => void;
|
||||||
@@ -32,6 +32,6 @@ export interface AutofillOverlayContentService {
|
|||||||
autofillFieldElement: ElementWithOpId<FormFieldElement>,
|
autofillFieldElement: ElementWithOpId<FormFieldElement>,
|
||||||
autofillFieldData: AutofillField,
|
autofillFieldData: AutofillField,
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
blurMostRecentOverlayField(isRemovingOverlay?: boolean): void;
|
blurMostRecentlyFocusedField(isRemovingInlineMenu?: boolean): void;
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -884,7 +884,7 @@ describe("AutofillOverlayContentService", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("blurMostRecentOverlayField", () => {
|
describe("blurMostRecentlyFocusedField", () => {
|
||||||
it("removes focus from the most recently focused overlay field", () => {
|
it("removes focus from the most recently focused overlay field", () => {
|
||||||
const mostRecentlyFocusedField = document.createElement(
|
const mostRecentlyFocusedField = document.createElement(
|
||||||
"input",
|
"input",
|
||||||
@@ -892,7 +892,7 @@ describe("AutofillOverlayContentService", () => {
|
|||||||
autofillOverlayContentService["mostRecentlyFocusedField"] = mostRecentlyFocusedField;
|
autofillOverlayContentService["mostRecentlyFocusedField"] = mostRecentlyFocusedField;
|
||||||
jest.spyOn(mostRecentlyFocusedField, "blur");
|
jest.spyOn(mostRecentlyFocusedField, "blur");
|
||||||
|
|
||||||
autofillOverlayContentService["blurMostRecentOverlayField"]();
|
autofillOverlayContentService["blurMostRecentlyFocusedField"]();
|
||||||
|
|
||||||
expect(mostRecentlyFocusedField.blur).toHaveBeenCalled();
|
expect(mostRecentlyFocusedField.blur).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
|||||||
readonly extensionMessageHandlers: AutofillOverlayContentExtensionMessageHandlers = {
|
readonly extensionMessageHandlers: AutofillOverlayContentExtensionMessageHandlers = {
|
||||||
openAutofillInlineMenu: ({ message }) => this.openAutofillInlineMenu(message),
|
openAutofillInlineMenu: ({ message }) => this.openAutofillInlineMenu(message),
|
||||||
addNewVaultItemFromOverlay: () => this.addNewVaultItem(),
|
addNewVaultItemFromOverlay: () => this.addNewVaultItem(),
|
||||||
blurMostRecentOverlayField: () => this.blurMostRecentOverlayField(),
|
blurMostRecentlyFocusedField: () => this.blurMostRecentlyFocusedField(),
|
||||||
bgUnlockPopoutOpened: () => this.blurMostRecentOverlayField(true),
|
bgUnlockPopoutOpened: () => this.blurMostRecentlyFocusedField(true),
|
||||||
bgVaultItemRepromptPopoutOpened: () => this.blurMostRecentOverlayField(true),
|
bgVaultItemRepromptPopoutOpened: () => this.blurMostRecentlyFocusedField(true),
|
||||||
redirectAutofillInlineMenuFocusOut: ({ message }) =>
|
redirectAutofillInlineMenuFocusOut: ({ message }) =>
|
||||||
this.redirectInlineMenuFocusOut(message?.data?.direction),
|
this.redirectInlineMenuFocusOut(message?.data?.direction),
|
||||||
updateAutofillInlineMenuVisibility: ({ message }) =>
|
updateAutofillInlineMenuVisibility: ({ message }) =>
|
||||||
@@ -154,10 +154,10 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
|
|||||||
/**
|
/**
|
||||||
* Removes focus from the most recently focused field element.
|
* Removes focus from the most recently focused field element.
|
||||||
*/
|
*/
|
||||||
blurMostRecentOverlayField(isRemovingOverlay: boolean = false) {
|
blurMostRecentlyFocusedField(isRemovingInlineMenu: boolean = false) {
|
||||||
this.mostRecentlyFocusedField?.blur();
|
this.mostRecentlyFocusedField?.blur();
|
||||||
|
|
||||||
if (isRemovingOverlay) {
|
if (isRemovingInlineMenu) {
|
||||||
void sendExtensionMessage("closeAutofillInlineMenu");
|
void sendExtensionMessage("closeAutofillInlineMenu");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AutofillOverlayInlineMenuElements } from "../overlay/inline-menu/abstractions/autofill-overlay-inline-menu-elements";
|
import { AutofillInlineMenuContentService } from "../overlay/inline-menu/abstractions/autofill-inline-menu-content.service";
|
||||||
import { FillableFormFieldElement, FormFieldElement } from "../types";
|
import { FillableFormFieldElement, FormFieldElement } from "../types";
|
||||||
|
|
||||||
import { DomElementVisibilityService as domElementVisibilityServiceInterface } from "./abstractions/dom-element-visibility.service";
|
import { DomElementVisibilityService as domElementVisibilityServiceInterface } from "./abstractions/dom-element-visibility.service";
|
||||||
@@ -6,7 +6,7 @@ import { DomElementVisibilityService as domElementVisibilityServiceInterface } f
|
|||||||
class DomElementVisibilityService implements domElementVisibilityServiceInterface {
|
class DomElementVisibilityService implements domElementVisibilityServiceInterface {
|
||||||
private cachedComputedStyle: CSSStyleDeclaration | null = null;
|
private cachedComputedStyle: CSSStyleDeclaration | null = null;
|
||||||
|
|
||||||
constructor(private inlineMenuElements?: AutofillOverlayInlineMenuElements) {}
|
constructor(private inlineMenuElements?: AutofillInlineMenuContentService) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a form field is viewable. This is done by checking if the element is within the
|
* Checks if a form field is viewable. This is done by checking if the element is within the
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import AutofillField from "../models/autofill-field";
|
|||||||
import AutofillForm from "../models/autofill-form";
|
import AutofillForm from "../models/autofill-form";
|
||||||
import AutofillPageDetails from "../models/autofill-page-details";
|
import AutofillPageDetails from "../models/autofill-page-details";
|
||||||
import AutofillScript, { FillScript } from "../models/autofill-script";
|
import AutofillScript, { FillScript } from "../models/autofill-script";
|
||||||
import { InitAutofillOverlayButtonMessage } from "../overlay/inline-menu/abstractions/autofill-overlay-button";
|
import { InitAutofillInlineMenuButtonMessage } from "../overlay/inline-menu/abstractions/autofill-inline-menu-button";
|
||||||
import { InitAutofillOverlayListMessage } from "../overlay/inline-menu/abstractions/autofill-overlay-list";
|
import { InitAutofillOverlayListMessage } from "../overlay/inline-menu/abstractions/autofill-inline-menu-list";
|
||||||
import { GenerateFillScriptOptions, PageDetail } from "../services/abstractions/autofill.service";
|
import { GenerateFillScriptOptions, PageDetail } from "../services/abstractions/autofill.service";
|
||||||
|
|
||||||
function createAutofillFormMock(customFields = {}): AutofillForm {
|
function createAutofillFormMock(customFields = {}): AutofillForm {
|
||||||
@@ -165,9 +165,9 @@ const overlayPagesTranslations = {
|
|||||||
newItem: "newItem",
|
newItem: "newItem",
|
||||||
addNewVaultItem: "addNewVaultItem",
|
addNewVaultItem: "addNewVaultItem",
|
||||||
};
|
};
|
||||||
function createInitAutofillOverlayButtonMessageMock(
|
function createInitAutofillInlineMenuButtonMessageMock(
|
||||||
customFields = {},
|
customFields = {},
|
||||||
): InitAutofillOverlayButtonMessage {
|
): InitAutofillInlineMenuButtonMessage {
|
||||||
return {
|
return {
|
||||||
command: "initAutofillInlineMenuButton",
|
command: "initAutofillInlineMenuButton",
|
||||||
translations: overlayPagesTranslations,
|
translations: overlayPagesTranslations,
|
||||||
@@ -297,7 +297,7 @@ export {
|
|||||||
createChromeTabMock,
|
createChromeTabMock,
|
||||||
createGenerateFillScriptOptionsMock,
|
createGenerateFillScriptOptionsMock,
|
||||||
createAutofillScriptMock,
|
createAutofillScriptMock,
|
||||||
createInitAutofillOverlayButtonMessageMock,
|
createInitAutofillInlineMenuButtonMessageMock,
|
||||||
createInitAutofillOverlayListMessageMock,
|
createInitAutofillOverlayListMessageMock,
|
||||||
createFocusedFieldDataMock,
|
createFocusedFieldDataMock,
|
||||||
createPortSpyMock,
|
createPortSpyMock,
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ const mainConfig = {
|
|||||||
"content/fido2/page-script": "./src/vault/fido2/content/page-script.ts",
|
"content/fido2/page-script": "./src/vault/fido2/content/page-script.ts",
|
||||||
"notification/bar": "./src/autofill/notification/bar.ts",
|
"notification/bar": "./src/autofill/notification/bar.ts",
|
||||||
"overlay/button":
|
"overlay/button":
|
||||||
"./src/autofill/overlay/inline-menu/pages/button/bootstrap-autofill-overlay-button.ts",
|
"./src/autofill/overlay/inline-menu/pages/button/bootstrap-autofill-inline-menu-button.ts",
|
||||||
"overlay/list":
|
"overlay/list":
|
||||||
"./src/autofill/overlay/inline-menu/pages/list/bootstrap-autofill-overlay-list.ts",
|
"./src/autofill/overlay/inline-menu/pages/list/bootstrap-autofill-overlay-list.ts",
|
||||||
"overlay/menu":
|
"overlay/menu":
|
||||||
|
|||||||
Reference in New Issue
Block a user