1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-05 18:47:52 +01:00

[CL-509][PM-16190] Avoid double scrollbar appearing when default zoom is >100% (#12427)

This commit is contained in:
Victoria League 2024-12-27 15:42:35 -05:00 committed by GitHub
parent 6d65ce9abd
commit 4f060d88fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 84 additions and 37 deletions

View File

@ -165,6 +165,21 @@ export class BrowserApi {
});
}
/**
* Fetch the currently open browser tab
*/
static async getCurrentTab(): Promise<chrome.tabs.Tab> | null {
if (BrowserApi.isManifestVersion(3)) {
return await chrome.tabs.getCurrent();
}
return new Promise((resolve) =>
chrome.tabs.getCurrent((tab) => {
resolve(tab);
}),
);
}
static async tabsQuery(options: chrome.tabs.QueryInfo): Promise<chrome.tabs.Tab[]> {
return new Promise((resolve) => {
chrome.tabs.query(options, (tabs) => {

View File

@ -3,7 +3,7 @@
import { BrowserApi } from "../browser/browser-api";
import { ScrollOptions } from "./abstractions/browser-popup-utils.abstractions";
import { PopupWidthOptions } from "./layout/popup-width.service";
import { PopupWidthOptions } from "./layout/popup-size.service";
class BrowserPopupUtils {
/**
@ -24,6 +24,22 @@ class BrowserPopupUtils {
return BrowserPopupUtils.urlContainsSearchParams(win, "uilocation", "popout");
}
/**
* Check if the current popup view is open inside of the current browser tab
* (it is possible in Chrome to open the extension in a tab)
*/
static async isInTab() {
const tabId = (await BrowserApi.getCurrentTab())?.id;
if (tabId === undefined || tabId === null) {
return false;
}
const result = BrowserApi.getExtensionViews({ tabId, type: "tab" });
return result.length > 0;
}
/**
* Identifies if the popup is within the single action popout.
*

View File

@ -8,7 +8,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
templateUrl: "popup-page.component.html",
standalone: true,
host: {
class: "tw-h-full tw-flex tw-flex-col tw-flex-1 tw-overflow-y-hidden",
class: "tw-h-full tw-flex tw-flex-col tw-overflow-y-hidden",
},
imports: [CommonModule],
})

View File

@ -7,6 +7,8 @@ import {
POPUP_STYLE_DISK,
} from "@bitwarden/common/platform/state";
import BrowserPopupUtils from "../browser-popup-utils";
/**
*
* Value represents width in pixels
@ -25,10 +27,12 @@ const POPUP_WIDTH_KEY_DEF = new KeyDefinition<PopupWidthOption>(POPUP_STYLE_DISK
});
/**
* Updates the extension popup width based on a user setting
* Handles sizing the popup based on available width/height, which can be affected by
* user default zoom level.
* Updates the extension popup width based on a user setting.
**/
@Injectable({ providedIn: "root" })
export class PopupWidthService {
export class PopupSizeService {
private static readonly LocalStorageKey = "bw-popup-width";
private readonly state = inject(GlobalStateProvider).get(POPUP_WIDTH_KEY_DEF);
@ -41,15 +45,31 @@ export class PopupWidthService {
}
/** Begin listening for state changes */
init() {
async init() {
this.width$.subscribe((width: PopupWidthOption) => {
PopupWidthService.setStyle(width);
localStorage.setItem(PopupWidthService.LocalStorageKey, width);
PopupSizeService.setStyle(width);
localStorage.setItem(PopupSizeService.LocalStorageKey, width);
});
const isInChromeTab = await BrowserPopupUtils.isInTab();
if (!BrowserPopupUtils.inPopup(window) || isInChromeTab) {
window.document.body.classList.add("body-full");
} else if (window.innerHeight < 400) {
window.document.body.classList.add("body-xxs");
} else if (window.innerHeight < 500) {
window.document.body.classList.add("body-xs");
} else if (window.innerHeight < 600) {
window.document.body.classList.add("body-sm");
}
}
private static setStyle(width: PopupWidthOption) {
if (!BrowserPopupUtils.inPopup(window)) {
return;
}
const pxWidth = PopupWidthOptions[width] ?? PopupWidthOptions.default;
document.body.style.minWidth = `${pxWidth}px`;
}
@ -57,7 +77,7 @@ export class PopupWidthService {
* To keep the popup size from flickering on bootstrap, we store the width in `localStorage` so we can quickly & synchronously reference it.
**/
static initBodyWidthFromLocalStorage() {
const storedValue = localStorage.getItem(PopupWidthService.LocalStorageKey);
const storedValue = localStorage.getItem(PopupSizeService.LocalStorageKey);
this.setStyle(storedValue as any);
}
}

View File

@ -23,7 +23,6 @@ import {
} from "@bitwarden/components";
import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-mode.service";
import { PopupWidthService } from "../platform/popup/layout/popup-width.service";
import { PopupViewCacheService } from "../platform/popup/view-cache/popup-view-cache.service";
import { initPopupClosedListener } from "../platform/services/popup-view-cache-background.service";
import { VaultBrowserStateService } from "../vault/services/vault-browser-state.service";
@ -42,7 +41,6 @@ import { DesktopSyncVerificationDialogComponent } from "./components/desktop-syn
export class AppComponent implements OnInit, OnDestroy {
private viewCacheService = inject(PopupViewCacheService);
private compactModeService = inject(PopupCompactModeService);
private widthService = inject(PopupWidthService);
private lastActivity: Date;
private activeUserId: UserId;
@ -73,7 +71,6 @@ export class AppComponent implements OnInit, OnDestroy {
await this.viewCacheService.init();
this.compactModeService.init();
this.widthService.init();
// Component states must not persist between closing and reopening the popup, otherwise they become dead objects
// Clear them aggressively to make sure this doesn't occur

View File

@ -1,7 +1,7 @@
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { PopupWidthService } from "../platform/popup/layout/popup-width.service";
import { PopupSizeService } from "../platform/popup/layout/popup-size.service";
import { BrowserPlatformUtilsService } from "../platform/services/platform-utils/browser-platform-utils.service";
require("./scss/popup.scss");
@ -10,7 +10,7 @@ require("./scss/tailwind.css");
import { AppModule } from "./app.module";
// We put these first to minimize the delay in window changing.
PopupWidthService.initBodyWidthFromLocalStorage();
PopupSizeService.initBodyWidthFromLocalStorage();
// Should be removed once we deprecate support for Safari 16.0 and older. See Jira ticket [PM-1861]
if (BrowserPlatformUtilsService.shouldApplySafariHeightFix(window)) {
document.documentElement.classList.add("safari_height_fix");

View File

@ -19,8 +19,8 @@ body {
}
body {
min-width: 380px;
height: 600px !important;
width: 380px;
height: 600px;
position: relative;
min-height: 100vh;
overflow: hidden;
@ -33,18 +33,20 @@ body {
}
&.body-sm {
width: 375px !important;
height: 500px !important;
height: 500px;
}
&.body-xs {
width: 375px !important;
height: 300px !important;
height: 400px;
}
&.body-xxs {
height: 300px;
}
&.body-full {
width: 100% !important;
height: 100% !important;
width: 100%;
height: 100%;
}
}

View File

@ -1,5 +1,5 @@
import { DOCUMENT } from "@angular/common";
import { Inject, Injectable } from "@angular/core";
import { inject, Inject, Injectable } from "@angular/core";
import { AbstractThemingService } from "@bitwarden/angular/platform/services/theming/theming.service.abstraction";
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
@ -10,8 +10,11 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
import { BrowserApi } from "../../platform/browser/browser-api";
import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
import { PopupSizeService } from "../../platform/popup/layout/popup-size.service";
@Injectable()
export class InitService {
private sizeService = inject(PopupSizeService);
constructor(
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
@ -28,13 +31,7 @@ export class InitService {
await this.i18nService.init();
this.twoFactorService.init();
if (!BrowserPopupUtils.inPopup(window)) {
window.document.body.classList.add("body-full");
} else if (window.screen.availHeight < 600) {
window.document.body.classList.add("body-xs");
} else if (window.screen.availHeight <= 800) {
window.document.body.classList.add("body-sm");
}
await this.sizeService.init();
const htmlEl = window.document.documentElement;
this.themingService.applyThemeChangesTo(this.document);

View File

@ -16,7 +16,7 @@ import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-stat
import { PopupCompactModeService } from "../../../platform/popup/layout/popup-compact-mode.service";
import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component";
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
import { PopupWidthService } from "../../../platform/popup/layout/popup-width.service";
import { PopupSizeService } from "../../../platform/popup/layout/popup-size.service";
import { VaultPopupCopyButtonsService } from "../services/vault-popup-copy-buttons.service";
import { AppearanceV2Component } from "./appearance-v2.component";
@ -55,7 +55,7 @@ describe("AppearanceV2Component", () => {
const setEnableCompactMode = jest.fn().mockResolvedValue(undefined);
const setShowQuickCopyActions = jest.fn().mockResolvedValue(undefined);
const mockWidthService: Partial<PopupWidthService> = {
const mockWidthService: Partial<PopupSizeService> = {
width$: new BehaviorSubject("default"),
setWidth: jest.fn().mockResolvedValue(undefined),
};
@ -95,7 +95,7 @@ describe("AppearanceV2Component", () => {
} as Partial<VaultPopupCopyButtonsService>,
},
{
provide: PopupWidthService,
provide: PopupSizeService,
useValue: mockWidthService,
},
],

View File

@ -25,8 +25,8 @@ import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-heade
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
import {
PopupWidthOption,
PopupWidthService,
} from "../../../platform/popup/layout/popup-width.service";
PopupSizeService,
} from "../../../platform/popup/layout/popup-size.service";
import { VaultPopupCopyButtonsService } from "../services/vault-popup-copy-buttons.service";
@Component({
@ -49,7 +49,7 @@ import { VaultPopupCopyButtonsService } from "../services/vault-popup-copy-butto
export class AppearanceV2Component implements OnInit {
private compactModeService = inject(PopupCompactModeService);
private copyButtonsService = inject(VaultPopupCopyButtonsService);
private popupWidthService = inject(PopupWidthService);
private popupSizeService = inject(PopupSizeService);
private i18nService = inject(I18nService);
appearanceForm = this.formBuilder.group({
@ -103,7 +103,7 @@ export class AppearanceV2Component implements OnInit {
const showQuickCopyActions = await firstValueFrom(
this.copyButtonsService.showQuickCopyActions$,
);
const width = await firstValueFrom(this.popupWidthService.width$);
const width = await firstValueFrom(this.popupSizeService.width$);
// Set initial values for the form
this.appearanceForm.setValue({
@ -187,6 +187,6 @@ export class AppearanceV2Component implements OnInit {
}
async updateWidth(width: PopupWidthOption) {
await this.popupWidthService.setWidth(width);
await this.popupSizeService.setWidth(width);
}
}