sidebar-customize.mjs (12017B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { 6 html, 7 when, 8 ifDefined, 9 } from "chrome://global/content/vendor/lit.all.mjs"; 10 11 import { SidebarPage } from "./sidebar-page.mjs"; 12 13 const { XPCOMUtils } = ChromeUtils.importESModule( 14 "resource://gre/modules/XPCOMUtils.sys.mjs" 15 ); 16 17 const l10nMap = new Map([ 18 ["viewGenaiChatSidebar", "sidebar-menu-genai-chat-label"], 19 ["viewGenaiPageAssistSidebar", "sidebar-menu-genai-page-assist-label"], 20 ["viewGenaiSmartAssistSidebar", "sidebar-menu-genai-smart-assist-label"], 21 ["viewHistorySidebar", "sidebar-menu-history-label"], 22 ["viewTabsSidebar", "sidebar-menu-synced-tabs-label"], 23 ["viewBookmarksSidebar", "sidebar-menu-bookmarks-label"], 24 ["viewCPMSidebar", "sidebar-menu-contextual-password-manager-label"], 25 ]); 26 const VISIBILITY_SETTING_PREF = "sidebar.visibility"; 27 const EXPAND_ON_HOVER_PREF = "sidebar.expandOnHover"; 28 const POSITION_SETTING_PREF = "sidebar.position_start"; 29 const TAB_DIRECTION_SETTING_PREF = "sidebar.verticalTabs"; 30 31 export class SidebarCustomize extends SidebarPage { 32 constructor() { 33 super(); 34 XPCOMUtils.defineLazyPreferenceGetter( 35 this.#prefValues, 36 "visibility", 37 VISIBILITY_SETTING_PREF, 38 "always-show", 39 (_aPreference, _previousValue, newValue) => { 40 this.visibility = newValue; 41 } 42 ); 43 XPCOMUtils.defineLazyPreferenceGetter( 44 this.#prefValues, 45 "isPositionStart", 46 POSITION_SETTING_PREF, 47 true, 48 (_aPreference, _previousValue, newValue) => { 49 this.isPositionStart = newValue; 50 } 51 ); 52 XPCOMUtils.defineLazyPreferenceGetter( 53 this.#prefValues, 54 "verticalTabsEnabled", 55 TAB_DIRECTION_SETTING_PREF, 56 false, 57 (_aPreference, _previousValue, newValue) => { 58 this.verticalTabsEnabled = newValue; 59 } 60 ); 61 XPCOMUtils.defineLazyPreferenceGetter( 62 this.#prefValues, 63 "expandOnHoverEnabled", 64 EXPAND_ON_HOVER_PREF, 65 false, 66 (_aPreference, _previousValue, newValue) => { 67 this.expandOnHoverEnabled = newValue; 68 } 69 ); 70 this.visibility = this.#prefValues.visibility; 71 this.isPositionStart = this.#prefValues.isPositionStart; 72 this.verticalTabsEnabled = this.#prefValues.verticalTabsEnabled; 73 this.expandOnHoverEnabled = this.#prefValues.expandOnHoverEnabled; 74 this.boundObserve = (...args) => this.observe(...args); 75 } 76 77 #prefValues = {}; 78 79 static properties = { 80 visibility: { type: String }, 81 isPositionStart: { type: Boolean }, 82 verticalTabsEnabled: { type: Boolean }, 83 expandOnHoverEnabled: { type: Boolean }, 84 }; 85 86 static queries = { 87 toolInputs: { all: ".tools > .tool" }, 88 extensionInputs: { all: ".extensions > .tool" }, 89 extensionLink: ".extension-item a", 90 positionInput: "#position", 91 visibilityInput: "#hide-sidebar", 92 verticalTabsInput: "#vertical-tabs", 93 expandOnHoverInput: "#expand-on-hover", 94 }; 95 96 connectedCallback() { 97 super.connectedCallback(); 98 this.getWindow().addEventListener("SidebarItemAdded", this); 99 this.getWindow().addEventListener("SidebarItemChanged", this); 100 this.getWindow().addEventListener("SidebarItemRemoved", this); 101 } 102 103 disconnectedCallback() { 104 super.disconnectedCallback(); 105 this.getWindow().removeEventListener("SidebarItemAdded", this); 106 this.getWindow().removeEventListener("SidebarItemChanged", this); 107 this.getWindow().removeEventListener("SidebarItemRemoved", this); 108 } 109 110 get fluentStrings() { 111 if (!this._fluentStrings) { 112 this._fluentStrings = new Localization(["browser/sidebar.ftl"], true); 113 } 114 return this._fluentStrings; 115 } 116 117 getWindow() { 118 return window.browsingContext.embedderWindowGlobal.browsingContext.window; 119 } 120 121 handleEvent(e) { 122 switch (e.type) { 123 case "SidebarItemAdded": 124 case "SidebarItemChanged": 125 case "SidebarItemRemoved": 126 this.requestUpdate(); 127 break; 128 } 129 } 130 131 async onToggleToolInput(e, commandID) { 132 e.preventDefault(); 133 this.getWindow().SidebarController.toggleTool(commandID); 134 switch (commandID) { 135 case "viewGenaiChatSidebar": 136 Glean.sidebarCustomize.chatbotEnabled.record({ 137 checked: e.target.checked, 138 }); 139 break; 140 case "viewTabsSidebar": 141 Glean.sidebarCustomize.syncedTabsEnabled.record({ 142 checked: e.target.checked, 143 }); 144 break; 145 case "viewHistorySidebar": 146 Glean.sidebarCustomize.historyEnabled.record({ 147 checked: e.target.checked, 148 }); 149 break; 150 case "viewBookmarksSidebar": 151 Glean.sidebarCustomize.bookmarksEnabled.record({ 152 checked: e.target.checked, 153 }); 154 break; 155 case "viewCPMSidebar": 156 Glean.contextualManager.passwordsEnabled.record({ 157 checked: e.target.checked, 158 }); 159 break; 160 } 161 } 162 163 getInputL10nId(view) { 164 return l10nMap.get(view); 165 } 166 167 openFirefoxSettings(e) { 168 if (e.type == "click" || (e.type == "keydown" && e.code == "Enter")) { 169 e.preventDefault(); 170 this.getWindow().openPreferences(); 171 Glean.sidebarCustomize.firefoxSettingsClicked.record(); 172 } 173 } 174 175 toolInputTemplate(tool) { 176 if (tool.hidden) { 177 return null; 178 } 179 180 return html` 181 <moz-checkbox 182 class="tool" 183 type="checkbox" 184 id=${tool.view} 185 name=${tool.name} 186 iconsrc=${tool.iconUrl} 187 data-l10n-id=${ifDefined(this.getInputL10nId(tool.view))} 188 label=${ifDefined(tool.tooltiptext)} 189 @change=${e => this.onToggleToolInput(e, tool.commandID)} 190 ?checked=${!tool.disabled} 191 ></moz-checkbox> 192 `; 193 } 194 195 manageAddons(e) { 196 if (e.type == "click" || (e.type == "keydown" && e.code == "Enter")) { 197 e.preventDefault(); 198 this.getWindow().BrowserAddonUI.openAddonsMgr("addons://list/extension"); 199 Glean.sidebarCustomize.extensionsClicked.record(); 200 } 201 } 202 203 reversePosition() { 204 const { SidebarController } = this.getWindow(); 205 SidebarController.reversePosition(); 206 Glean.sidebarCustomize.sidebarPosition.record({ 207 position: 208 this.isPositionStart !== this.getWindow().RTL_UI ? "left" : "right", 209 }); 210 } 211 212 render() { 213 let extensions = this.getWindow().SidebarController.getExtensions(); 214 return html` 215 ${this.stylesheet()} 216 <link rel="stylesheet" href="chrome://browser/content/sidebar/sidebar-customize.css"></link> 217 <div class="sidebar-panel"> 218 <sidebar-panel-header data-l10n-id="sidebar-menu-customize-header" data-l10n-attrs="heading" view="viewCustomizeSidebar"> 219 </sidebar-panel-header> 220 <div class="sidebar-panel-scrollable-content"> 221 <moz-fieldset class="customize-group no-end-margin" data-l10n-id="sidebar-settings"> 222 <moz-checkbox 223 type="checkbox" 224 id="vertical-tabs" 225 name="verticalTabs" 226 iconsrc="chrome://browser/skin/sidebar-collapsed.svg" 227 data-l10n-id="sidebar-vertical-tabs" 228 @change=${this.#handleTabDirectionChange} 229 ?checked=${this.verticalTabsEnabled} 230 > 231 ${when( 232 this.verticalTabsEnabled, 233 () => html` 234 ${when( 235 this.expandOnHoverEnabled, 236 () => html` 237 <moz-checkbox 238 slot="nested" 239 type="checkbox" 240 id="expand-on-hover" 241 name="expand-on-hover" 242 data-l10n-id="expand-sidebar-on-hover" 243 @change=${this.#toggleExpandOnHover} 244 ?checked=${this.getWindow().SidebarController._state 245 .revampVisibility === "expand-on-hover"} 246 ?disabled=${this.visibility == "hide-sidebar"} 247 ></moz-checkbox> 248 ` 249 )} 250 <moz-checkbox 251 slot="nested" 252 type="checkbox" 253 id="hide-sidebar" 254 name="hideSidebar" 255 data-l10n-id="sidebar-hide-tabs-and-sidebar" 256 @change=${this.#handleVisibilityChange} 257 ?checked=${this.visibility == "hide-sidebar"} 258 ?disabled=${this.getWindow().SidebarController._state 259 .revampVisibility === "expand-on-hover"} 260 ></moz-checkbox> 261 ` 262 )} 263 </moz-checkbox> 264 </moz-fieldset> 265 <moz-fieldset class="customize-group medium-top-margin no-label"> 266 <moz-checkbox 267 type="checkbox" 268 id="position" 269 name="position" 270 data-l10n-id=${document.dir == "rtl" ? "sidebar-show-on-the-left" : "sidebar-show-on-the-right"} 271 @change=${this.reversePosition} 272 ?checked=${!this.isPositionStart} 273 ></moz-checkbox> 274 </moz-fieldset> 275 <moz-fieldset class="customize-group tools" data-l10n-id="sidebar-customize-firefox-tools-header"> 276 ${this.getWindow() 277 .SidebarController.getTools() 278 .map(tool => this.toolInputTemplate(tool))} 279 </moz-fieldset> 280 ${when( 281 extensions.length, 282 () => 283 html`<div class="customize-group"> 284 <h4 285 class="customize-extensions-heading" 286 data-l10n-id="sidebar-customize-extensions-header" 287 ></h4> 288 <div role="list" class="extensions"> 289 ${extensions.map(extension => 290 this.toolInputTemplate(extension) 291 )} 292 <div class="extension-item"> 293 <img 294 src="chrome://mozapps/skin/extensions/category-extensions.svg" 295 class="icon" 296 role="presentation" 297 /> 298 <a 299 href="about:addons" 300 @click=${this.manageAddons} 301 @keydown=${this.manageAddons} 302 data-l10n-id="sidebar-manage-extensions" 303 > 304 </a> 305 </div> 306 </div> 307 </div>` 308 )} 309 <div id="manage-settings"> 310 <img src="chrome://browser/skin/preferences/category-general.svg" class="icon" role="presentation" /> 311 <a 312 href="about:preferences" 313 @click=${this.openFirefoxSettings} 314 @keydown=${this.openFirefoxSettings} 315 data-l10n-id="sidebar-customize-firefox-settings" 316 > 317 </a> 318 </div> 319 </div> 320 </div> 321 `; 322 } 323 324 #handleVisibilityChange(e) { 325 e.stopPropagation(); 326 this.visibility = e.target.checked ? "hide-sidebar" : "always-show"; 327 Services.prefs.setStringPref( 328 VISIBILITY_SETTING_PREF, 329 e.target.checked ? "hide-sidebar" : "always-show" 330 ); 331 Glean.sidebarCustomize.sidebarDisplay.record({ 332 preference: e.target.checked ? "hide" : "always", 333 }); 334 } 335 336 #toggleExpandOnHover(e) { 337 e.stopPropagation(); 338 if (e.target.checked) { 339 Services.prefs.setStringPref("sidebar.visibility", "expand-on-hover"); 340 Glean.sidebarCustomize.expandOnHoverEnabled.record({ 341 checked: true, 342 }); 343 } else { 344 Services.prefs.setStringPref("sidebar.visibility", "always-show"); 345 } 346 } 347 348 #handleTabDirectionChange({ target: { checked } }) { 349 const verticalTabsEnabled = checked; 350 Services.prefs.setBoolPref(TAB_DIRECTION_SETTING_PREF, verticalTabsEnabled); 351 Glean.sidebarCustomize.tabsLayout.record({ 352 orientation: verticalTabsEnabled ? "vertical" : "horizontal", 353 }); 354 } 355 } 356 357 customElements.define("sidebar-customize", SidebarCustomize);