/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; const BACKUP_STATE_PREF = "sidebar.backupState"; const VISIBILITY_SETTING_PREF = "sidebar.visibility"; const SIDEBAR_TOOLS = "sidebar.main.tools"; const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { ExperimentAPI: "resource://nimbus/ExperimentAPI.sys.mjs", NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs", PrefUtils: "resource://normandy/lib/PrefUtils.sys.mjs", }); XPCOMUtils.defineLazyPreferenceGetter(lazy, "sidebarNimbus", "sidebar.nimbus"); XPCOMUtils.defineLazyPreferenceGetter( lazy, "sidebarBackupState", BACKUP_STATE_PREF ); XPCOMUtils.defineLazyPreferenceGetter( lazy, "verticalTabsEnabled", "sidebar.verticalTabs", false, (pref, oldVal, newVal) => { SidebarManager.handleVerticalTabsPrefChange(newVal, true); } ); XPCOMUtils.defineLazyPreferenceGetter( lazy, "sidebarRevampEnabled", "sidebar.revamp", false, () => SidebarManager.updateDefaultTools() ); XPCOMUtils.defineLazyPreferenceGetter(lazy, "sidebarTools", SIDEBAR_TOOLS); export const SidebarManager = { /** * Handle startup tasks like telemetry, adding listeners. */ init() { // Handle nimbus feature pref setting updates on init and enrollment const featureId = "sidebar"; lazy.NimbusFeatures[featureId].onUpdate(() => { // Set prefs only if we have an enrollment that's new const feature = { featureId }; const enrollment = lazy.ExperimentAPI.getExperimentMetaData(feature) ?? lazy.ExperimentAPI.getRolloutMetaData(feature); if (!enrollment) { return; } const slug = enrollment.slug + ":" + enrollment.branch.slug; if (slug == lazy.sidebarNimbus) { return; } // Enforce minimum version by skipping pref changes until Firefox restarts // with the appropriate version if ( Services.vc.compare( // Support betas, e.g., 132.0b1, instead of MOZ_APP_VERSION AppConstants.MOZ_APP_VERSION_DISPLAY, // Check configured version or compare with unset handled as 0 lazy.NimbusFeatures[featureId].getVariable("minVersion") ) < 0 ) { return; } // Set/override user prefs to persist after experiment end const setPref = (pref, value) => { // Only set prefs with a value (so no clearing) if (value != null) { lazy.PrefUtils.setPref("sidebar." + pref, value); } }; setPref("nimbus", slug); ["main.tools", "revamp", "verticalTabs", "visibility"].forEach(pref => setPref(pref, lazy.NimbusFeatures[featureId].getVariable(pref)) ); }); Services.prefs.addObserver( "sidebar.newTool.migration.", this.updateDefaultTools.bind(this) ); this.updateDefaultTools(); // if there's no user visibility pref, we may need to update it to the default value for the tab orientation const shouldResetVisibility = !Services.prefs.prefHasUserValue( VISIBILITY_SETTING_PREF ); this.handleVerticalTabsPrefChange( lazy.verticalTabsEnabled, shouldResetVisibility ); }, /** * Adjust for a change to the verticalTabs pref. */ handleVerticalTabsPrefChange(isEnabled, resetVisibility = true) { if (!isEnabled) { // horizontal tabs can only have visibility of "hide-sidebar" Services.prefs.setStringPref(VISIBILITY_SETTING_PREF, "hide-sidebar"); } else if (resetVisibility) { // only reset visibility pref when switching to vertical tabs and explictly indicated Services.prefs.setStringPref(VISIBILITY_SETTING_PREF, "always-show"); } }, /** * Appends any new tools defined on the sidebar.newTool.migration pref branch * to the sidebar.main.tools pref one time as a way of introducing a new tool * to the launcher without overwriting what a user had previously customized. */ updateDefaultTools() { if (!lazy.sidebarRevampEnabled) { return; } let tools = lazy.sidebarTools; for (const pref of Services.prefs.getChildList( "sidebar.newTool.migration." )) { try { let options = JSON.parse(Services.prefs.getStringPref(pref)); let newTool = pref.split(".")[3]; // ensure we only add this tool once if (options?.alreadyShown || lazy.sidebarTools.includes(newTool)) { continue; } if (options?.visibilityPref) { // Will only add the tool to the launcher if the panel governing a panels sidebar visibility // is first enabled let visibilityPrefValue = Services.prefs.getBoolPref( options.visibilityPref ); if (!visibilityPrefValue) { Services.prefs.addObserver( options.visibilityPref, this.updateDefaultTools.bind(this) ); continue; } } tools = tools + "," + newTool; options.alreadyShown = true; Services.prefs.setStringPref(pref, JSON.stringify(options)); } catch (ex) { console.error("Failed to handle pref " + pref, ex); } } if (tools.length > lazy.sidebarTools.length) { Services.prefs.setStringPref(SIDEBAR_TOOLS, tools); } }, /** * Provide a system-level "backup" state to be stored for those using "Never * remember history" or "Clear history when browser closes". * * If it doesn't exist or isn't parsable, return `null`. * * @returns {object} */ getBackupState() { try { return JSON.parse(lazy.sidebarBackupState); } catch (e) { Services.prefs.clearUserPref(BACKUP_STATE_PREF); return null; } }, /** * Set the backup state. * * @param {object} state */ setBackupState(state) { if (!state) { return; } Services.prefs.setStringPref(BACKUP_STATE_PREF, JSON.stringify(state)); }, }; // Initialize on first import SidebarManager.init();