devtools-experimental-prefs.js (6781B)
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 "use strict"; 6 7 loader.lazyRequireGetter( 8 this, 9 "HTMLTooltip", 10 "resource://devtools/client/shared/widgets/tooltip/HTMLTooltip.js", 11 true 12 ); 13 14 const PREFERENCES = [ 15 [ 16 "fission.autostart", 17 "Enable fission in Firefox. When navigating between two domains, you " + 18 "will switch between two distinct processes. And if an iframe is " + 19 "hosted from another domain, it will run in another process", 20 ], 21 [ 22 "fission.bfcacheInParent", 23 "Enable bfcache navigation in parent process (requires Fission and involve " + 24 "more top level target switching", 25 ], 26 [ 27 "devtools.debugger.features.javascript-tracing", 28 "Enable the JavaScript tracer. (You need to restart Firefox / the Browser Toolbox to apply this setting)", 29 ], 30 ]; 31 32 /** 33 * Show a Tooltip with the currently enabled preferences relevant for DevTools 34 * ongoing experiments (new features, refactors, migrations). 35 */ 36 function showTooltip(toolbox) { 37 if (!toolbox._experimentalPrefsTooltip) { 38 toolbox._experimentalPrefsTooltip = new HTMLTooltip(toolbox.doc, { 39 type: "doorhanger", 40 useXulWrapper: true, 41 }); 42 toolbox.once("destroy", () => toolbox._experimentalPrefsTooltip.destroy()); 43 } 44 45 // Terrible hack to allow to toggle using the command button. 46 if (toolbox._experimentalPrefsTooltip.preventShow) { 47 return; 48 } 49 50 updateTooltipContent(toolbox); 51 52 const commandId = "command-button-experimental-prefs"; 53 toolbox._experimentalPrefsTooltip.show(toolbox.doc.getElementById(commandId)); 54 55 // Follows a hack to be able to close the tooltip when clicking on the 56 // command button. Otherwise it will flicker and reopen. 57 toolbox._experimentalPrefsTooltip.preventShow = true; 58 toolbox._experimentalPrefsTooltip.once("hidden", () => { 59 toolbox.win.setTimeout( 60 () => (toolbox._experimentalPrefsTooltip.preventShow = false), 61 250 62 ); 63 }); 64 } 65 exports.showTooltip = showTooltip; 66 function updateTooltipContent(toolbox) { 67 const container = toolbox.doc.createElement("div"); 68 69 /* 70 * This is the grid we want to have: 71 * +--------------------------------------------+---------------+ 72 * | Header text | Reset button | 73 * +------+-----------------------------+-------+---------------+ 74 * | Icon | Preference name | Value | Toggle button | 75 * +------+-----------------------------+-------+---------------+ 76 * | Icon | Preference name | Value | Toggle button | 77 * +------+-----------------------------+-------+---------------+ 78 */ 79 80 Object.assign(container.style, { 81 display: "grid", 82 gridTemplateColumns: 83 "max-content minmax(300px, auto) max-content max-content", 84 gridColumnGap: "8px", 85 gridTemplateRows: `repeat(${PREFERENCES.length + 1}, auto)`, 86 gridRowGap: "8px", 87 padding: "12px", 88 fontSize: "11px", 89 }); 90 91 container.classList.add("theme-body"); 92 93 const headerContainer = toolbox.doc.createElement("header"); 94 /** 95 * The grid layout of the header container is as follows: 96 * 97 * +-------------------------+--------------+ 98 * | Header text | Reset button | 99 * +-------------------------+--------------+ 100 */ 101 102 Object.assign(headerContainer.style, { 103 display: "grid", 104 gridTemplateColumns: "subgrid", 105 gridColumn: "1 / -1", 106 }); 107 108 const header = toolbox.doc.createElement("h1"); 109 110 Object.assign(header.style, { 111 gridColumn: "1 / -2", 112 fontSize: "11px", 113 margin: "0", 114 padding: "0", 115 }); 116 117 header.textContent = "DevTools Experimental preferences"; 118 119 const resetButton = toolbox.doc.createElement("button"); 120 resetButton.addEventListener("click", () => { 121 for (const [name] of PREFERENCES) { 122 Services.prefs.clearUserPref(name); 123 } 124 updateTooltipContent(toolbox); 125 }); 126 resetButton.textContent = "reset all"; 127 128 headerContainer.append(header, resetButton); 129 130 const prefList = toolbox.doc.createElement("ul"); 131 Object.assign(prefList.style, { 132 display: "grid", 133 gridTemplateColumns: "subgrid", 134 gridTemplateRows: "subgrid", 135 // Subgrid should span all grid columns 136 gridColumn: "1 / -1", 137 gridRow: "2 / -1", 138 listStyle: "none", 139 margin: "0", 140 padding: "0", 141 }); 142 143 for (const [name, desc] of PREFERENCES) { 144 const prefEl = createPreferenceListItem(toolbox, name, desc); 145 prefList.appendChild(prefEl); 146 } 147 148 container.append(headerContainer, prefList); 149 150 toolbox._experimentalPrefsTooltip.panel.innerHTML = ""; 151 // There is a hardcoded 320px max width for doorhanger tooltips, 152 // see Bug 1654020. 153 toolbox._experimentalPrefsTooltip.panel.style.maxWidth = "unset"; 154 toolbox._experimentalPrefsTooltip.panel.appendChild(container); 155 } 156 157 function createPreferenceListItem(toolbox, name, desc) { 158 const isPrefEnabled = Services.prefs.getBoolPref(name, false); 159 160 const prefEl = toolbox.doc.createElement("li"); 161 162 /** 163 * The grid layout of a preference line is as follows: 164 * 165 * +------+-----------------------------+-------+---------------+ 166 * | Icon | Preference name | Value | Toggle button | 167 * +------+-----------------------------+-------+---------------+ 168 */ 169 170 Object.assign(prefEl.style, { 171 margin: "0", 172 lineHeight: "12px", 173 display: "grid", 174 alignItems: "center", 175 gridTemplateColumns: "subgrid", 176 gridColumn: "1 / -1", 177 }); 178 179 prefEl.classList.toggle("theme-comment", !isPrefEnabled); 180 181 // Icon 182 const prefInfo = toolbox.doc.createElement("div"); 183 prefInfo.title = desc; 184 185 Object.assign(prefInfo.style, { 186 width: "12px", 187 height: "12px", 188 }); 189 190 prefInfo.classList.add("experimental-pref-icon"); 191 192 // Preference name 193 const prefTitle = toolbox.doc.createElement("span"); 194 195 Object.assign(prefTitle.style, { 196 userSelect: "text", 197 fontWeight: isPrefEnabled ? "bold" : "normal", 198 }); 199 200 prefTitle.textContent = name; 201 202 // Value 203 const prefValue = toolbox.doc.createElement("span"); 204 prefValue.textContent = isPrefEnabled; 205 206 // Toggle Button 207 const toggleButton = toolbox.doc.createElement("button"); 208 toggleButton.addEventListener("click", () => { 209 Services.prefs.setBoolPref(name, !isPrefEnabled); 210 updateTooltipContent(toolbox); 211 }); 212 toggleButton.textContent = "toggle"; 213 214 prefEl.append(prefInfo, prefTitle, prefValue, toggleButton); 215 return prefEl; 216 } 217 218 function isAnyPreferenceEnabled() { 219 for (const [name] of PREFERENCES) { 220 const isPrefEnabled = Services.prefs.getBoolPref(name, false); 221 if (isPrefEnabled) { 222 return true; 223 } 224 } 225 return false; 226 } 227 exports.isAnyPreferenceEnabled = isAnyPreferenceEnabled;