2013-05-04 10:31:07 +04:00
|
|
|
/* 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";
|
|
|
|
|
2014-04-03 12:19:42 +04:00
|
|
|
const Services = require("Services");
|
2016-02-11 15:29:47 +03:00
|
|
|
const { gDevTools } = require("devtools/client/framework/devtools");
|
2013-05-04 10:31:07 +04:00
|
|
|
|
2016-08-19 21:02:15 +03:00
|
|
|
const { LocalizationHelper } = require("devtools/shared/l10n");
|
2016-10-26 06:30:18 +03:00
|
|
|
const L10N = new LocalizationHelper(
|
|
|
|
"devtools/client/locales/toolbox.properties"
|
|
|
|
);
|
2013-05-04 10:31:07 +04:00
|
|
|
|
2018-03-20 00:18:20 +03:00
|
|
|
loader.lazyRequireGetter(
|
|
|
|
this,
|
|
|
|
"AppConstants",
|
|
|
|
"resource://gre/modules/AppConstants.jsm",
|
|
|
|
true
|
|
|
|
);
|
2019-09-27 17:31:16 +03:00
|
|
|
loader.lazyRequireGetter(
|
|
|
|
this,
|
|
|
|
"openDocLink",
|
|
|
|
"devtools/client/shared/link",
|
|
|
|
true
|
|
|
|
);
|
2016-12-27 19:59:58 +03:00
|
|
|
|
2016-08-19 21:02:15 +03:00
|
|
|
exports.OptionsPanel = OptionsPanel;
|
2013-05-28 23:36:16 +04:00
|
|
|
|
2014-07-18 19:39:00 +04:00
|
|
|
function GetPref(name) {
|
2018-06-01 13:36:09 +03:00
|
|
|
const type = Services.prefs.getPrefType(name);
|
2014-07-18 19:39:00 +04:00
|
|
|
switch (type) {
|
|
|
|
case Services.prefs.PREF_STRING:
|
|
|
|
return Services.prefs.getCharPref(name);
|
|
|
|
case Services.prefs.PREF_INT:
|
|
|
|
return Services.prefs.getIntPref(name);
|
|
|
|
case Services.prefs.PREF_BOOL:
|
|
|
|
return Services.prefs.getBoolPref(name);
|
|
|
|
default:
|
|
|
|
throw new Error("Unknown type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function SetPref(name, value) {
|
2018-06-01 13:36:09 +03:00
|
|
|
const type = Services.prefs.getPrefType(name);
|
2014-07-18 19:39:00 +04:00
|
|
|
switch (type) {
|
|
|
|
case Services.prefs.PREF_STRING:
|
|
|
|
return Services.prefs.setCharPref(name, value);
|
|
|
|
case Services.prefs.PREF_INT:
|
|
|
|
return Services.prefs.setIntPref(name, value);
|
|
|
|
case Services.prefs.PREF_BOOL:
|
|
|
|
return Services.prefs.setBoolPref(name, value);
|
|
|
|
default:
|
|
|
|
throw new Error("Unknown type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function InfallibleGetBoolPref(key) {
|
|
|
|
try {
|
|
|
|
return Services.prefs.getBoolPref(key);
|
|
|
|
} catch (ex) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-04 10:31:07 +04:00
|
|
|
/**
|
|
|
|
* Represents the Options Panel in the Toolbox.
|
|
|
|
*/
|
|
|
|
function OptionsPanel(iframeWindow, toolbox) {
|
|
|
|
this.panelDoc = iframeWindow.document;
|
|
|
|
this.panelWin = iframeWindow;
|
2014-11-18 04:35:01 +03:00
|
|
|
|
2013-05-31 19:52:06 +04:00
|
|
|
this.toolbox = toolbox;
|
2018-05-10 17:14:01 +03:00
|
|
|
this.telemetry = toolbox.telemetry;
|
2013-06-23 07:00:51 +04:00
|
|
|
this.isReady = false;
|
2013-05-04 10:31:07 +04:00
|
|
|
|
2018-04-12 20:26:06 +03:00
|
|
|
this.setupToolsList = this.setupToolsList.bind(this);
|
2014-07-17 13:39:56 +04:00
|
|
|
this._prefChanged = this._prefChanged.bind(this);
|
2014-08-18 16:25:14 +04:00
|
|
|
this._themeRegistered = this._themeRegistered.bind(this);
|
|
|
|
this._themeUnregistered = this._themeUnregistered.bind(this);
|
2014-11-25 10:47:00 +03:00
|
|
|
this._disableJSClicked = this._disableJSClicked.bind(this);
|
|
|
|
|
2017-02-22 21:33:20 +03:00
|
|
|
this.disableJSNode = this.panelDoc.getElementById(
|
|
|
|
"devtools-disable-javascript"
|
|
|
|
);
|
2014-07-17 13:39:56 +04:00
|
|
|
|
|
|
|
this._addListeners();
|
|
|
|
|
2018-03-14 19:31:12 +03:00
|
|
|
const EventEmitter = require("devtools/shared/event-emitter");
|
2013-05-04 10:31:07 +04:00
|
|
|
EventEmitter.decorate(this);
|
2013-12-18 13:34:49 +04:00
|
|
|
}
|
2013-05-04 10:31:07 +04:00
|
|
|
|
|
|
|
OptionsPanel.prototype = {
|
2013-05-28 23:36:16 +04:00
|
|
|
get target() {
|
|
|
|
return this.toolbox.target;
|
|
|
|
},
|
|
|
|
|
2018-03-11 13:05:00 +03:00
|
|
|
async open() {
|
2016-01-26 14:23:47 +03:00
|
|
|
this.setupToolsList();
|
|
|
|
this.setupToolbarButtonsList();
|
|
|
|
this.setupThemeList();
|
2019-12-17 17:22:23 +03:00
|
|
|
this.setupAdditionalOptions();
|
2018-03-11 13:05:00 +03:00
|
|
|
await this.populatePreferences();
|
2016-01-26 14:23:47 +03:00
|
|
|
this.isReady = true;
|
|
|
|
this.emit("ready");
|
|
|
|
return this;
|
2018-03-11 13:05:00 +03:00
|
|
|
},
|
2013-05-04 10:31:07 +04:00
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
_addListeners: function() {
|
2017-04-15 00:39:22 +03:00
|
|
|
Services.prefs.addObserver("devtools.cache.disabled", this._prefChanged);
|
|
|
|
Services.prefs.addObserver("devtools.theme", this._prefChanged);
|
2017-09-15 18:07:37 +03:00
|
|
|
Services.prefs.addObserver(
|
|
|
|
"devtools.source-map.client-service.enabled",
|
|
|
|
this._prefChanged
|
|
|
|
);
|
2014-08-18 16:25:14 +04:00
|
|
|
gDevTools.on("theme-registered", this._themeRegistered);
|
|
|
|
gDevTools.on("theme-unregistered", this._themeUnregistered);
|
2018-01-23 00:42:35 +03:00
|
|
|
|
2018-04-12 20:26:06 +03:00
|
|
|
// Refresh the tools list when a new tool or webextension has been
|
|
|
|
// registered to the toolbox.
|
|
|
|
this.toolbox.on("tool-registered", this.setupToolsList);
|
|
|
|
this.toolbox.on("webextension-registered", this.setupToolsList);
|
|
|
|
// Refresh the tools list when a new tool or webextension has been
|
|
|
|
// unregistered from the toolbox.
|
|
|
|
this.toolbox.on("tool-unregistered", this.setupToolsList);
|
|
|
|
this.toolbox.on("webextension-unregistered", this.setupToolsList);
|
2014-07-17 13:39:56 +04:00
|
|
|
},
|
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
_removeListeners: function() {
|
2016-09-14 16:33:55 +03:00
|
|
|
Services.prefs.removeObserver("devtools.cache.disabled", this._prefChanged);
|
|
|
|
Services.prefs.removeObserver("devtools.theme", this._prefChanged);
|
2017-09-15 18:07:37 +03:00
|
|
|
Services.prefs.removeObserver(
|
|
|
|
"devtools.source-map.client-service.enabled",
|
|
|
|
this._prefChanged
|
|
|
|
);
|
2018-01-23 00:42:35 +03:00
|
|
|
|
2018-04-12 20:26:06 +03:00
|
|
|
this.toolbox.off("tool-registered", this.setupToolsList);
|
|
|
|
this.toolbox.off("tool-unregistered", this.setupToolsList);
|
|
|
|
this.toolbox.off("webextension-registered", this.setupToolsList);
|
|
|
|
this.toolbox.off("webextension-unregistered", this.setupToolsList);
|
2018-01-23 00:42:35 +03:00
|
|
|
|
2014-08-18 16:25:14 +04:00
|
|
|
gDevTools.off("theme-registered", this._themeRegistered);
|
|
|
|
gDevTools.off("theme-unregistered", this._themeUnregistered);
|
2014-07-17 13:39:56 +04:00
|
|
|
},
|
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
_prefChanged: function(subject, topic, prefName) {
|
2016-09-14 16:33:55 +03:00
|
|
|
if (prefName === "devtools.cache.disabled") {
|
2018-06-01 13:36:09 +03:00
|
|
|
const cacheDisabled = GetPref(prefName);
|
|
|
|
const cbx = this.panelDoc.getElementById("devtools-disable-cache");
|
2014-07-17 13:39:56 +04:00
|
|
|
cbx.checked = cacheDisabled;
|
2016-09-14 16:33:55 +03:00
|
|
|
} else if (prefName === "devtools.theme") {
|
2014-08-18 16:25:14 +04:00
|
|
|
this.updateCurrentTheme();
|
2017-09-15 18:07:37 +03:00
|
|
|
} else if (prefName === "devtools.source-map.client-service.enabled") {
|
|
|
|
this.updateSourceMapPref();
|
2014-08-18 16:25:14 +04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-03-14 19:31:12 +03:00
|
|
|
_themeRegistered: function(themeId) {
|
2014-08-18 16:25:14 +04:00
|
|
|
this.setupThemeList();
|
|
|
|
},
|
|
|
|
|
2018-03-14 19:31:12 +03:00
|
|
|
_themeUnregistered: function(theme) {
|
2018-06-01 13:36:09 +03:00
|
|
|
const themeBox = this.panelDoc.getElementById("devtools-theme-box");
|
|
|
|
const themeInput = themeBox.querySelector(`[value=${theme.id}]`);
|
2014-08-18 16:25:14 +04:00
|
|
|
|
2016-02-27 01:40:14 +03:00
|
|
|
if (themeInput) {
|
|
|
|
themeInput.parentNode.remove();
|
2014-08-18 16:25:14 +04:00
|
|
|
}
|
2014-07-17 13:39:56 +04:00
|
|
|
},
|
|
|
|
|
2018-03-11 13:05:00 +03:00
|
|
|
async setupToolbarButtonsList() {
|
2016-11-19 00:02:21 +03:00
|
|
|
// Ensure the toolbox is open, and the buttons are all set up.
|
2018-03-11 13:05:00 +03:00
|
|
|
await this.toolbox.isOpen;
|
2016-11-19 00:02:21 +03:00
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const enabledToolbarButtonsBox = this.panelDoc.getElementById(
|
2016-02-27 01:40:14 +03:00
|
|
|
"enabled-toolbox-buttons-box"
|
|
|
|
);
|
2014-03-07 02:02:11 +04:00
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const toolbarButtons = this.toolbox.toolbarButtons;
|
2016-11-19 00:02:21 +03:00
|
|
|
|
|
|
|
if (!toolbarButtons) {
|
|
|
|
console.warn("The command buttons weren't initiated yet.");
|
|
|
|
return;
|
|
|
|
}
|
2014-03-07 02:02:11 +04:00
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const onCheckboxClick = checkbox => {
|
|
|
|
const commandButton = toolbarButtons.filter(
|
2016-03-12 00:23:53 +03:00
|
|
|
toggleableButton => toggleableButton.id === checkbox.id
|
|
|
|
)[0];
|
2019-09-17 22:37:00 +03:00
|
|
|
|
2016-03-12 00:23:53 +03:00
|
|
|
Services.prefs.setBoolPref(
|
2016-11-19 00:02:21 +03:00
|
|
|
commandButton.visibilityswitch,
|
|
|
|
checkbox.checked
|
|
|
|
);
|
|
|
|
this.toolbox.updateToolboxButtonsVisibility();
|
2014-03-07 02:02:11 +04:00
|
|
|
};
|
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const createCommandCheckbox = button => {
|
|
|
|
const checkboxLabel = this.panelDoc.createElement("label");
|
|
|
|
const checkboxSpanLabel = this.panelDoc.createElement("span");
|
2016-11-19 00:02:21 +03:00
|
|
|
checkboxSpanLabel.textContent = button.description;
|
2018-06-01 13:36:09 +03:00
|
|
|
const checkboxInput = this.panelDoc.createElement("input");
|
2016-02-27 01:40:14 +03:00
|
|
|
checkboxInput.setAttribute("type", "checkbox");
|
2016-11-19 00:02:21 +03:00
|
|
|
checkboxInput.setAttribute("id", button.id);
|
2019-09-17 22:37:00 +03:00
|
|
|
|
2020-02-11 00:03:28 +03:00
|
|
|
if (Services.prefs.getBoolPref(button.visibilityswitch, true)) {
|
2016-02-27 01:40:14 +03:00
|
|
|
checkboxInput.setAttribute("checked", true);
|
|
|
|
}
|
|
|
|
checkboxInput.addEventListener(
|
|
|
|
"change",
|
|
|
|
onCheckboxClick.bind(this, checkboxInput)
|
|
|
|
);
|
|
|
|
|
|
|
|
checkboxLabel.appendChild(checkboxInput);
|
|
|
|
checkboxLabel.appendChild(checkboxSpanLabel);
|
2019-10-23 03:33:24 +03:00
|
|
|
|
2016-02-27 01:40:14 +03:00
|
|
|
return checkboxLabel;
|
2014-03-07 02:02:11 +04:00
|
|
|
};
|
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const button of toolbarButtons) {
|
2016-11-19 00:02:21 +03:00
|
|
|
if (!button.isTargetSupported(this.toolbox.target)) {
|
2016-01-28 21:11:31 +03:00
|
|
|
continue;
|
|
|
|
}
|
2014-10-30 19:23:01 +03:00
|
|
|
|
2016-11-19 00:02:21 +03:00
|
|
|
enabledToolbarButtonsBox.appendChild(createCommandCheckbox(button));
|
2014-03-07 02:02:11 +04:00
|
|
|
}
|
2018-03-11 13:05:00 +03:00
|
|
|
},
|
2014-03-07 02:02:11 +04:00
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
setupToolsList: function() {
|
2018-06-01 13:36:09 +03:00
|
|
|
const defaultToolsBox = this.panelDoc.getElementById("default-tools-box");
|
|
|
|
const additionalToolsBox = this.panelDoc.getElementById(
|
2016-03-12 00:23:53 +03:00
|
|
|
"additional-tools-box"
|
|
|
|
);
|
2018-06-01 13:36:09 +03:00
|
|
|
const toolsNotSupportedLabel = this.panelDoc.getElementById(
|
2016-03-12 00:23:53 +03:00
|
|
|
"tools-not-supported-label"
|
|
|
|
);
|
2013-05-28 23:36:16 +04:00
|
|
|
let atleastOneToolNotSupported = false;
|
2013-05-04 10:31:07 +04:00
|
|
|
|
2016-11-03 20:41:26 +03:00
|
|
|
// Signal tool registering/unregistering globally (for the tools registered
|
|
|
|
// globally) and per toolbox (for the tools registered to a single toolbox).
|
2018-01-23 00:42:35 +03:00
|
|
|
// This event handler expect this to be binded to the related checkbox element.
|
2018-06-01 13:36:09 +03:00
|
|
|
const onCheckboxClick = function(telemetry, tool) {
|
2013-05-04 10:31:07 +04:00
|
|
|
// Set the kill switch pref boolean to true
|
2018-01-23 00:42:35 +03:00
|
|
|
Services.prefs.setBoolPref(tool.visibilityswitch, this.checked);
|
|
|
|
|
|
|
|
if (!tool.isWebExtension) {
|
|
|
|
gDevTools.emit(
|
|
|
|
this.checked ? "tool-registered" : "tool-unregistered",
|
|
|
|
tool.id
|
|
|
|
);
|
2018-04-09 22:26:47 +03:00
|
|
|
// Record which tools were registered and unregistered.
|
2018-05-22 10:55:00 +03:00
|
|
|
telemetry.keyedScalarSet(
|
|
|
|
"devtools.tool.registered",
|
|
|
|
tool.id,
|
|
|
|
this.checked
|
|
|
|
);
|
2018-01-23 00:42:35 +03:00
|
|
|
}
|
2013-05-04 10:31:07 +04:00
|
|
|
};
|
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const createToolCheckbox = tool => {
|
|
|
|
const checkboxLabel = this.panelDoc.createElement("label");
|
|
|
|
const checkboxInput = this.panelDoc.createElement("input");
|
2016-02-27 01:40:14 +03:00
|
|
|
checkboxInput.setAttribute("type", "checkbox");
|
|
|
|
checkboxInput.setAttribute("id", tool.id);
|
|
|
|
checkboxInput.setAttribute("title", tool.tooltip || "");
|
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const checkboxSpanLabel = this.panelDoc.createElement("span");
|
2013-05-28 23:36:16 +04:00
|
|
|
if (tool.isTargetSupported(this.target)) {
|
2016-02-27 01:40:14 +03:00
|
|
|
checkboxSpanLabel.textContent = tool.label;
|
2016-03-12 00:23:53 +03:00
|
|
|
} else {
|
2013-05-28 23:36:16 +04:00
|
|
|
atleastOneToolNotSupported = true;
|
2016-08-19 21:02:15 +03:00
|
|
|
checkboxSpanLabel.textContent = L10N.getFormatStr(
|
|
|
|
"options.toolNotSupportedMarker",
|
|
|
|
tool.label
|
|
|
|
);
|
2016-02-27 01:40:14 +03:00
|
|
|
checkboxInput.setAttribute("data-unsupported", "true");
|
|
|
|
checkboxInput.setAttribute("disabled", "true");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InfallibleGetBoolPref(tool.visibilityswitch)) {
|
|
|
|
checkboxInput.setAttribute("checked", "true");
|
2013-05-28 23:36:16 +04:00
|
|
|
}
|
2016-02-27 01:40:14 +03:00
|
|
|
|
2018-05-22 10:55:00 +03:00
|
|
|
checkboxInput.addEventListener(
|
|
|
|
"change",
|
|
|
|
onCheckboxClick.bind(checkboxInput, this.telemetry, tool)
|
|
|
|
);
|
2016-02-27 01:40:14 +03:00
|
|
|
|
|
|
|
checkboxLabel.appendChild(checkboxInput);
|
|
|
|
checkboxLabel.appendChild(checkboxSpanLabel);
|
2019-02-26 20:08:52 +03:00
|
|
|
|
2020-12-11 16:55:01 +03:00
|
|
|
// We shouldn't have deprecated tools anymore, but we might have one in the future,
|
|
|
|
// when migrating the storage inspector to the application panel (Bug 1681059).
|
|
|
|
// Let's keep this code for now so we keep the l10n property around and avoid
|
|
|
|
// unnecessary translation work if we need it again in the future.
|
2019-08-23 15:30:10 +03:00
|
|
|
if (tool.deprecated) {
|
|
|
|
const deprecationURL = this.panelDoc.createElement("a");
|
|
|
|
deprecationURL.title = deprecationURL.href = tool.deprecationURL;
|
|
|
|
deprecationURL.textContent = L10N.getStr("options.deprecationNotice");
|
2019-09-27 17:31:16 +03:00
|
|
|
// Cannot use a real link when we are in the Browser Toolbox.
|
|
|
|
deprecationURL.addEventListener("click", e => {
|
|
|
|
e.preventDefault();
|
|
|
|
openDocLink(tool.deprecationURL, { relatedToCurrent: true });
|
|
|
|
});
|
2019-08-23 15:30:10 +03:00
|
|
|
|
|
|
|
const checkboxSpanDeprecated = this.panelDoc.createElement("span");
|
|
|
|
checkboxSpanDeprecated.className = "deprecation-notice";
|
|
|
|
checkboxLabel.appendChild(checkboxSpanDeprecated);
|
|
|
|
checkboxSpanDeprecated.appendChild(deprecationURL);
|
|
|
|
}
|
|
|
|
|
2016-02-27 01:40:14 +03:00
|
|
|
return checkboxLabel;
|
2013-05-28 23:36:16 +04:00
|
|
|
};
|
|
|
|
|
2018-01-23 00:42:35 +03:00
|
|
|
// Clean up any existent default tools content.
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const label of defaultToolsBox.querySelectorAll("label")) {
|
2018-01-23 00:42:35 +03:00
|
|
|
label.remove();
|
|
|
|
}
|
|
|
|
|
2013-05-28 23:36:16 +04:00
|
|
|
// Populating the default tools lists
|
2018-06-01 13:36:09 +03:00
|
|
|
const toggleableTools = gDevTools.getDefaultTools().filter(tool => {
|
2015-08-30 01:49:22 +03:00
|
|
|
return tool.visibilityswitch && !tool.hiddenInOptions;
|
2013-11-19 00:12:02 +04:00
|
|
|
});
|
2014-04-03 12:19:42 +04:00
|
|
|
|
2018-09-27 17:33:39 +03:00
|
|
|
const fragment = this.panelDoc.createDocumentFragment();
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const tool of toggleableTools) {
|
2018-09-27 17:33:39 +03:00
|
|
|
fragment.appendChild(createToolCheckbox(tool));
|
2013-05-04 10:31:07 +04:00
|
|
|
}
|
|
|
|
|
2018-09-27 17:33:39 +03:00
|
|
|
const toolsNotSupportedLabelNode = this.panelDoc.getElementById(
|
|
|
|
"tools-not-supported-label"
|
|
|
|
);
|
|
|
|
defaultToolsBox.insertBefore(fragment, toolsNotSupportedLabelNode);
|
|
|
|
|
2018-01-23 00:42:35 +03:00
|
|
|
// Clean up any existent additional tools content.
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const label of additionalToolsBox.querySelectorAll("label")) {
|
2018-01-23 00:42:35 +03:00
|
|
|
label.remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populating the additional tools list.
|
2013-05-04 10:31:07 +04:00
|
|
|
let atleastOneAddon = false;
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const tool of gDevTools.getAdditionalTools()) {
|
2013-05-04 10:31:07 +04:00
|
|
|
atleastOneAddon = true;
|
2016-11-03 20:41:26 +03:00
|
|
|
additionalToolsBox.appendChild(createToolCheckbox(tool));
|
|
|
|
}
|
|
|
|
|
2018-01-23 00:42:35 +03:00
|
|
|
// Populating the additional tools that came from the installed WebExtension add-ons.
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const { uuid, name, pref } of this.toolbox.listWebExtensions()) {
|
2016-11-03 20:41:26 +03:00
|
|
|
atleastOneAddon = true;
|
2018-01-23 00:42:35 +03:00
|
|
|
|
|
|
|
additionalToolsBox.appendChild(
|
|
|
|
createToolCheckbox({
|
|
|
|
isWebExtension: true,
|
2019-07-05 12:24:38 +03:00
|
|
|
|
2018-01-23 00:42:35 +03:00
|
|
|
// Use the preference as the unified webextensions tool id.
|
|
|
|
id: `webext-${uuid}`,
|
|
|
|
tooltip: name,
|
|
|
|
label: name,
|
|
|
|
// Disable the devtools extension using the given pref name:
|
|
|
|
// the toolbox options for the WebExtensions are not related to a single
|
|
|
|
// tool (e.g. a devtools panel created from the extension devtools_page)
|
|
|
|
// but to the entire devtools part of a webextension which is enabled
|
|
|
|
// by the Addon Manager (but it may be disabled by its related
|
|
|
|
// devtools about:config preference), and so the following
|
|
|
|
visibilityswitch: pref,
|
2019-07-05 12:24:38 +03:00
|
|
|
|
2018-01-23 00:42:35 +03:00
|
|
|
// Only local tabs are currently supported as targets.
|
|
|
|
isTargetSupported: target => target.isLocalTab,
|
|
|
|
})
|
|
|
|
);
|
2013-05-04 10:31:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!atleastOneAddon) {
|
|
|
|
additionalToolsBox.style.display = "none";
|
2018-01-23 00:42:35 +03:00
|
|
|
} else {
|
|
|
|
additionalToolsBox.style.display = "";
|
2013-05-04 10:31:07 +04:00
|
|
|
}
|
|
|
|
|
2013-05-28 23:36:16 +04:00
|
|
|
if (!atleastOneToolNotSupported) {
|
|
|
|
toolsNotSupportedLabel.style.display = "none";
|
2018-01-23 00:42:35 +03:00
|
|
|
} else {
|
|
|
|
toolsNotSupportedLabel.style.display = "";
|
2013-05-28 23:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-05-04 10:31:07 +04:00
|
|
|
this.panelWin.focus();
|
|
|
|
},
|
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
setupThemeList: function() {
|
2018-06-01 13:36:09 +03:00
|
|
|
const themeBox = this.panelDoc.getElementById("devtools-theme-box");
|
|
|
|
const themeLabels = themeBox.querySelectorAll("label");
|
|
|
|
for (const label of themeLabels) {
|
2016-10-25 13:18:28 +03:00
|
|
|
label.remove();
|
|
|
|
}
|
2014-08-18 16:25:14 +04:00
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const createThemeOption = theme => {
|
|
|
|
const inputLabel = this.panelDoc.createElement("label");
|
|
|
|
const inputRadio = this.panelDoc.createElement("input");
|
2016-02-27 01:40:14 +03:00
|
|
|
inputRadio.setAttribute("type", "radio");
|
|
|
|
inputRadio.setAttribute("value", theme.id);
|
|
|
|
inputRadio.setAttribute("name", "devtools-theme-item");
|
2018-03-12 21:24:38 +03:00
|
|
|
inputRadio.addEventListener("change", function(e) {
|
2016-11-21 18:47:10 +03:00
|
|
|
SetPref(themeBox.getAttribute("data-pref"), e.target.value);
|
2016-02-27 01:40:14 +03:00
|
|
|
});
|
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const inputSpanLabel = this.panelDoc.createElement("span");
|
2016-02-27 01:40:14 +03:00
|
|
|
inputSpanLabel.textContent = theme.label;
|
|
|
|
inputLabel.appendChild(inputRadio);
|
|
|
|
inputLabel.appendChild(inputSpanLabel);
|
|
|
|
|
|
|
|
return inputLabel;
|
2014-08-18 16:25:14 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Populating the default theme list
|
2018-06-01 13:36:09 +03:00
|
|
|
const themes = gDevTools.getThemeDefinitionArray();
|
|
|
|
for (const theme of themes) {
|
2014-08-18 16:25:14 +04:00
|
|
|
themeBox.appendChild(createThemeOption(theme));
|
|
|
|
}
|
|
|
|
|
|
|
|
this.updateCurrentTheme();
|
|
|
|
},
|
|
|
|
|
2016-12-27 19:59:58 +03:00
|
|
|
/**
|
2019-12-17 17:22:23 +03:00
|
|
|
* Add extra checkbox options bound to a boolean preference.
|
2016-12-27 19:59:58 +03:00
|
|
|
*/
|
2019-12-17 17:22:23 +03:00
|
|
|
setupAdditionalOptions: function() {
|
|
|
|
const prefDefinitions = [];
|
2016-12-27 19:59:58 +03:00
|
|
|
|
2019-12-17 17:22:23 +03:00
|
|
|
const isNightly = AppConstants.NIGHTLY_BUILD;
|
|
|
|
if (isNightly) {
|
|
|
|
// Labels are hardcoded in english because this checkbox is Nightly only.
|
|
|
|
prefDefinitions.push({
|
2017-11-08 19:36:43 +03:00
|
|
|
pref: "devtools.performance.new-panel-enabled",
|
|
|
|
label: "Enable new performance recorder (then re-open DevTools)",
|
|
|
|
id: "devtools-new-performance",
|
|
|
|
parentId: "context-options",
|
2019-12-17 17:22:23 +03:00
|
|
|
});
|
|
|
|
}
|
2019-07-05 12:24:38 +03:00
|
|
|
|
2019-08-27 11:44:42 +03:00
|
|
|
if (this.target.isParentProcess) {
|
2019-12-17 17:22:23 +03:00
|
|
|
// The Multiprocess Browser Toolbox is only displayed in the settings
|
|
|
|
// panel for the Browser Toolbox, or when debugging the main process in
|
|
|
|
// remote debugging.
|
2019-08-27 11:44:42 +03:00
|
|
|
prefDefinitions.push({
|
|
|
|
pref: "devtools.browsertoolbox.fission",
|
2019-12-12 18:00:20 +03:00
|
|
|
label: L10N.getStr("options.enableMultiProcessToolbox"),
|
2019-08-27 11:44:42 +03:00
|
|
|
id: "devtools-browsertoolbox-fission",
|
|
|
|
parentId: "context-options",
|
2019-12-17 17:22:23 +03:00
|
|
|
// createPreferenceOption already updates the value of the preference
|
|
|
|
// for the current profile when the checkbox changes. Here we need a
|
|
|
|
// custom behavior for the Browser Toolbox, so we pass an additional
|
|
|
|
// onChange callback.
|
|
|
|
onChange: async checked => {
|
|
|
|
if (!this.toolbox.isBrowserToolbox()) {
|
|
|
|
// If we are debugging a parent process, but the toolbox is not a
|
|
|
|
// Browser Toolbox, it means we are remote debugging another
|
|
|
|
// browser. In this case, the value of devtools.browsertoolbox.fission
|
|
|
|
// should not be updated in the target browser.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// When setting this preference from the BrowserToolbox, we need to
|
|
|
|
// update the preference on the debugged Firefox profile as well.
|
|
|
|
// The devtools.browsertoolbox.fission preference is copied from the
|
|
|
|
// regular Firefox Profile to the Browser Toolbox profile.
|
|
|
|
// If the preference is not updated on the regular Firefox profile, the
|
|
|
|
// new value will be lost on the next Browser Toolbox restart.
|
|
|
|
const { mainRoot } = this.target.client;
|
|
|
|
const preferenceFront = await mainRoot.getFront("preference");
|
|
|
|
preferenceFront.setBoolPref(
|
|
|
|
"devtools.browsertoolbox.fission",
|
|
|
|
checked
|
|
|
|
);
|
|
|
|
},
|
2019-08-27 11:44:42 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-12-17 17:22:23 +03:00
|
|
|
const createPreferenceOption = ({ pref, label, id, onChange }) => {
|
2018-06-01 13:36:09 +03:00
|
|
|
const inputLabel = this.panelDoc.createElement("label");
|
|
|
|
const checkbox = this.panelDoc.createElement("input");
|
2016-12-27 19:59:58 +03:00
|
|
|
checkbox.setAttribute("type", "checkbox");
|
|
|
|
if (GetPref(pref)) {
|
|
|
|
checkbox.setAttribute("checked", "checked");
|
|
|
|
}
|
|
|
|
checkbox.setAttribute("id", id);
|
|
|
|
checkbox.addEventListener("change", e => {
|
|
|
|
SetPref(pref, e.target.checked);
|
2019-12-17 17:22:23 +03:00
|
|
|
if (onChange) {
|
|
|
|
onChange(e.target.checked);
|
|
|
|
}
|
2016-12-27 19:59:58 +03:00
|
|
|
});
|
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const inputSpanLabel = this.panelDoc.createElement("span");
|
2016-12-27 19:59:58 +03:00
|
|
|
inputSpanLabel.textContent = label;
|
|
|
|
inputLabel.appendChild(checkbox);
|
|
|
|
inputLabel.appendChild(inputSpanLabel);
|
|
|
|
|
|
|
|
return inputLabel;
|
|
|
|
};
|
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const prefDefinition of prefDefinitions) {
|
|
|
|
const parent = this.panelDoc.getElementById(prefDefinition.parentId);
|
2018-09-27 17:33:38 +03:00
|
|
|
// We want to insert the new definition after the last existing
|
|
|
|
// definition, but before any other element.
|
|
|
|
// For example in the "Advanced Settings" column there's indeed a <span>
|
|
|
|
// text at the end, and we want that it stays at the end.
|
|
|
|
// The reference element can be `null` if there's no label or if there's
|
|
|
|
// no element after the last label. But that's OK and it will do what we
|
|
|
|
// want.
|
|
|
|
const referenceElement = parent.querySelector("label:last-of-type + *");
|
|
|
|
parent.insertBefore(
|
|
|
|
createPreferenceOption(prefDefinition),
|
|
|
|
referenceElement
|
|
|
|
);
|
2016-12-27 19:59:58 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-03-11 13:05:00 +03:00
|
|
|
async populatePreferences() {
|
2018-06-01 13:36:09 +03:00
|
|
|
const prefCheckboxes = this.panelDoc.querySelectorAll(
|
2016-02-27 01:40:14 +03:00
|
|
|
"input[type=checkbox][data-pref]"
|
|
|
|
);
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const prefCheckbox of prefCheckboxes) {
|
2016-02-27 01:40:14 +03:00
|
|
|
if (GetPref(prefCheckbox.getAttribute("data-pref"))) {
|
|
|
|
prefCheckbox.setAttribute("checked", true);
|
|
|
|
}
|
2018-03-12 21:24:38 +03:00
|
|
|
prefCheckbox.addEventListener("change", function(e) {
|
2018-06-01 13:36:09 +03:00
|
|
|
const checkbox = e.target;
|
2016-11-21 18:47:10 +03:00
|
|
|
SetPref(checkbox.getAttribute("data-pref"), checkbox.checked);
|
2016-02-27 01:40:14 +03:00
|
|
|
});
|
2013-05-04 10:31:07 +04:00
|
|
|
}
|
2016-02-27 01:40:14 +03:00
|
|
|
// Themes radio inputs are handled in setupThemeList
|
2018-06-01 13:36:09 +03:00
|
|
|
const prefRadiogroups = this.panelDoc.querySelectorAll(
|
2016-02-27 01:40:14 +03:00
|
|
|
".radiogroup[data-pref]:not(#devtools-theme-box)"
|
|
|
|
);
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const radioGroup of prefRadiogroups) {
|
|
|
|
const selectedValue = GetPref(radioGroup.getAttribute("data-pref"));
|
2016-02-27 01:40:14 +03:00
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const radioInput of radioGroup.querySelectorAll(
|
|
|
|
"input[type=radio]"
|
|
|
|
)) {
|
2016-02-27 01:40:14 +03:00
|
|
|
if (radioInput.getAttribute("value") == selectedValue) {
|
|
|
|
radioInput.setAttribute("checked", true);
|
2013-05-04 10:31:07 +04:00
|
|
|
}
|
2016-02-27 01:40:14 +03:00
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
radioInput.addEventListener("change", function(e) {
|
2016-11-21 18:47:10 +03:00
|
|
|
SetPref(radioGroup.getAttribute("data-pref"), e.target.value);
|
2016-02-27 01:40:14 +03:00
|
|
|
});
|
2013-05-04 10:31:07 +04:00
|
|
|
}
|
|
|
|
}
|
2018-06-01 13:36:09 +03:00
|
|
|
const prefSelects = this.panelDoc.querySelectorAll("select[data-pref]");
|
|
|
|
for (const prefSelect of prefSelects) {
|
|
|
|
const pref = GetPref(prefSelect.getAttribute("data-pref"));
|
|
|
|
const options = [...prefSelect.options];
|
2018-03-12 21:24:38 +03:00
|
|
|
options.some(function(option) {
|
2018-06-01 13:36:09 +03:00
|
|
|
const value = option.value;
|
2016-02-27 01:40:14 +03:00
|
|
|
// non strict check to allow int values.
|
|
|
|
if (value == pref) {
|
|
|
|
prefSelect.selectedIndex = options.indexOf(option);
|
|
|
|
return true;
|
2013-09-16 14:01:25 +04:00
|
|
|
}
|
2017-02-22 21:33:20 +03:00
|
|
|
return false;
|
2016-02-27 01:40:14 +03:00
|
|
|
});
|
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
prefSelect.addEventListener("change", function(e) {
|
2018-06-01 13:36:09 +03:00
|
|
|
const select = e.target;
|
2016-11-21 18:47:10 +03:00
|
|
|
SetPref(
|
|
|
|
select.getAttribute("data-pref"),
|
2016-02-27 01:40:14 +03:00
|
|
|
select.options[select.selectedIndex].value
|
|
|
|
);
|
|
|
|
});
|
2013-09-16 14:01:25 +04:00
|
|
|
}
|
2013-12-18 13:34:49 +04:00
|
|
|
|
2019-02-02 14:24:24 +03:00
|
|
|
if (!this.target.chrome) {
|
2021-02-16 01:41:58 +03:00
|
|
|
const isJavascriptEnabled = await this.toolbox.targetList.isJavascriptEnabled();
|
|
|
|
this.disableJSNode.checked = !isJavascriptEnabled;
|
2017-02-22 21:33:20 +03:00
|
|
|
this.disableJSNode.addEventListener("click", this._disableJSClicked);
|
|
|
|
} else {
|
|
|
|
// Hide the checkbox and label
|
|
|
|
this.disableJSNode.parentNode.style.display = "none";
|
2018-09-27 17:33:41 +03:00
|
|
|
|
|
|
|
const triggersPageRefreshLabel = this.panelDoc.getElementById(
|
|
|
|
"triggers-page-refresh-label"
|
|
|
|
);
|
|
|
|
triggersPageRefreshLabel.style.display = "none";
|
2014-08-18 16:25:14 +04:00
|
|
|
}
|
2018-03-11 13:05:00 +03:00
|
|
|
},
|
2014-08-18 16:25:14 +04:00
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
updateCurrentTheme: function() {
|
2018-06-01 13:36:09 +03:00
|
|
|
const currentTheme = GetPref("devtools.theme");
|
|
|
|
const themeBox = this.panelDoc.getElementById("devtools-theme-box");
|
|
|
|
const themeRadioInput = themeBox.querySelector(`[value=${currentTheme}]`);
|
2014-08-18 16:25:14 +04:00
|
|
|
|
2016-02-27 01:40:14 +03:00
|
|
|
if (themeRadioInput) {
|
2016-09-14 16:33:55 +03:00
|
|
|
themeRadioInput.checked = true;
|
2016-02-27 01:40:14 +03:00
|
|
|
} else {
|
|
|
|
// If the current theme does not exist anymore, switch to light theme
|
2018-06-01 13:36:09 +03:00
|
|
|
const lightThemeInputRadio = themeBox.querySelector("[value=light]");
|
2016-09-14 16:33:55 +03:00
|
|
|
lightThemeInputRadio.checked = true;
|
2014-08-18 16:25:14 +04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
updateSourceMapPref: function() {
|
2017-09-15 18:07:37 +03:00
|
|
|
const prefName = "devtools.source-map.client-service.enabled";
|
2018-06-01 13:36:09 +03:00
|
|
|
const enabled = GetPref(prefName);
|
|
|
|
const box = this.panelDoc.querySelector(`[data-pref="${prefName}"]`);
|
2017-09-15 18:07:37 +03:00
|
|
|
box.checked = enabled;
|
|
|
|
},
|
|
|
|
|
2013-05-31 19:52:06 +04:00
|
|
|
/**
|
|
|
|
* Disables JavaScript for the currently loaded tab. We force a page refresh
|
|
|
|
* here because setting docShell.allowJavascript to true fails to block JS
|
|
|
|
* execution from event listeners added using addEventListener(), AJAX calls
|
|
|
|
* and timers. The page refresh prevents these things from being added in the
|
|
|
|
* first place.
|
|
|
|
*
|
|
|
|
* @param {Event} event
|
|
|
|
* The event sent by checking / unchecking the disable JS checkbox.
|
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
_disableJSClicked: function(event) {
|
2018-06-01 13:36:09 +03:00
|
|
|
const checked = event.target.checked;
|
2013-05-31 19:52:06 +04:00
|
|
|
|
2018-06-01 13:36:09 +03:00
|
|
|
const options = {
|
2013-12-18 13:34:49 +04:00
|
|
|
javascriptEnabled: !checked,
|
|
|
|
};
|
|
|
|
|
2019-02-02 14:24:24 +03:00
|
|
|
this.target.reconfigure({ options });
|
2013-12-18 13:34:49 +04:00
|
|
|
},
|
2013-12-17 14:58:21 +04:00
|
|
|
|
2018-03-12 21:24:38 +03:00
|
|
|
destroy: function() {
|
2018-09-28 10:39:44 +03:00
|
|
|
if (this.destroyed) {
|
|
|
|
return;
|
2013-12-18 13:34:49 +04:00
|
|
|
}
|
2018-09-28 10:39:44 +03:00
|
|
|
this.destroyed = true;
|
2013-12-18 13:34:49 +04:00
|
|
|
|
2014-07-17 13:39:56 +04:00
|
|
|
this._removeListeners();
|
2013-12-18 13:34:49 +04:00
|
|
|
|
2019-02-02 14:24:24 +03:00
|
|
|
this.disableJSNode.removeEventListener("click", this._disableJSClicked);
|
2013-12-18 13:34:49 +04:00
|
|
|
|
2015-05-18 21:15:35 +03:00
|
|
|
this.panelWin = this.panelDoc = this.disableJSNode = this.toolbox = null;
|
2013-05-04 10:31:07 +04:00
|
|
|
},
|
|
|
|
};
|