mirror of
https://github.com/bitwarden/browser
synced 2026-01-31 00:33:33 +00:00
Handle when events are intercepted by the host site
This commit is contained in:
@@ -1226,6 +1226,36 @@ describe("AutofillInlineMenuList", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("pointerdown event", () => {
|
||||
it("prevents list updates from destroying buttons mid-click", async () => {
|
||||
postWindowMessage(
|
||||
createInitAutofillInlineMenuListMessageMock({
|
||||
authStatus: AuthenticationStatus.Unlocked,
|
||||
ciphers: [],
|
||||
portKey,
|
||||
}),
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
const newItemButton = autofillInlineMenuList["newItemButtonElement"];
|
||||
expect(newItemButton).toBeDefined();
|
||||
|
||||
const pointerDownEvent = new Event("pointerdown", { bubbles: true });
|
||||
globalThis.document.dispatchEvent(pointerDownEvent);
|
||||
|
||||
postWindowMessage({
|
||||
command: "updateAutofillInlineMenuListCiphers",
|
||||
ciphers: [],
|
||||
showInlineMenuAccountCreation: true,
|
||||
portKey,
|
||||
token: "test-token",
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(autofillInlineMenuList["newItemButtonElement"]).toBe(newItemButton);
|
||||
});
|
||||
});
|
||||
|
||||
describe("keydown event", () => {
|
||||
beforeEach(() => {
|
||||
postWindowMessage(createInitAutofillInlineMenuListMessageMock({ portKey }));
|
||||
|
||||
@@ -476,6 +476,11 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
|
||||
ciphers,
|
||||
showInlineMenuAccountCreation,
|
||||
}: UpdateAutofillInlineMenuListCiphersParams) {
|
||||
// Skip updates while user is actively clicking to prevent destroying buttons mid-click
|
||||
if (this.pointerIsDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isPasskeyAuthInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ export class AutofillInlineMenuPageElement extends HTMLElement {
|
||||
/** Non-null asserted. */
|
||||
protected windowMessageHandlers!: AutofillInlineMenuPageElementWindowMessageHandlers;
|
||||
private token?: string;
|
||||
protected pointerIsDown = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -94,8 +95,25 @@ export class AutofillInlineMenuPageElement extends HTMLElement {
|
||||
globalThis.addEventListener(EVENTS.MESSAGE, this.handleWindowMessage);
|
||||
globalThis.addEventListener(EVENTS.BLUR, this.handleWindowBlurEvent);
|
||||
globalThis.document.addEventListener(EVENTS.KEYDOWN, this.handleDocumentKeyDownEvent);
|
||||
globalThis.document.addEventListener(EVENTS.POINTERDOWN, this.handlePointerDownEvent, true);
|
||||
globalThis.document.addEventListener(EVENTS.POINTERUP, this.handlePointerUpEvent, true);
|
||||
globalThis.document.addEventListener(EVENTS.POINTERCANCEL, this.handlePointerUpEvent, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles pointerdown events. Sets a flag when the user is actively interacting with the menu.
|
||||
*/
|
||||
private handlePointerDownEvent = () => {
|
||||
this.pointerIsDown = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles pointerup/pointercancel events. Clears the `pointerIsDown` flag.
|
||||
*/
|
||||
private handlePointerUpEvent = () => {
|
||||
this.pointerIsDown = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles window messages from the parent window.
|
||||
*
|
||||
|
||||
@@ -25,6 +25,9 @@ export const EVENTS = {
|
||||
MOUSELEAVE: "mouseleave",
|
||||
MOUSEUP: "mouseup",
|
||||
MOUSEOUT: "mouseout",
|
||||
POINTERDOWN: "pointerdown",
|
||||
POINTERUP: "pointerup",
|
||||
POINTERCANCEL: "pointercancel",
|
||||
SUBMIT: "submit",
|
||||
} as const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user