1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-22 16:29:09 +01:00

[PM-5189] Reworking how we handle updating the inline menu position

This commit is contained in:
Cesar Gonzalez 2024-06-18 16:00:26 -05:00
parent 89ad8e485a
commit 3e74eb7606
No known key found for this signature in database
GPG Key ID: 3381A5457F8CCECF
2 changed files with 63 additions and 47 deletions

View File

@ -392,26 +392,26 @@ describe("OverlayBackground", () => {
expect(getFrameDetailsSpy).toHaveBeenCalledWith({ tabId, frameId: middleFrameId });
});
it("triggers an update of the inline menu position after rebuilding sub frames", async () => {
jest.useFakeTimers();
overlayBackground["delayedUpdateInlineMenuPositionTimeout"] = setTimeout(jest.fn, 650);
const sender = mock<chrome.runtime.MessageSender>({ tab, frameId: middleFrameId });
jest.spyOn(overlayBackground as any, "updateInlineMenuPositionAfterRepositionEvent");
sendMockExtensionMessage(
{
command: "repositionAutofillInlineMenuForSubFrame",
triggerInlineMenuPositionUpdate: true,
},
sender,
);
await flushPromises();
jest.advanceTimersByTime(650);
expect(
overlayBackground["updateInlineMenuPositionAfterRepositionEvent"],
).toHaveBeenCalled();
});
// it("triggers an update of the inline menu position after rebuilding sub frames", async () => {
// jest.useFakeTimers();
// overlayBackground["delayedUpdateInlineMenuPositionTimeout"] = setTimeout(jest.fn, 650);
// const sender = mock<chrome.runtime.MessageSender>({ tab, frameId: middleFrameId });
// jest.spyOn(overlayBackground as any, "updateInlineMenuPositionAfterRepositionEvent");
//
// sendMockExtensionMessage(
// {
// command: "repositionAutofillInlineMenuForSubFrame",
// triggerInlineMenuPositionUpdate: true,
// },
// sender,
// );
// await flushPromises();
// jest.advanceTimersByTime(650);
//
// expect(
// overlayBackground["updateInlineMenuPositionAfterRepositionEvent"],
// ).toHaveBeenCalled();
// });
});
describe("updateInlineMenuPositionAfterRepositionEvent", () => {

View File

@ -1,4 +1,4 @@
import { firstValueFrom, Subject, throttleTime } from "rxjs";
import { firstValueFrom, merge, Subject, throttleTime } from "rxjs";
import { debounceTime, switchMap } from "rxjs/operators";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
@ -64,8 +64,9 @@ export class OverlayBackground implements OverlayBackgroundInterface {
private inlineMenuListPort: chrome.runtime.Port;
private inlineMenuCiphers: Map<string, CipherView> = new Map();
private inlineMenuPageTranslations: Record<string, string>;
private inlineMenuFadeInTimeout: number | NodeJS.Timeout;
private delayedCloseTimeout: number | NodeJS.Timeout;
private startInlineMenuFadeInSubject = new Subject<void>();
private cancelInlineMenuFadeInSubject = new Subject<boolean>();
private repositionInlineMenuSubject = new Subject<chrome.runtime.MessageSender>();
private rebuildSubFrameOffsetsSubject = new Subject<chrome.runtime.MessageSender>();
private focusedFieldData: FocusedFieldData;
@ -140,6 +141,20 @@ export class OverlayBackground implements OverlayBackgroundInterface {
private platformUtilsService: PlatformUtilsService,
private themeStateService: ThemeStateService,
) {
this.initOverlayObservables();
}
/**
* Sets up the extension message listeners and gets the settings for the
* overlay's visibility and the user's authentication status.
*/
async init() {
this.setupExtensionMessageListeners();
const env = await firstValueFrom(this.environmentService.environment$);
this.iconsServerUrl = env.getIconsUrl();
}
private initOverlayObservables() {
this.repositionInlineMenuSubject
.pipe(
debounceTime(500),
@ -152,16 +167,14 @@ export class OverlayBackground implements OverlayBackgroundInterface {
switchMap((sender) => this.rebuildSubFrameOffsets(sender)),
)
.subscribe();
}
/**
* Sets up the extension message listeners and gets the settings for the
* overlay's visibility and the user's authentication status.
*/
async init() {
this.setupExtensionMessageListeners();
const env = await firstValueFrom(this.environmentService.environment$);
this.iconsServerUrl = env.getIconsUrl();
// FadeIn Observable behavior
merge(
this.startInlineMenuFadeInSubject.pipe(debounceTime(150)),
this.cancelInlineMenuFadeInSubject,
)
.pipe(switchMap((cancelSignal) => this.triggerInlineMenuFadeIn(!!cancelSignal)))
.subscribe();
}
/**
@ -623,7 +636,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
return;
}
this.clearInlineMenuFadeInTimeout();
this.cancelInlineMenuFadeIn();
await BrowserApi.tabSendMessage(
sender.tab,
@ -642,7 +655,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
command: "updateAutofillInlineMenuPosition",
styles: this.getInlineMenuButtonPosition(subFrameOffsets),
});
this.setInlineMenuFadeInTimeout();
this.startInlineMenuFadeIn();
return;
}
@ -651,30 +664,33 @@ export class OverlayBackground implements OverlayBackgroundInterface {
command: "updateAutofillInlineMenuPosition",
styles: this.getInlineMenuListPosition(subFrameOffsets),
});
this.setInlineMenuFadeInTimeout();
this.startInlineMenuFadeIn();
}
/**
* Handles updating the opacity of both the inline menu button and list.
* This is used to simultaneously fade in the inline menu elements.
*/
private setInlineMenuFadeInTimeout() {
this.clearInlineMenuFadeInTimeout();
this.inlineMenuFadeInTimeout = globalThis.setTimeout(() => {
const message = { command: "fadeInAutofillInlineMenuIframe" };
this.inlineMenuButtonPort?.postMessage(message);
this.inlineMenuListPort?.postMessage(message);
}, 150);
private startInlineMenuFadeIn() {
this.cancelInlineMenuFadeIn();
this.startInlineMenuFadeInSubject.next();
}
/**
* Clears the timeout used to fade in the inline menu elements.
*/
private clearInlineMenuFadeInTimeout() {
if (this.inlineMenuFadeInTimeout) {
globalThis.clearTimeout(this.inlineMenuFadeInTimeout);
private cancelInlineMenuFadeIn() {
this.cancelInlineMenuFadeInSubject.next(true);
}
private async triggerInlineMenuFadeIn(cancelFadeIn: boolean = false) {
if (cancelFadeIn) {
return;
}
const message = { command: "fadeInAutofillInlineMenuIframe" };
this.inlineMenuButtonPort?.postMessage(message);
this.inlineMenuListPort?.postMessage(message);
}
/**
@ -757,7 +773,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
{ isInlineMenuHidden, setTransparentInlineMenu }: ToggleInlineMenuHiddenMessage,
sender: chrome.runtime.MessageSender,
) {
this.clearInlineMenuFadeInTimeout();
this.cancelInlineMenuFadeIn();
const display = isInlineMenuHidden ? "none" : "block";
let styles: { display: string; opacity?: string } = { display };
@ -778,7 +794,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
this.inlineMenuListPort?.postMessage(portMessage);
if (setTransparentInlineMenu) {
this.setInlineMenuFadeInTimeout();
this.startInlineMenuFadeIn();
}
}