зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1308912 - Add support for addon tools registered to a specific DevTools toolbox. r=ochameau
MozReview-Commit-ID: 7DzyXLGOs5w --HG-- rename : devtools/client/framework/test/browser_toolbox_dynamic_registration.js => devtools/client/framework/test/browser_toolbox_tools_per_toolbox_registration.js extra : rebase_source : fb3b29d99151f3996624d8ba8cafaf8307affd8e extra : source : 714d261424158deabda8dc3cbf20c371775b3306
This commit is contained in:
Родитель
e86fa50b4e
Коммит
ef2eba34ab
|
@ -726,7 +726,11 @@ gDevTools.getToolDefinitionArray()
|
|||
// and the new ones.
|
||||
gDevTools.on("tool-registered", function (ev, toolId) {
|
||||
let toolDefinition = gDevTools._tools.get(toolId);
|
||||
gDevToolsBrowser._addToolToWindows(toolDefinition);
|
||||
// If the tool has been registered globally, add to all the
|
||||
// available windows.
|
||||
if (toolDefinition) {
|
||||
gDevToolsBrowser._addToolToWindows(toolDefinition);
|
||||
}
|
||||
});
|
||||
|
||||
gDevTools.on("tool-unregistered", function (ev, toolId) {
|
||||
|
|
|
@ -78,6 +78,7 @@ skip-if = e10s # Bug 1069044 - destroyInspector may hang during shutdown
|
|||
[browser_toolbox_toggle.js]
|
||||
[browser_toolbox_tool_ready.js]
|
||||
[browser_toolbox_tool_remote_reopen.js]
|
||||
[browser_toolbox_tools_per_toolbox_registration.js]
|
||||
[browser_toolbox_transport_events.js]
|
||||
[browser_toolbox_view_source_01.js]
|
||||
[browser_toolbox_view_source_02.js]
|
||||
|
|
|
@ -21,6 +21,7 @@ add_task(function* () {
|
|||
let target = TargetFactory.forTab(tab);
|
||||
toolbox = yield gDevTools.showToolbox(target);
|
||||
doc = toolbox.doc;
|
||||
yield registerNewPerToolboxTool();
|
||||
yield testSelectTool();
|
||||
yield testOptionsShortcut();
|
||||
yield testOptions();
|
||||
|
@ -46,6 +47,31 @@ function registerNewTool() {
|
|||
"The tool is registered");
|
||||
}
|
||||
|
||||
function registerNewPerToolboxTool() {
|
||||
let toolDefinition = {
|
||||
id: "test-pertoolbox-tool",
|
||||
isTargetSupported: () => true,
|
||||
visibilityswitch: "devtools.test-pertoolbox-tool.enabled",
|
||||
url: "about:blank",
|
||||
label: "perToolboxSomeLabel"
|
||||
};
|
||||
|
||||
ok(gDevTools, "gDevTools exists");
|
||||
ok(!gDevTools.getToolDefinitionMap().has("test-pertoolbox-tool"),
|
||||
"The per-toolbox tool is not registered globally");
|
||||
|
||||
ok(toolbox, "toolbox exists");
|
||||
ok(!toolbox.hasAdditionalTool("test-pertoolbox-tool"),
|
||||
"The per-toolbox tool is not yet registered to the toolbox");
|
||||
|
||||
toolbox.addAdditionalTool(toolDefinition);
|
||||
|
||||
ok(!gDevTools.getToolDefinitionMap().has("test-pertoolbox-tool"),
|
||||
"The per-toolbox tool is not registered globally");
|
||||
ok(toolbox.hasAdditionalTool("test-pertoolbox-tool"),
|
||||
"The per-toolbox tool has been registered to the toolbox");
|
||||
}
|
||||
|
||||
function* testSelectTool() {
|
||||
info("Checking to make sure that the options panel can be selected.");
|
||||
|
||||
|
@ -168,9 +194,13 @@ function* testToggleTools() {
|
|||
"#additional-tools-box input[type=checkbox]:not([data-unsupported])");
|
||||
let enabledTools = [...toolNodes].filter(node => node.checked);
|
||||
|
||||
let toggleableTools = gDevTools.getDefaultTools().filter(tool => {
|
||||
return tool.visibilityswitch;
|
||||
}).concat(gDevTools.getAdditionalTools());
|
||||
let toggleableTools = gDevTools.getDefaultTools()
|
||||
.filter(tool => {
|
||||
return tool.visibilityswitch;
|
||||
})
|
||||
.concat(gDevTools.getAdditionalTools())
|
||||
.concat(toolbox.getAdditionalTools());
|
||||
|
||||
|
||||
for (let node of toolNodes) {
|
||||
let id = node.getAttribute("id");
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URL = `data:text/html,<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
test for registering and unregistering tools to a specific toolbox
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const TOOL_ID = "test-toolbox-tool";
|
||||
var toolbox;
|
||||
var target;
|
||||
|
||||
function test() {
|
||||
addTab(TEST_URL).then(tab => {
|
||||
target = TargetFactory.forTab(tab);
|
||||
|
||||
gDevTools.showToolbox(target)
|
||||
.then(toolboxRegister)
|
||||
.then(testToolRegistered);
|
||||
});
|
||||
}
|
||||
|
||||
var resolveToolInstanceBuild;
|
||||
var waitForToolInstanceBuild = new Promise((resolve) => {
|
||||
resolveToolInstanceBuild = resolve;
|
||||
});
|
||||
|
||||
var resolveToolInstanceDestroyed;
|
||||
var waitForToolInstanceDestroyed = new Promise((resolve) => {
|
||||
resolveToolInstanceDestroyed = resolve;
|
||||
});
|
||||
|
||||
function toolboxRegister(aToolbox) {
|
||||
toolbox = aToolbox;
|
||||
|
||||
var resolveToolInstanceBuild;
|
||||
|
||||
waitForToolInstanceBuild = new Promise((resolve) => {
|
||||
resolveToolInstanceBuild = resolve;
|
||||
});
|
||||
|
||||
info("add per-toolbox tool in the opened toolbox.");
|
||||
|
||||
toolbox.addAdditionalTool({
|
||||
id: TOOL_ID,
|
||||
label: "per-toolbox Test Tool",
|
||||
inMenu: true,
|
||||
isTargetSupported: () => true,
|
||||
build: function () {
|
||||
info("per-toolbox tool has been built.");
|
||||
resolveToolInstanceBuild();
|
||||
|
||||
return {
|
||||
destroy: () => {
|
||||
info("per-toolbox tool has been destroyed.");
|
||||
resolveToolInstanceDestroyed();
|
||||
},
|
||||
};
|
||||
},
|
||||
key: "t"
|
||||
});
|
||||
}
|
||||
|
||||
function testToolRegistered() {
|
||||
ok(!gDevTools.getToolDefinitionMap().has(TOOL_ID), "per-toolbox tool is not registered globally");
|
||||
ok(toolbox.hasAdditionalTool(TOOL_ID),
|
||||
"per-toolbox tool registered to the specific toolbox");
|
||||
|
||||
// Test that the tool appeared in the UI.
|
||||
let doc = toolbox.doc;
|
||||
let tab = doc.getElementById("toolbox-tab-" + TOOL_ID);
|
||||
ok(tab, "new tool's tab exists in toolbox UI");
|
||||
|
||||
let panel = doc.getElementById("toolbox-panel-" + TOOL_ID);
|
||||
ok(panel, "new tool's panel exists in toolbox UI");
|
||||
|
||||
for (let win of getAllBrowserWindows()) {
|
||||
let key = win.document.getElementById("key_" + TOOL_ID);
|
||||
if (win.document == doc) {
|
||||
continue;
|
||||
}
|
||||
ok(!key, "key for new tool should not exists in the other browser windows");
|
||||
let menuitem = win.document.getElementById("menuitem_" + TOOL_ID);
|
||||
ok(!menuitem, "menu item should not exists in the other browser window");
|
||||
}
|
||||
|
||||
// Test that the tool is built once selected and then test its unregistering.
|
||||
info("select per-toolbox tool in the opened toolbox.");
|
||||
gDevTools.showToolbox(target, TOOL_ID)
|
||||
.then(waitForToolInstanceBuild)
|
||||
.then(testUnregister);
|
||||
}
|
||||
|
||||
function getAllBrowserWindows() {
|
||||
let wins = [];
|
||||
let enumerator = Services.wm.getEnumerator("navigator:browser");
|
||||
while (enumerator.hasMoreElements()) {
|
||||
wins.push(enumerator.getNext());
|
||||
}
|
||||
return wins;
|
||||
}
|
||||
|
||||
function testUnregister() {
|
||||
info("remove per-toolbox tool in the opened toolbox.");
|
||||
toolbox.removeAdditionalTool(TOOL_ID);
|
||||
|
||||
Promise.all([
|
||||
waitForToolInstanceDestroyed
|
||||
]).then(toolboxToolUnregistered);
|
||||
}
|
||||
|
||||
function toolboxToolUnregistered() {
|
||||
ok(!toolbox.hasAdditionalTool(TOOL_ID),
|
||||
"per-toolbox tool unregistered from the specific toolbox");
|
||||
|
||||
// test that it disappeared from the UI
|
||||
let doc = toolbox.doc;
|
||||
let tab = doc.getElementById("toolbox-tab-" + TOOL_ID);
|
||||
ok(!tab, "tool's tab was removed from the toolbox UI");
|
||||
|
||||
let panel = doc.getElementById("toolbox-panel-" + TOOL_ID);
|
||||
ok(!panel, "tool's panel was removed from toolbox UI");
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
toolbox.destroy();
|
||||
toolbox = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
|
@ -186,8 +186,12 @@ OptionsPanel.prototype = {
|
|||
"tools-not-supported-label");
|
||||
let atleastOneToolNotSupported = false;
|
||||
|
||||
const toolbox = this.toolbox;
|
||||
|
||||
// Signal tool registering/unregistering globally (for the tools registered
|
||||
// globally) and per toolbox (for the tools registered to a single toolbox).
|
||||
let onCheckboxClick = function (id) {
|
||||
let toolDefinition = gDevTools._tools.get(id);
|
||||
let toolDefinition = gDevTools._tools.get(id) || toolbox.getToolDefinition(id);
|
||||
// Set the kill switch pref boolean to true
|
||||
Services.prefs.setBoolPref(toolDefinition.visibilityswitch, this.checked);
|
||||
gDevTools.emit(this.checked ? "tool-registered" : "tool-unregistered", id);
|
||||
|
@ -239,6 +243,13 @@ OptionsPanel.prototype = {
|
|||
additionalToolsBox.appendChild(createToolCheckbox(tool));
|
||||
}
|
||||
|
||||
// Populating the additional toolbox-specific tools list that came
|
||||
// from WebExtension add-ons.
|
||||
for (let tool of this.toolbox.getAdditionalTools()) {
|
||||
atleastOneAddon = true;
|
||||
additionalToolsBox.appendChild(createToolCheckbox(tool));
|
||||
}
|
||||
|
||||
if (!atleastOneAddon) {
|
||||
additionalToolsBox.style.display = "none";
|
||||
}
|
||||
|
|
|
@ -895,6 +895,7 @@ Toolbox.prototype = {
|
|||
* Add tabs to the toolbox UI for registered tools
|
||||
*/
|
||||
_buildTabs: function () {
|
||||
// Build tabs for global registered tools.
|
||||
for (let definition of gDevTools.getToolDefinitionArray()) {
|
||||
this._buildTabForTool(definition);
|
||||
}
|
||||
|
@ -1252,6 +1253,81 @@ Toolbox.prototype = {
|
|||
this._addKeysToWindow();
|
||||
},
|
||||
|
||||
/**
|
||||
* Lazily created map of the additional tools registered to this toolbox.
|
||||
*
|
||||
* @returns {Map<string, object>}
|
||||
* a map of the tools definitions registered to this
|
||||
* particular toolbox (the key is the toolId string, the value
|
||||
* is the tool definition plain javascript object).
|
||||
*/
|
||||
get additionalToolDefinitions() {
|
||||
if (!this._additionalToolDefinitions) {
|
||||
this._additionalToolDefinitions = new Map();
|
||||
}
|
||||
|
||||
return this._additionalToolDefinitions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the array of the additional tools registered to this toolbox.
|
||||
*
|
||||
* @return {Array<object>}
|
||||
* the array of additional tool definitions registered on this toolbox.
|
||||
*/
|
||||
getAdditionalTools() {
|
||||
return Array.from(this.additionalToolDefinitions.values());
|
||||
},
|
||||
|
||||
/**
|
||||
* Test the existence of a additional tools registered to this toolbox by tool id.
|
||||
*
|
||||
* @param {string} toolId
|
||||
* the id of the tool to test for existence.
|
||||
*
|
||||
* @return {boolean}
|
||||
*
|
||||
*/
|
||||
hasAdditionalTool(toolId) {
|
||||
return this.additionalToolDefinitions.has(toolId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Register and load an additional tool on this particular toolbox.
|
||||
*
|
||||
* @param {object} definition
|
||||
* the additional tool definition to register and add to this toolbox.
|
||||
*/
|
||||
addAdditionalTool(definition) {
|
||||
if (!definition.id) {
|
||||
throw new Error("Tool definition id is missing");
|
||||
}
|
||||
|
||||
if (this.isToolRegistered(definition.id)) {
|
||||
throw new Error("Tool definition already registered: " +
|
||||
definition.id);
|
||||
}
|
||||
|
||||
this.additionalToolDefinitions.set(definition.id, definition);
|
||||
this._buildTabForTool(definition);
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregister and unload an additional tool from this particular toolbox.
|
||||
*
|
||||
* @param {string} toolId
|
||||
* the id of the additional tool to unregister and remove.
|
||||
*/
|
||||
removeAdditionalTool(toolId) {
|
||||
if (!this.hasAdditionalTool(toolId)) {
|
||||
throw new Error("Tool definition not registered to this toolbox: " +
|
||||
toolId);
|
||||
}
|
||||
|
||||
this.unloadTool(toolId);
|
||||
this.additionalToolDefinitions.delete(toolId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure the tool with the given id is loaded.
|
||||
*
|
||||
|
@ -1280,7 +1356,9 @@ Toolbox.prototype = {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
let definition = gDevTools.getToolDefinition(id);
|
||||
// Retrieve the tool definition (from the global or the per-toolbox tool maps)
|
||||
let definition = this.getToolDefinition(id);
|
||||
|
||||
if (!definition) {
|
||||
deferred.reject(new Error("no such tool id " + id));
|
||||
return deferred.promise;
|
||||
|
@ -1907,38 +1985,49 @@ Toolbox.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Return if the tool is available as a tab (i.e. if it's checked
|
||||
* in the options panel). This is different from Toolbox.getPanel -
|
||||
* a tool could be registered but not yet opened in which case
|
||||
* isToolRegistered would return true but getPanel would return false.
|
||||
* Test the availability of a tool (both globally registered tools and
|
||||
* additional tools registered to this toolbox) by tool id.
|
||||
*
|
||||
* @param {string} toolId
|
||||
* Id of the tool definition to search in the per-toolbox or globally
|
||||
* registered tools.
|
||||
*
|
||||
* @returns {bool}
|
||||
* Returns true if the tool is registered globally or on this toolbox.
|
||||
*/
|
||||
isToolRegistered: function (toolId) {
|
||||
return gDevTools.getToolDefinitionMap().has(toolId);
|
||||
return !!this.getToolDefinition(toolId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the tool-registered event.
|
||||
* @param {string} event
|
||||
* Name of the event ("tool-registered")
|
||||
* Return the tool definition registered globally or additional tools registered
|
||||
* to this toolbox.
|
||||
*
|
||||
* @param {string} toolId
|
||||
* Id of the tool that was registered
|
||||
* Id of the tool definition to retrieve for the per-toolbox and globally
|
||||
* registered tools.
|
||||
*
|
||||
* @returns {object}
|
||||
* The plain javascript object that represents the requested tool definition.
|
||||
*/
|
||||
_toolRegistered: function (event, toolId) {
|
||||
let tool = gDevTools.getToolDefinition(toolId);
|
||||
this._buildTabForTool(tool);
|
||||
// Emit the event so tools can listen to it from the toolbox level
|
||||
// instead of gDevTools
|
||||
this.emit("tool-registered", toolId);
|
||||
getToolDefinition: function (toolId) {
|
||||
return gDevTools.getToolDefinition(toolId) ||
|
||||
this.additionalToolDefinitions.get(toolId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the tool-unregistered event.
|
||||
* @param {string} event
|
||||
* Name of the event ("tool-unregistered")
|
||||
* Internal helper that removes a loaded tool from the toolbox,
|
||||
* it removes a loaded tool panel and tab from the toolbox without removing
|
||||
* its definition, so that it can still be listed in options and re-added later.
|
||||
*
|
||||
* @param {string} toolId
|
||||
* id of the tool that was unregistered.
|
||||
* Id of the tool to be removed.
|
||||
*/
|
||||
_toolUnregistered: function (event, toolId) {
|
||||
unloadTool: function (toolId) {
|
||||
if (typeof toolId != "string") {
|
||||
throw new Error("Unexpected non-string toolId received.");
|
||||
}
|
||||
|
||||
if (this._toolPanels.has(toolId)) {
|
||||
let instance = this._toolPanels.get(toolId);
|
||||
instance.destroy();
|
||||
|
@ -1975,6 +2064,38 @@ Toolbox.prototype = {
|
|||
key.parentNode.removeChild(key);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the tool-registered event.
|
||||
* @param {string} event
|
||||
* Name of the event ("tool-registered")
|
||||
* @param {string} toolId
|
||||
* Id of the tool that was registered
|
||||
*/
|
||||
_toolRegistered: function (event, toolId) {
|
||||
let tool = this.getToolDefinition(toolId);
|
||||
if (!tool) {
|
||||
// Ignore if the tool is not found, when a per-toolbox tool
|
||||
// has been toggle in the toolbox options view, every toolbox will receive
|
||||
// the toolbox-register and toolbox-unregister events.
|
||||
return;
|
||||
}
|
||||
this._buildTabForTool(tool);
|
||||
// Emit the event so tools can listen to it from the toolbox level
|
||||
// instead of gDevTools.
|
||||
this.emit("tool-registered", toolId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the tool-unregistered event.
|
||||
* @param {string} event
|
||||
* Name of the event ("tool-unregistered")
|
||||
* @param {string} toolId
|
||||
* id of the tool that was unregistered
|
||||
*/
|
||||
_toolUnregistered: function (event, toolId) {
|
||||
this.unloadTool(toolId);
|
||||
// Emit the event so tools can listen to it from the toolbox level
|
||||
// instead of gDevTools
|
||||
this.emit("tool-unregistered", toolId);
|
||||
|
|
Загрузка…
Ссылка в новой задаче