/* 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/. */ "use strict"; loader.lazyRequireGetter( this, "HTMLTooltip", "resource://devtools/client/shared/widgets/tooltip/HTMLTooltip.js", true ); const PREFERENCES = [ [ "fission.autostart", "Enable fission in Firefox. When navigating between two domains, you " + "will switch between two distinct processes. And if an iframe is " + "hosted from another domain, it will run in another process", ], [ "devtools.every-frame-target.enabled", "When enabled, targets will be created for all iframes, no matter if " + "they are remote or not, independently of Fission being enabled or not", ], [ "fission.bfcacheInParent", "Enable bfcache navigation in parent process (requires Fission and involve " + "more top level target switching", ], ]; /** * Temporary module to show a Tooltip with the currently enabled preferences * relevant for DevTools ongoing architectural work (e.g. Fission, EFT, …). * * This module should be deleted once all experimental prefs are preffed on in Nightly. */ function showTooltip(toolbox) { if (!toolbox._experimentalPrefsTooltip) { toolbox._experimentalPrefsTooltip = new HTMLTooltip(toolbox.doc, { type: "doorhanger", useXulWrapper: true, }); toolbox.once("destroy", () => toolbox._experimentalPrefsTooltip.destroy()); } // Terrible hack to allow to toggle using the command button. if (toolbox._experimentalPrefsTooltip.preventShow) { return; } updateTooltipContent(toolbox); const commandId = "command-button-experimental-prefs"; toolbox._experimentalPrefsTooltip.show(toolbox.doc.getElementById(commandId)); // Follows a hack to be able to close the tooltip when clicking on the // command button. Otherwise it will flicker and reopen. toolbox._experimentalPrefsTooltip.preventShow = true; toolbox._experimentalPrefsTooltip.once("hidden", () => { toolbox.win.setTimeout( () => (toolbox._experimentalPrefsTooltip.preventShow = false), 250 ); }); } exports.showTooltip = showTooltip; function updateTooltipContent(toolbox) { const container = toolbox.doc.createElement("div"); /* * This is the grid we want to have: * +--------------------------------------------+---------------+ * | Header text | Reset button | * +------+-----------------------------+-------+---------------+ * | Icon | Preference name | Value | Toggle button | * +------+-----------------------------+-------+---------------+ * | Icon | Preference name | Value | Toggle button | * +------+-----------------------------+-------+---------------+ */ Object.assign(container.style, { display: "grid", gridTemplateColumns: "max-content minmax(300px, auto) max-content max-content", gridColumnGap: "8px", gridTemplateRows: `repeat(${PREFERENCES.length + 1}, auto)`, gridRowGap: "8px", padding: "12px", fontSize: "11px", }); container.classList.add("theme-body"); const headerContainer = toolbox.doc.createElement("header"); /** * The grid layout of the header container is as follows: * * +-------------------------+--------------+ * | Header text | Reset button | * +-------------------------+--------------+ */ Object.assign(headerContainer.style, { display: "grid", gridTemplateColumns: "subgrid", gridColumn: "1 / -1", }); const header = toolbox.doc.createElement("h1"); Object.assign(header.style, { gridColumn: "1 / -2", fontSize: "11px", margin: "0", padding: "0", }); header.textContent = "DevTools Experimental preferences"; const resetButton = toolbox.doc.createElement("button"); resetButton.addEventListener("click", () => { for (const [name] of PREFERENCES) { Services.prefs.clearUserPref(name); } updateTooltipContent(toolbox); }); resetButton.textContent = "reset all"; headerContainer.append(header, resetButton); const prefList = toolbox.doc.createElement("ul"); Object.assign(prefList.style, { display: "grid", gridTemplateColumns: "subgrid", gridTemplateRows: "subgrid", // Subgrid should span all grid columns gridColumn: "1 / -1", gridRow: "2 / -1", listStyle: "none", margin: "0", padding: "0", }); for (const [name, desc] of PREFERENCES) { const prefEl = createPreferenceListItem(toolbox, name, desc); prefList.appendChild(prefEl); } container.append(headerContainer, prefList); toolbox._experimentalPrefsTooltip.panel.innerHTML = ""; // There is a hardcoded 320px max width for doorhanger tooltips, // see Bug 1654020. toolbox._experimentalPrefsTooltip.panel.style.maxWidth = "unset"; toolbox._experimentalPrefsTooltip.panel.appendChild(container); } function createPreferenceListItem(toolbox, name, desc) { const isPrefEnabled = Services.prefs.getBoolPref(name, false); const prefEl = toolbox.doc.createElement("li"); /** * The grid layout of a preference line is as follows: * * +------+-----------------------------+-------+---------------+ * | Icon | Preference name | Value | Toggle button | * +------+-----------------------------+-------+---------------+ */ Object.assign(prefEl.style, { margin: "0", lineHeight: "12px", display: "grid", alignItems: "center", gridTemplateColumns: "subgrid", gridColumn: "1 / -1", }); prefEl.classList.toggle("theme-comment", !isPrefEnabled); // Icon const prefInfo = toolbox.doc.createElement("div"); prefInfo.title = desc; Object.assign(prefInfo.style, { width: "12px", height: "12px", }); prefInfo.classList.add("experimental-pref-icon"); // Preference name const prefTitle = toolbox.doc.createElement("span"); Object.assign(prefTitle.style, { userSelect: "text", fontWeight: isPrefEnabled ? "bold" : "normal", }); prefTitle.textContent = name; // Value const prefValue = toolbox.doc.createElement("span"); prefValue.textContent = isPrefEnabled; // Toggle Button const toggleButton = toolbox.doc.createElement("button"); toggleButton.addEventListener("click", () => { Services.prefs.setBoolPref(name, !isPrefEnabled); updateTooltipContent(toolbox); }); toggleButton.textContent = "toggle"; prefEl.append(prefInfo, prefTitle, prefValue, toggleButton); return prefEl; } function isAnyPreferenceEnabled() { for (const [name] of PREFERENCES) { const isPrefEnabled = Services.prefs.getBoolPref(name, false); if (isPrefEnabled) { return true; } } return false; } exports.isAnyPreferenceEnabled = isAnyPreferenceEnabled;