Tweak browser extension popup dismissed checks (#1931)

This commit is contained in:
Leendert de Borst
2026-04-18 21:16:10 +02:00
committed by Leendert de Borst
parent 6b75ccd2d1
commit 36ade373ff
3 changed files with 78 additions and 11 deletions

View File

@@ -656,6 +656,13 @@ export default defineContentScript({
};
if (authStatus.isVaultLocked) {
// Check if the user has dismissed the vault locked popup
const dismissUntil = await LocalPreferencesService.getVaultLockedDismissUntil();
if (dismissUntil && Date.now() < dismissUntil) {
// User has dismissed the popup, don't show it again
return;
}
// Vault is locked, show vault locked popup
const { createVaultLockedPopup } = await import('@/entrypoints/contentScript/Popup');
createVaultLockedPopup(inputElement, container);

View File

@@ -1,6 +1,6 @@
import { sendMessage } from 'webext-bridge/content-script';
import { openAutofillPopup, openTotpPopup } from '@/entrypoints/contentScript/Popup';
import { openAutofillPopup, openTotpPopup, removeExistingPopup } from '@/entrypoints/contentScript/Popup';
import { LOGO_MARK_SVG } from '@/utils/constants/logo';
import type { Item } from '@/utils/dist/core/models/vault';
@@ -290,6 +290,15 @@ export function injectIcon(input: HTMLInputElement, container: HTMLElement, fiel
window.addEventListener('scroll', updateIconPosition, true);
window.addEventListener('resize', updateIconPosition);
/*
* Prevent mousedown from propagating to document to avoid triggering
* the "click outside" handler that would close the popup immediately.
*/
icon.addEventListener('mousedown', (e: MouseEvent) => {
e.preventDefault();
e.stopPropagation();
});
// Add click event to trigger the autofill popup and refocus the input
icon.addEventListener('click', async (e: MouseEvent) => {
e.preventDefault();
@@ -303,11 +312,24 @@ export function injectIcon(input: HTMLInputElement, container: HTMLElement, fiel
setTimeout(() => actualInput.focus(), 0);
// Open the appropriate popup based on field type
if (fieldType === DetectedFieldType.Totp) {
openTotpPopup(actualInput, container);
/*
* Toggle the popup: if it's already open, close it; otherwise open it.
* Check if popup exists in the container.
*/
const existingPopup = container.querySelector('#aliasvault-credential-popup');
if (existingPopup) {
// Popup is open, close it
removeExistingPopup(container);
} else {
openAutofillPopup(actualInput, container);
/*
* Open the appropriate popup based on field type.
* Pass forceShow=true since this is a manual user action (icon click).
*/
if (fieldType === DetectedFieldType.Totp) {
openTotpPopup(actualInput, container, true);
} else {
openAutofillPopup(actualInput, container, true);
}
}
});

View File

@@ -109,8 +109,11 @@ const createSuggestedNameSpan = (name: string): HTMLElement => {
/**
* Open (or refresh) the autofill popup including check if vault is locked.
* @param input - The input element that triggered the popup
* @param container - The container element
* @param forceShow - If true, always show the popup even if dismissed (for manual icon clicks)
*/
export function openAutofillPopup(input: HTMLInputElement, container: HTMLElement) : void {
export function openAutofillPopup(input: HTMLInputElement, container: HTMLElement, forceShow: boolean = false) : void {
createLoadingPopup(input, '', container);
/**
@@ -140,6 +143,16 @@ export function openAutofillPopup(input: HTMLInputElement, container: HTMLElemen
if (response.success) {
await createAutofillPopup(input, response.items, container);
} else {
// Check if the user has dismissed the vault locked popup (only for auto-show, not manual clicks)
if (!forceShow) {
const dismissUntil = await LocalPreferencesService.getVaultLockedDismissUntil();
if (dismissUntil && Date.now() < dismissUntil) {
// User has dismissed the popup, don't show it again
removeExistingPopup(container);
return;
}
}
await createVaultLockedPopup(input, container);
}
})();
@@ -148,8 +161,11 @@ export function openAutofillPopup(input: HTMLInputElement, container: HTMLElemen
/**
* Open (or refresh) the TOTP autofill popup for 2FA code fields.
* Shows only items that have TOTP codes stored.
* @param input - The input element that triggered the popup
* @param container - The container element
* @param forceShow - If true, always show the popup even if dismissed (for manual icon clicks)
*/
export function openTotpPopup(input: HTMLInputElement, container: HTMLElement) : void {
export function openTotpPopup(input: HTMLInputElement, container: HTMLElement, forceShow: boolean = false) : void {
createLoadingPopup(input, '', container);
/**
@@ -176,6 +192,16 @@ export function openTotpPopup(input: HTMLInputElement, container: HTMLElement) :
if (response.success) {
await createTotpPopup(input, response.items, container);
} else {
// Check if the user has dismissed the vault locked popup (only for auto-show, not manual clicks)
if (!forceShow) {
const dismissUntil = await LocalPreferencesService.getVaultLockedDismissUntil();
if (dismissUntil && Date.now() < dismissUntil) {
// User has dismissed the popup, don't show it again
removeExistingPopup(container);
return;
}
}
await createVaultLockedPopup(input, container);
}
})();
@@ -349,8 +375,11 @@ async function createTotpPopup(input: HTMLInputElement, items: Item[] | undefine
return;
}
// Check if the click is on the AliasVault icon
const isIconClick = targetElement.closest('.av-input-icon') !== null;
// Check if the click is outside the popup and outside the shadow UI
if (popupElement && !popupElement.contains(target) && !input.contains(target) && targetElement.tagName !== 'ALIASVAULT-UI') {
if (popupElement && !popupElement.contains(target) && !input.contains(target) && !isIconClick && targetElement.tagName !== 'ALIASVAULT-UI') {
removeExistingPopup(rootContainer);
}
};
@@ -995,8 +1024,11 @@ export async function createAutofillPopup(input: HTMLInputElement, items: Item[]
return;
}
// Check if the click is on the AliasVault icon
const isIconClick = targetElement.closest('.av-input-icon') !== null;
// Check if the click is outside the popup and outside the shadow UI
if (popup && !popup.contains(target) && !input.contains(target) && targetElement.tagName !== 'ALIASVAULT-UI') {
if (popup && !popup.contains(target) && !input.contains(target) && !isIconClick && targetElement.tagName !== 'ALIASVAULT-UI') {
removeExistingPopup(rootContainer);
}
};
@@ -1083,8 +1115,11 @@ export async function createVaultLockedPopup(input: HTMLInputElement, rootContai
const target = event.target as Node;
const targetElement = event.target as HTMLElement;
// Check if the click is on the AliasVault icon
const isIconClick = targetElement.closest('.av-input-icon') !== null;
// Check if the click is outside the popup and outside the shadow UI
if (popup && !popup.contains(target) && !input.contains(target) && targetElement.tagName !== 'ALIASVAULT-UI') {
if (popup && !popup.contains(target) && !input.contains(target) && !isIconClick && targetElement.tagName !== 'ALIASVAULT-UI') {
removeExistingPopup(rootContainer);
document.removeEventListener('mousedown', handleClickOutside);
}
@@ -2502,8 +2537,11 @@ export async function createUpgradeRequiredPopup(input: HTMLInputElement, rootCo
const target = event.target as Node;
const targetElement = event.target as HTMLElement;
// Check if the click is on the AliasVault icon
const isIconClick = targetElement.closest('.av-input-icon') !== null;
// Check if the click is outside the popup and outside the shadow UI
if (popup && !popup.contains(target) && !input.contains(target) && targetElement.tagName !== 'ALIASVAULT-UI') {
if (popup && !popup.contains(target) && !input.contains(target) && !isIconClick && targetElement.tagName !== 'ALIASVAULT-UI') {
removeExistingPopup(rootContainer);
document.removeEventListener('mousedown', handleClickOutside);
}