--- a/devtools/client/commandline/test/helpers.js
+++ b/devtools/client/commandline/test/helpers.js
@@ -19,16 +19,17 @@
// A copy of this code exists in firefox mochitests. They should be kept
// in sync. Hence the exports synonym for non AMD contexts.
var { helpers, assert } = (function () {
var helpers = {};
var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
var { TargetFactory } = require("devtools/client/framework/target");
+ var { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
var Services = require("Services");
var assert = { ok: ok, is: is, log: info };
var util = require("gcli/util/util");
var cli = require("gcli/cli");
var KeyEvent = require("gcli/util/util").KeyEvent;
const { GcliFront } = require("devtools/shared/fronts/gcli");
@@ -206,18 +207,18 @@ var { helpers, assert } = (function () {
* - requisition
* @return A promise which resolves to the options object when the 'load' event
* happens on the new tab
*/
helpers.openToolbar = function (options) {
options = options || {};
options.chromeWindow = options.chromeWindow || window;
- return options.chromeWindow.DeveloperToolbar.show(true).then(function () {
- var toolbar = options.chromeWindow.DeveloperToolbar;
+ var toolbar = gDevToolsBrowser.getDeveloperToolbar(options.chromeWindow);
+ return toolbar.show(true).then(function () {
options.automator = createDeveloperToolbarAutomator(toolbar);
options.requisition = toolbar.requisition;
return options;
});
};
/**
* Navigate the current tab to a URL
@@ -238,17 +239,18 @@ var { helpers, assert } = (function () {
});
/**
* Undo the effects of |helpers.openToolbar|
* @param options The options object passed to |helpers.openToolbar|
* @return A promise resolved (with undefined) when the toolbar is closed
*/
helpers.closeToolbar = function (options) {
- return options.chromeWindow.DeveloperToolbar.hide().then(function () {
+ var toolbar = gDevToolsBrowser.getDeveloperToolbar(options.chromeWindow).hide();
+ return toolbar.then(function () {
delete options.automator;
delete options.requisition;
});
};
/**
* A helper to work with Task.spawn so you can do:
* return Task.spawn(realTestFunc).then(finish, helpers.handleError);
@@ -318,28 +320,28 @@ var { helpers, assert } = (function () {
* As addTab, but that also opens the developer toolbar. In addition a new
* 'automator' property is added to the options object which uses the
* developer toolbar
*/
helpers.addTabWithToolbar = function (url, callback, options) {
return helpers.addTab(url, function (innerOptions) {
var win = innerOptions.chromeWindow;
- return win.DeveloperToolbar.show(true).then(function () {
- var toolbar = win.DeveloperToolbar;
+ var toolbar = gDevToolsBrowser.getDeveloperToolbar(win);
+ return toolbar.show(true).then(function () {
innerOptions.automator = createDeveloperToolbarAutomator(toolbar);
innerOptions.requisition = toolbar.requisition;
var reply = callback.call(null, innerOptions);
return Promise.resolve(reply).catch(function (error) {
ok(false, error);
console.error(error);
}).then(function () {
- win.DeveloperToolbar.hide().then(function () {
+ toolbar.hide().then(function () {
delete innerOptions.automator;
});
});
});
}, options);
};
/**
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -19,16 +19,17 @@ const {gDevTools} = require("./devtools"
// Load target and toolbox lazily as they need gDevTools to be fully initialized
loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
loader.lazyRequireGetter(this, "BrowserMenus", "devtools/client/framework/browser-menus");
loader.lazyRequireGetter(this, "appendStyleSheet", "devtools/client/shared/stylesheet-utils", true);
+loader.lazyRequireGetter(this, "DeveloperToolbar", "devtools/client/shared/developer-toolbar", true);
loader.lazyImporter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm");
loader.lazyImporter(this, "CustomizableWidgets", "resource:///modules/CustomizableWidgets.jsm");
loader.lazyImporter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm");
loader.lazyImporter(this, "LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm");
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
@@ -50,16 +51,21 @@ var gDevToolsBrowser = exports.gDevTools
_trackedBrowserWindows: new Set(),
/**
* WeakMap keeping track of the devtools-browser stylesheets loaded in the various
* tracked windows.
*/
_browserStyleSheets: new WeakMap(),
+ /**
+ * WeakMap keeping track of DeveloperToolbar instances for each firefox window.
+ */
+ _toolbars: new WeakMap(),
+
_tabStats: {
peakOpen: 0,
peakPinned: 0,
histOpen: [],
histPinned: []
},
/**
@@ -103,17 +109,17 @@ var gDevToolsBrowser = exports.gDevTools
toggleMenuItem("menu_devToolbar", devToolbarEnabled);
let focusEl = doc.getElementById("menu_devToolbar");
if (devToolbarEnabled) {
focusEl.removeAttribute("disabled");
} else {
focusEl.setAttribute("disabled", "true");
}
if (devToolbarEnabled && Services.prefs.getBoolPref("devtools.toolbar.visible")) {
- win.DeveloperToolbar.show(false).catch(console.error);
+ this.getDeveloperToolbar(win).show(false).catch(console.error);
}
// Enable WebIDE?
let webIDEEnabled = Services.prefs.getBoolPref("devtools.webide.enabled");
toggleMenuItem("menu_webide", webIDEEnabled);
if (webIDEEnabled) {
gDevToolsBrowser.installWebIDEWidget();
@@ -494,36 +500,46 @@ var gDevToolsBrowser = exports.gDevTools
gDevToolsBrowser._trackedBrowserWindows.add(win);
BrowserMenus.addMenus(win.document);
// Register the Developer widget in the Hamburger menu or navbar
// only once menus are registered as it depends on it.
gDevToolsBrowser.installDeveloperWidget();
- // Inject lazily DeveloperToolbar on the chrome window
- loader.lazyGetter(win, "DeveloperToolbar", function () {
- let { DeveloperToolbar } = require("devtools/client/shared/developer-toolbar");
- return new DeveloperToolbar(win);
- });
-
this.updateCommandAvailability(win);
this.updateDevtoolsThemeAttribute(win);
this.ensurePrefObserver();
win.addEventListener("unload", this);
let tabContainer = win.gBrowser.tabContainer;
tabContainer.addEventListener("TabSelect", this);
tabContainer.addEventListener("TabOpen", this);
tabContainer.addEventListener("TabClose", this);
tabContainer.addEventListener("TabPinned", this);
tabContainer.addEventListener("TabUnpinned", this);
},
/**
+ * Create singleton instance of the developer toolbar for a given top level window.
+ *
+ * @param {Window} win
+ * The window to which the toolbar should be created.
+ */
+ getDeveloperToolbar(win) {
+ let toolbar = this._toolbars.get(win);
+ if (toolbar) {
+ return toolbar;
+ }
+ toolbar = new DeveloperToolbar(win);
+ this._toolbars.set(win, toolbar);
+ return toolbar;
+ },
+
+ /**
* Hook the JS debugger tool to the "Debug Script" button of the slow script
* dialog.
*/
setSlowScriptDebugHandler() {
let debugService = Cc["@mozilla.org/dom/slow-script-debug;1"]
.getService(Ci.nsISlowScriptDebug);
let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
@@ -722,21 +738,17 @@ var gDevToolsBrowser = exports.gDevTools
}
let styleSheet = this._browserStyleSheets.get(win);
if (styleSheet) {
styleSheet.remove();
this._browserStyleSheets.delete(win);
}
- // Destroy the Developer toolbar if it has been accessed
- let desc = Object.getOwnPropertyDescriptor(win, "DeveloperToolbar");
- if (desc && !desc.get) {
- win.DeveloperToolbar.destroy();
- }
+ this._toolbars.delete(win);
let tabContainer = win.gBrowser.tabContainer;
tabContainer.removeEventListener("TabSelect", this);
tabContainer.removeEventListener("TabOpen", this);
tabContainer.removeEventListener("TabClose", this);
tabContainer.removeEventListener("TabPinned", this);
tabContainer.removeEventListener("TabUnpinned", this);
},
--- a/devtools/client/menus.js
+++ b/devtools/client/menus.js
@@ -70,19 +70,19 @@ exports.menuitems = [
l10nKey: "devToolbarMenu",
disabled: true,
oncommand(event) {
let window = event.target.ownerDocument.defaultView;
// Distinguish events when selecting a menuitem, where we either open
// or close the toolbar and when hitting the key shortcut where we just
// focus the toolbar if it doesn't already has it.
if (event.target.tagName.toLowerCase() == "menuitem") {
- window.DeveloperToolbar.toggle();
+ gDevToolsBrowser.getDeveloperToolbar(window).toggle();
} else {
- window.DeveloperToolbar.focusToggle();
+ gDevToolsBrowser.getDeveloperToolbar(window).focusToggle();
}
},
key: {
id: "devToolbar",
modifiers: "shift"
},
checkbox: true
},
--- a/devtools/client/shared/developer-toolbar.js
+++ b/devtools/client/shared/developer-toolbar.js
@@ -225,17 +225,19 @@ DeveloperToolbar.prototype.createToolbar
}
let toolbar = this._doc.createElement("toolbar");
toolbar.setAttribute("id", "developer-toolbar");
toolbar.setAttribute("hidden", "true");
let close = this._doc.createElement("toolbarbutton");
close.setAttribute("id", "developer-toolbar-closebutton");
close.setAttribute("class", "close-icon");
- close.setAttribute("oncommand", "DeveloperToolbar.hide();");
+ close.addEventListener("command", (event) => {
+ this.hide();
+ });
let closeTooltip = L10N.getStr("toolbar.closeButton.tooltip");
close.setAttribute("tooltiptext", closeTooltip);
let stack = this._doc.createElement("stack");
stack.setAttribute("flex", "1");
let input = this._doc.createElement("textbox");
input.setAttribute("class", "gclitoolbar-input-node");
--- a/devtools/client/shared/test/.eslintrc.js
+++ b/devtools/client/shared/test/.eslintrc.js
@@ -1,9 +1,6 @@
"use strict";
module.exports = {
// Extend from the shared list of defined globals for mochitests.
"extends": "../../../.eslintrc.mochitests.js",
- "globals": {
- "DeveloperToolbar": true
- }
};
--- a/devtools/client/shared/test/browser_toolbar_basic.js
+++ b/devtools/client/shared/test/browser_toolbar_basic.js
@@ -1,27 +1,30 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that the developer toolbar works properly
+const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
+
const TEST_URI = TEST_URI_ROOT + "doc_toolbar_basic.html";
add_task(function* () {
info("Starting browser_toolbar_basic.js");
yield addTab(TEST_URI);
- ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible in to start");
+ let toolbar = gDevToolsBrowser.getDeveloperToolbar(window);
+ ok(!toolbar.visible, "DeveloperToolbar is not visible in to start");
- let shown = oneTimeObserve(DeveloperToolbar.NOTIFICATIONS.SHOW);
+ let shown = oneTimeObserve(toolbar.NOTIFICATIONS.SHOW);
document.getElementById("menu_devToolbar").doCommand();
yield shown;
- ok(DeveloperToolbar.visible, "DeveloperToolbar is visible in checkOpen");
+ ok(toolbar.visible, "DeveloperToolbar is visible in checkOpen");
let close = document.getElementById("developer-toolbar-closebutton");
ok(close, "Close button exists");
let toggleToolbox =
document.getElementById("menu_devToolbox");
ok(!isChecked(toggleToolbox), "toggle toolbox button is not checked");
@@ -31,30 +34,30 @@ add_task(function* () {
yield addTab("about:blank");
info("Opened a new tab");
ok(!isChecked(toggleToolbox), "toggle toolbox button is not checked");
gBrowser.removeCurrentTab();
- let hidden = oneTimeObserve(DeveloperToolbar.NOTIFICATIONS.HIDE);
+ let hidden = oneTimeObserve(toolbar.NOTIFICATIONS.HIDE);
document.getElementById("menu_devToolbar").doCommand();
yield hidden;
- ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible in hidden");
+ ok(!toolbar.visible, "DeveloperToolbar is not visible in hidden");
- shown = oneTimeObserve(DeveloperToolbar.NOTIFICATIONS.SHOW);
+ shown = oneTimeObserve(toolbar.NOTIFICATIONS.SHOW);
document.getElementById("menu_devToolbar").doCommand();
yield shown;
- ok(DeveloperToolbar.visible, "DeveloperToolbar is visible in after open");
+ ok(toolbar.visible, "DeveloperToolbar is visible in after open");
ok(isChecked(toggleToolbox), "toggle toolbox button is checked");
- hidden = oneTimeObserve(DeveloperToolbar.NOTIFICATIONS.HIDE);
+ hidden = oneTimeObserve(toolbar.NOTIFICATIONS.HIDE);
document.getElementById("developer-toolbar-closebutton").doCommand();
yield hidden;
- ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible after re-close");
+ ok(!toolbar.visible, "DeveloperToolbar is not visible after re-close");
});
function isChecked(b) {
return b.getAttribute("checked") == "true";
}
--- a/devtools/client/shared/test/browser_toolbar_tooltip.js
+++ b/devtools/client/shared/test/browser_toolbar_tooltip.js
@@ -1,99 +1,103 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that the developer toolbar works properly
+const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
+
const TEST_URI = "data:text/html;charset=utf-8,<p>Tooltip Tests</p>";
const PREF_DEVTOOLS_THEME = "devtools.theme";
registerCleanupFunction(() => {
// Set preferences back to their original values
Services.prefs.clearUserPref(PREF_DEVTOOLS_THEME);
});
+let toolbar = gDevToolsBrowser.getDeveloperToolbar(window);
+
add_task(function* showToolbar() {
yield addTab(TEST_URI);
info("Starting browser_toolbar_tooltip.js");
- ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible in runTest");
+ ok(!toolbar.visible, "DeveloperToolbar is not visible in runTest");
- let showPromise = observeOnce(DeveloperToolbar.NOTIFICATIONS.SHOW);
+ let showPromise = observeOnce(toolbar.NOTIFICATIONS.SHOW);
document.getElementById("menu_devToolbar").doCommand();
yield showPromise;
});
add_task(function* testDimensions() {
- let tooltipPanel = DeveloperToolbar.tooltipPanel;
+ let tooltipPanel = toolbar.tooltipPanel;
- DeveloperToolbar.focusManager.helpRequest();
- yield DeveloperToolbar.inputter.setInput("help help");
+ toolbar.focusManager.helpRequest();
+ yield toolbar.inputter.setInput("help help");
- DeveloperToolbar.inputter.setCursor({ start: "help help".length });
+ toolbar.inputter.setCursor({ start: "help help".length });
is(tooltipPanel._dimensions.start, "help ".length,
"search param start, when cursor at end");
ok(getLeftMargin() > 30, "tooltip offset, when cursor at end");
- DeveloperToolbar.inputter.setCursor({ start: "help".length });
+ toolbar.inputter.setCursor({ start: "help".length });
is(tooltipPanel._dimensions.start, 0,
"search param start, when cursor at end of command");
ok(getLeftMargin() > 9, "tooltip offset, when cursor at end of command");
- DeveloperToolbar.inputter.setCursor({ start: "help help".length - 1 });
+ toolbar.inputter.setCursor({ start: "help help".length - 1 });
is(tooltipPanel._dimensions.start, "help ".length,
"search param start, when cursor at penultimate position");
ok(getLeftMargin() > 30, "tooltip offset, when cursor at penultimate position");
- DeveloperToolbar.inputter.setCursor({ start: 0 });
+ toolbar.inputter.setCursor({ start: 0 });
is(tooltipPanel._dimensions.start, 0,
"search param start, when cursor at start");
ok(getLeftMargin() > 9, "tooltip offset, when cursor at start");
});
add_task(function* testThemes() {
- let tooltipPanel = DeveloperToolbar.tooltipPanel;
+ let tooltipPanel = toolbar.tooltipPanel;
ok(tooltipPanel.document, "Tooltip panel is initialized");
Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
- yield DeveloperToolbar.inputter.setInput("");
- yield DeveloperToolbar.inputter.setInput("help help");
+ yield toolbar.inputter.setInput("");
+ yield toolbar.inputter.setInput("help help");
is(tooltipPanel.document.documentElement.getAttribute("devtoolstheme"),
"dark", "Tooltip panel has correct theme");
Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
- yield DeveloperToolbar.inputter.setInput("");
- yield DeveloperToolbar.inputter.setInput("help help");
+ yield toolbar.inputter.setInput("");
+ yield toolbar.inputter.setInput("help help");
is(tooltipPanel.document.documentElement.getAttribute("devtoolstheme"),
"light", "Tooltip panel has correct theme");
});
add_task(function* hideToolbar() {
info("Ending browser_toolbar_tooltip.js");
- yield DeveloperToolbar.inputter.setInput("");
+ yield toolbar.inputter.setInput("");
- ok(DeveloperToolbar.visible, "DeveloperToolbar is visible in hideToolbar");
+ ok(toolbar.visible, "DeveloperToolbar is visible in hideToolbar");
info("Hide toolbar");
- let hidePromise = observeOnce(DeveloperToolbar.NOTIFICATIONS.HIDE);
+ let hidePromise = observeOnce(toolbar.NOTIFICATIONS.HIDE);
document.getElementById("menu_devToolbar").doCommand();
yield hidePromise;
- ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible in hideToolbar");
+ ok(!toolbar.visible, "DeveloperToolbar is not visible in hideToolbar");
info("Done test");
});
function getLeftMargin() {
- let style = DeveloperToolbar.tooltipPanel._panel.style.marginLeft;
+ let style = toolbar.tooltipPanel._panel.style.marginLeft;
return parseInt(style.slice(0, -2), 10);
}
function observeOnce(topic, ownsWeak = false) {
return new Promise(function (resolve, reject) {
let resolver = function (subject) {
Services.obs.removeObserver(resolver, topic);
resolve(subject);
--- a/devtools/client/shared/test/browser_toolbar_webconsole_errors_count.js
+++ b/devtools/client/shared/test/browser_toolbar_webconsole_errors_count.js
@@ -2,24 +2,28 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable mozilla/no-cpows-in-tests */
"use strict";
// Tests that the developer toolbar errors count works properly.
+const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
+
// Use the old webconsole since this is directly accessing old DOM, and
// the error count isn't reset when pressing the clear button in new one
// See Bug 1304794.
Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
});
+let toolbar = gDevToolsBrowser.getDeveloperToolbar(window);
+
function test() {
const TEST_URI = TEST_URI_ROOT + "doc_toolbar_webconsole_errors_count.html";
let tab1, tab2, webconsole;
Services.prefs.setBoolPref("javascript.options.strict", true);
registerCleanupFunction(() => {
@@ -30,25 +34,25 @@ function test() {
addTab(TEST_URI).then(openToolbar);
function openToolbar(tab) {
tab1 = tab;
ignoreAllUncaughtExceptions(false);
expectUncaughtException();
- if (!DeveloperToolbar.visible) {
- DeveloperToolbar.show(true).then(onOpenToolbar);
+ if (!toolbar.visible) {
+ toolbar.show(true).then(onOpenToolbar);
} else {
onOpenToolbar();
}
}
function onOpenToolbar() {
- ok(DeveloperToolbar.visible, "DeveloperToolbar is visible");
+ ok(toolbar.visible, "DeveloperToolbar is visible");
webconsole = document.getElementById("developer-toolbar-toolbox-button");
waitForButtonUpdate({
name: "web console button shows page errors",
errors: 3,
warnings: 0,
callback: addErrors,
});
@@ -235,19 +239,19 @@ function test() {
// Get out of the toolbar event execution loop.
executeSoon(options.callback);
}
return result;
}
if (!check()) {
info("wait for: " + options.name);
- DeveloperToolbar.on("errors-counter-updated", function onUpdate(event) {
+ toolbar.on("errors-counter-updated", function onUpdate(event) {
if (check()) {
- DeveloperToolbar.off(event, onUpdate);
+ toolbar.off(event, onUpdate);
}
});
}
}
function openWebConsole(tab, callback) {
let target = TargetFactory.forTab(tab);
gDevTools.showToolbox(target, "webconsole").then((toolbox) =>
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -2,16 +2,17 @@
* 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";
var WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
const {extend} = require("devtools/shared/extend");
var {TargetFactory} = require("devtools/client/framework/target");
+var {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
var {Tools} = require("devtools/client/definitions");
const { Task } = require("devtools/shared/task");
var promise = require("promise");
var Services = require("Services");
loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole", true);
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
@@ -391,17 +392,18 @@ WebConsole.prototype = {
/**
* The clear output button handler.
* @private
*/
_onClearButton: function WC__onClearButton()
{
if (this.target.isLocalTab) {
- this.browserWindow.DeveloperToolbar.resetErrorsCount(this.target.tab);
+ gDevToolsBrowser.getDeveloperToolbar(this.browserWindow)
+ .resetErrorsCount(this.target.tab);
}
},
/**
* Alias for the WebConsoleFrame.setFilterState() method.
* @see webconsole.js::WebConsoleFrame.setFilterState()
*/
setFilterState: function WC_setFilterState()