diff --git a/browser/components/sidebar/sidebar-customize.mjs b/browser/components/sidebar/sidebar-customize.mjs
index e9315a4e2729..3808c41e9239 100644
--- a/browser/components/sidebar/sidebar-customize.mjs
+++ b/browser/components/sidebar/sidebar-customize.mjs
@@ -9,6 +9,10 @@ import { SidebarPage } from "./sidebar-page.mjs";
// eslint-disable-next-line import/no-unassigned-import
import "chrome://global/content/elements/moz-radio-group.mjs";
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
const l10nMap = new Map([
["viewGenaiChatSidebar", "sidebar-menu-genai-chat-label"],
["viewReviewCheckerSidebar", "sidebar-menu-review-checker-label"],
@@ -17,22 +21,53 @@ const l10nMap = new Map([
["viewBookmarksSidebar", "sidebar-menu-bookmarks-label"],
]);
const VISIBILITY_SETTING_PREF = "sidebar.visibility";
+const POSITION_SETTING_PREF = "sidebar.position_start";
const TAB_DIRECTION_SETTING_PREF = "sidebar.verticalTabs";
export class SidebarCustomize extends SidebarPage {
constructor() {
super();
this.activeExtIndex = 0;
- this.visibility = Services.prefs.getStringPref(
+ XPCOMUtils.defineLazyPreferenceGetter(
+ this.#prefValues,
+ "visibility",
VISIBILITY_SETTING_PREF,
- "always-show"
+ "always-show",
+ (_aPreference, _previousValue, newValue) => {
+ this.visibility = newValue;
+ }
);
+ XPCOMUtils.defineLazyPreferenceGetter(
+ this.#prefValues,
+ "isPositionStart",
+ POSITION_SETTING_PREF,
+ true,
+ (_aPreference, _previousValue, newValue) => {
+ this.isPositionStart = newValue;
+ }
+ );
+ XPCOMUtils.defineLazyPreferenceGetter(
+ this.#prefValues,
+ "isVerticalTabs",
+ TAB_DIRECTION_SETTING_PREF,
+ false,
+ (_aPreference, _previousValue, newValue) => {
+ this.isVerticalTabs = newValue;
+ }
+ );
+ this.visibility = this.#prefValues.visibility;
+ this.isPositionStart = this.#prefValues.isPositionStart;
+ this.isVerticalTabs = this.#prefValues.isVerticalTabs;
this.boundObserve = (...args) => this.observe(...args);
}
+ #prefValues = {};
+
static properties = {
activeExtIndex: { type: Number },
visibility: { type: String },
+ isPositionStart: { type: Boolean },
+ isVerticalTabs: { type: Boolean },
};
static queries = {
@@ -48,7 +83,6 @@ export class SidebarCustomize extends SidebarPage {
this.getWindow().addEventListener("SidebarItemAdded", this);
this.getWindow().addEventListener("SidebarItemChanged", this);
this.getWindow().addEventListener("SidebarItemRemoved", this);
- Services.prefs.addObserver(VISIBILITY_SETTING_PREF, this.boundObserve);
}
disconnectedCallback() {
@@ -56,26 +90,6 @@ export class SidebarCustomize extends SidebarPage {
this.getWindow().removeEventListener("SidebarItemAdded", this);
this.getWindow().removeEventListener("SidebarItemChanged", this);
this.getWindow().removeEventListener("SidebarItemRemoved", this);
- Services.prefs.removeObserver(VISIBILITY_SETTING_PREF, this.boundObserve);
- }
-
- observe(subject, topic, prefName) {
- switch (topic) {
- case "nsPref:changed":
- switch (prefName) {
- case VISIBILITY_SETTING_PREF:
- this.visibility = Services.prefs.getStringPref(
- VISIBILITY_SETTING_PREF,
- "always-show"
- );
- break;
- }
- break;
- }
- }
-
- get sidebarLauncher() {
- return this.getWindow().document.querySelector("sidebar-launcher");
}
getWindow() {
@@ -186,9 +200,7 @@ export class SidebarCustomize extends SidebarPage {
SidebarController.reversePosition();
Glean.sidebarCustomize.sidebarPosition.record({
position:
- SidebarController._positionStart !== this.getWindow().RTL_UI
- ? "left"
- : "right",
+ this.isPositionStart !== this.getWindow().RTL_UI ? "left" : "right",
});
}
@@ -245,6 +257,7 @@ export class SidebarCustomize extends SidebarPage {
@@ -267,16 +280,13 @@ export class SidebarCustomize extends SidebarPage {
@@ -284,11 +294,7 @@ export class SidebarCustomize extends SidebarPage {
class="position-setting"
id="position-right"
value=${this.getWindow().RTL_UI}
- ?checked=${
- this.getWindow().RTL_UI
- ? this.getWindow().SidebarController._positionStart
- : !this.getWindow().SidebarController._positionStart
- }
+ ?checked=${this.isPositionStart == this.getWindow().RTL_UI}
iconsrc="chrome://browser/skin/sidebar-expanded-right.svg"
data-l10n-id="sidebar-position-right"
>
@@ -298,14 +304,13 @@ export class SidebarCustomize extends SidebarPage {
@@ -313,10 +318,7 @@ export class SidebarCustomize extends SidebarPage {
class="vertical-tabs-setting"
id="horizontal-tabs"
value=${false}
- ?checked=${
- this.getWindow().SidebarController
- .sidebarVerticalTabsEnabled === false
- }
+ ?checked=${!this.isVerticalTabs}
iconsrc="chrome://browser/skin/sidebar-horizontal-tabs.svg"
data-l10n-id="sidebar-horizontal-tabs"
>
diff --git a/browser/components/sidebar/tests/browser/browser_customize_sidebar.js b/browser/components/sidebar/tests/browser/browser_customize_sidebar.js
index 5d7fc8f02ee3..c4d0c9527a51 100644
--- a/browser/components/sidebar/tests/browser/browser_customize_sidebar.js
+++ b/browser/components/sidebar/tests/browser/browser_customize_sidebar.js
@@ -6,8 +6,15 @@
requestLongerTimeout(2);
const SIDEBAR_VISIBILITY_PREF = "sidebar.visibility";
+const POSITION_SETTING_PREF = "sidebar.position_start";
const TAB_DIRECTION_PREF = "sidebar.verticalTabs";
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(SIDEBAR_VISIBILITY_PREF);
+ Services.prefs.clearUserPref(POSITION_SETTING_PREF);
+ Services.prefs.clearUserPref(TAB_DIRECTION_PREF);
+});
+
async function showCustomizePanel(win) {
await win.SidebarController.show("viewCustomizeSidebar");
const document = win.SidebarController.browser.contentDocument;
@@ -292,3 +299,49 @@ add_task(async function test_keyboard_navigation_away_from_settings_link() {
await BrowserTestUtils.closeWindow(win);
});
+
+add_task(async function test_settings_synchronized_across_windows() {
+ const panel = await showCustomizePanel(window);
+ const { contentWindow } = SidebarController.browser;
+ const newWindow = await BrowserTestUtils.openNewBrowserWindow();
+ const newPanel = await showCustomizePanel(newWindow);
+
+ info("Update visibility settings.");
+ EventUtils.synthesizeMouseAtCenter(
+ panel.visibilityInputs[1],
+ {},
+ contentWindow
+ );
+ await newPanel.updateComplete;
+ ok(
+ newPanel.visibilityInputs[1].checked,
+ "New window shows the updated visibility setting."
+ );
+
+ info("Update position settings.");
+ EventUtils.synthesizeMouseAtCenter(
+ panel.positionInputs[1],
+ {},
+ contentWindow
+ );
+ await newPanel.updateComplete;
+ ok(
+ newPanel.positionInputs[1].checked,
+ "New window shows the updated position setting."
+ );
+
+ info("Update vertical tabs settings.");
+ EventUtils.synthesizeMouseAtCenter(
+ panel.verticalTabsInputs[0],
+ {},
+ contentWindow
+ );
+ await newPanel.updateComplete;
+ ok(
+ newPanel.verticalTabsInputs[0].checked,
+ "New window shows the vertical tabs setting."
+ );
+
+ SidebarController.hide();
+ await BrowserTestUtils.closeWindow(newWindow);
+});
diff --git a/browser/components/sidebar/tests/unit/test_sidebar_state.js b/browser/components/sidebar/tests/unit/test_sidebar_state.js
index 568c539d4bc2..8f7317b77c02 100644
--- a/browser/components/sidebar/tests/unit/test_sidebar_state.js
+++ b/browser/components/sidebar/tests/unit/test_sidebar_state.js
@@ -11,17 +11,19 @@ const { SidebarState } = ChromeUtils.importESModule(
"resource:///modules/SidebarState.sys.mjs"
);
-const mockElement = { toggleAttribute: sinon.stub() };
+const mockElement = {
+ setAttribute(name, value) {
+ this[name] = value;
+ },
+ style: { width: "200px" },
+ toggleAttribute: sinon.stub(),
+};
const mockGlobal = {
document: { getElementById: () => mockElement },
gBrowser: { tabContainer: mockElement },
};
-const mockPanel = {
- setAttribute: (name, value) => (mockPanel[name] = value),
- style: { width: "200px" },
-};
const mockController = {
- _box: mockPanel,
+ _box: mockElement,
showInitially: sinon.stub(),
sidebarContainer: { ownerGlobal: mockGlobal },
sidebarMain: mockElement,