Bug 1891688: Don't rely on static_assert(false) being valid in uninstantiated templat...
[gecko.git] / devtools / client / devtools-experimental-prefs.js
blobdfa006841015e49fa42b5e118ebdd536b8c0aa32
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/. */
5 "use strict";
7 loader.lazyRequireGetter(
8   this,
9   "HTMLTooltip",
10   "resource://devtools/client/shared/widgets/tooltip/HTMLTooltip.js",
11   true
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     "devtools.every-frame-target.enabled",
23     "When enabled, targets will be created for all iframes, no matter if " +
24       "they are remote or not, independently of Fission being enabled or not",
25   ],
26   [
27     "fission.bfcacheInParent",
28     "Enable bfcache navigation in parent process (requires Fission and involve " +
29       "more top level target switching",
30   ],
33 /**
34  * Temporary module to show a Tooltip with the currently enabled preferences
35  * relevant for DevTools ongoing architectural work (e.g. Fission, EFT, …).
36  *
37  * This module should be deleted once all experimental prefs are preffed on in Nightly.
38  */
39 function showTooltip(toolbox) {
40   if (!toolbox._experimentalPrefsTooltip) {
41     toolbox._experimentalPrefsTooltip = new HTMLTooltip(toolbox.doc, {
42       type: "doorhanger",
43       useXulWrapper: true,
44     });
45     toolbox.once("destroy", () => toolbox._experimentalPrefsTooltip.destroy());
46   }
48   // Terrible hack to allow to toggle using the command button.
49   if (toolbox._experimentalPrefsTooltip.preventShow) {
50     return;
51   }
53   updateTooltipContent(toolbox);
55   const commandId = "command-button-experimental-prefs";
56   toolbox._experimentalPrefsTooltip.show(toolbox.doc.getElementById(commandId));
58   // Follows a hack to be able to close the tooltip when clicking on the
59   // command button. Otherwise it will flicker and reopen.
60   toolbox._experimentalPrefsTooltip.preventShow = true;
61   toolbox._experimentalPrefsTooltip.once("hidden", () => {
62     toolbox.win.setTimeout(
63       () => (toolbox._experimentalPrefsTooltip.preventShow = false),
64       250
65     );
66   });
68 exports.showTooltip = showTooltip;
69 function updateTooltipContent(toolbox) {
70   const container = toolbox.doc.createElement("div");
72   /*
73    *  This is the grid we want to have:
74    *  +--------------------------------------------+---------------+
75    *  | Header text                                | Reset button  |
76    *  +------+-----------------------------+-------+---------------+
77    *  | Icon | Preference name             | Value | Toggle button |
78    *  +------+-----------------------------+-------+---------------+
79    *  | Icon | Preference name             | Value | Toggle button |
80    *  +------+-----------------------------+-------+---------------+
81    */
83   Object.assign(container.style, {
84     display: "grid",
85     gridTemplateColumns:
86       "max-content minmax(300px, auto) max-content max-content",
87     gridColumnGap: "8px",
88     gridTemplateRows: `repeat(${PREFERENCES.length + 1}, auto)`,
89     gridRowGap: "8px",
90     padding: "12px",
91     fontSize: "11px",
92   });
94   container.classList.add("theme-body");
96   const headerContainer = toolbox.doc.createElement("header");
97   /**
98    * The grid layout of the header container is as follows:
99    *
100    *  +-------------------------+--------------+
101    *  | Header text             | Reset button |
102    *  +-------------------------+--------------+
103    */
105   Object.assign(headerContainer.style, {
106     display: "grid",
107     gridTemplateColumns: "subgrid",
108     gridColumn: "1 / -1",
109   });
111   const header = toolbox.doc.createElement("h1");
113   Object.assign(header.style, {
114     gridColumn: "1 / -2",
115     fontSize: "11px",
116     margin: "0",
117     padding: "0",
118   });
120   header.textContent = "DevTools Experimental preferences";
122   const resetButton = toolbox.doc.createElement("button");
123   resetButton.addEventListener("click", () => {
124     for (const [name] of PREFERENCES) {
125       Services.prefs.clearUserPref(name);
126     }
127     updateTooltipContent(toolbox);
128   });
129   resetButton.textContent = "reset all";
131   headerContainer.append(header, resetButton);
133   const prefList = toolbox.doc.createElement("ul");
134   Object.assign(prefList.style, {
135     display: "grid",
136     gridTemplateColumns: "subgrid",
137     gridTemplateRows: "subgrid",
138     // Subgrid should span all grid columns
139     gridColumn: "1 / -1",
140     gridRow: "2 / -1",
141     listStyle: "none",
142     margin: "0",
143     padding: "0",
144   });
146   for (const [name, desc] of PREFERENCES) {
147     const prefEl = createPreferenceListItem(toolbox, name, desc);
148     prefList.appendChild(prefEl);
149   }
151   container.append(headerContainer, prefList);
153   toolbox._experimentalPrefsTooltip.panel.innerHTML = "";
154   // There is a hardcoded 320px max width for doorhanger tooltips,
155   // see Bug 1654020.
156   toolbox._experimentalPrefsTooltip.panel.style.maxWidth = "unset";
157   toolbox._experimentalPrefsTooltip.panel.appendChild(container);
160 function createPreferenceListItem(toolbox, name, desc) {
161   const isPrefEnabled = Services.prefs.getBoolPref(name, false);
163   const prefEl = toolbox.doc.createElement("li");
165   /**
166    * The grid layout of a preference line is as follows:
167    *
168    *  +------+-----------------------------+-------+---------------+
169    *  | Icon | Preference name             | Value | Toggle button |
170    *  +------+-----------------------------+-------+---------------+
171    */
173   Object.assign(prefEl.style, {
174     margin: "0",
175     lineHeight: "12px",
176     display: "grid",
177     alignItems: "center",
178     gridTemplateColumns: "subgrid",
179     gridColumn: "1 / -1",
180   });
182   prefEl.classList.toggle("theme-comment", !isPrefEnabled);
184   // Icon
185   const prefInfo = toolbox.doc.createElement("div");
186   prefInfo.title = desc;
188   Object.assign(prefInfo.style, {
189     width: "12px",
190     height: "12px",
191   });
193   prefInfo.classList.add("experimental-pref-icon");
195   // Preference name
196   const prefTitle = toolbox.doc.createElement("span");
198   Object.assign(prefTitle.style, {
199     userSelect: "text",
200     fontWeight: isPrefEnabled ? "bold" : "normal",
201   });
203   prefTitle.textContent = name;
205   // Value
206   const prefValue = toolbox.doc.createElement("span");
207   prefValue.textContent = isPrefEnabled;
209   // Toggle Button
210   const toggleButton = toolbox.doc.createElement("button");
211   toggleButton.addEventListener("click", () => {
212     Services.prefs.setBoolPref(name, !isPrefEnabled);
213     updateTooltipContent(toolbox);
214   });
215   toggleButton.textContent = "toggle";
217   prefEl.append(prefInfo, prefTitle, prefValue, toggleButton);
218   return prefEl;
221 function isAnyPreferenceEnabled() {
222   for (const [name] of PREFERENCES) {
223     const isPrefEnabled = Services.prefs.getBoolPref(name, false);
224     if (isPrefEnabled) {
225       return true;
226     }
227   }
228   return false;
230 exports.isAnyPreferenceEnabled = isAnyPreferenceEnabled;