author | Alexandre Poirot <poirot.alex@gmail.com> |
Wed, 21 Mar 2018 08:43:51 -0700 | |
changeset 418815 | 9e89ec8f95a95ccb2e0e0ac222c26ecfdb188a1c |
parent 418814 | c33590719e4e45e7b8ba8f5cf2a3e4801421f93a |
child 418816 | 2f774e9a7e5d2fca91daae5cdf52e66304edf10c |
push id | 34014 |
push user | aciure@mozilla.com |
push date | Fri, 18 May 2018 22:04:52 +0000 |
treeherder | mozilla-central@b54f574a1dd2 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jryans |
bugs | 1461970 |
milestone | 62.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/devtools/client/framework/devtools-browser.js +++ b/devtools/client/framework/devtools-browser.js @@ -19,17 +19,16 @@ 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/debugger-client", 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.lazyRequireGetter(this, "ResponsiveUIManager", "devtools/client/responsive.html/manager", true); loader.lazyImporter(this, "BrowserToolboxProcess", "resource://devtools/client/framework/ToolboxProcess.jsm"); loader.lazyImporter(this, "ScratchpadManager", "resource://devtools/client/scratchpad/scratchpad-manager.jsm"); loader.lazyImporter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm"); const {LocalizationHelper} = require("devtools/shared/l10n"); const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties"); @@ -49,21 +48,16 @@ var gDevToolsBrowser = exports.gDevTools /** * 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(), - - /** * This function is for the benefit of Tools:DevToolbox in * browser/base/content/browser-sets.inc and should not be used outside * of there */ // used by browser-sets.inc, command toggleToolboxCommand(gBrowser, startTime) { let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = gDevTools.getToolbox(target); @@ -93,29 +87,16 @@ var gDevToolsBrowser = exports.gDevTools cmd.removeAttribute("disabled"); cmd.removeAttribute("hidden"); } else { cmd.setAttribute("disabled", "true"); cmd.setAttribute("hidden", "true"); } } - // Enable developer toolbar? - let devToolbarEnabled = Services.prefs.getBoolPref("devtools.toolbar.enabled"); - 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")) { - 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(); } else { gDevToolsBrowser.uninstallWebIDEWidget(); @@ -259,19 +240,16 @@ var gDevToolsBrowser = exports.gDevTools return; } // Otherwise implement all other key shortcuts individually here switch (key.id) { case "toggleToolbox": case "toggleToolboxF12": gDevToolsBrowser.toggleToolboxCommand(window.gBrowser, startTime); break; - case "toggleToolbar": - gDevToolsBrowser.getDeveloperToolbar(window).focusToggle(); - break; case "webide": gDevToolsBrowser.openWebIDE(); break; case "browserToolbox": BrowserToolboxProcess.init(); break; case "browserConsole": let {HUDService} = require("devtools/client/webconsole/hudservice"); @@ -482,32 +460,16 @@ var gDevToolsBrowser = exports.gDevTools this.ensurePrefObserver(); win.addEventListener("unload", this); let tabContainer = win.gBrowser.tabContainer; tabContainer.addEventListener("TabSelect", 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); function slowScriptDebugHandler(tab, callback) { @@ -705,18 +667,16 @@ var gDevToolsBrowser = exports.gDevTools } let styleSheet = this._browserStyleSheets.get(win); if (styleSheet) { styleSheet.remove(); this._browserStyleSheets.delete(win); } - this._toolbars.delete(win); - let tabContainer = win.gBrowser.tabContainer; tabContainer.removeEventListener("TabSelect", this); }, handleEvent(event) { switch (event.type) { case "TabSelect": gDevToolsBrowser._updateMenuCheckbox();
--- a/devtools/client/framework/test/browser_dynamic_tool_enabling.js +++ b/devtools/client/framework/test/browser_dynamic_tool_enabling.js @@ -1,17 +1,16 @@ /* -*- 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/ */ // Tests that toggling prefs immediately (de)activates the relevant menuitem var gItemsToTest = { - "menu_devToolbar": "devtools.toolbar.enabled", "menu_browserToolbox": ["devtools.chrome.enabled", "devtools.debugger.remote-enabled"], "menu_devtools_connect": "devtools.debugger.remote-enabled", }; function expectedAttributeValueFromPrefs(prefs) { return prefs.every((pref) => Services.prefs.getBoolPref(pref)) ? "" : "true"; }
--- a/devtools/client/locales/en-US/menus.properties +++ b/devtools/client/locales/en-US/menus.properties @@ -36,19 +36,16 @@ browserToolboxMenu.label = Browser Toolb browserToolboxMenu.accesskey = e # LOCALIZATION NOTE (browserContentToolboxMenu.label): This is the label for the # application menu item that opens the browser content toolbox UI in the Tools menu. # This toolbox allows to debug the chrome of the content process in multiprocess builds. browserContentToolboxMenu.label = Browser Content Toolbox browserContentToolboxMenu.accesskey = x -devToolbarMenu.label = Developer Toolbar -devToolbarMenu.accesskey = v - webide.label = WebIDE webide.accesskey = W devToolboxMenuItem.label = Toggle Tools devToolboxMenuItem.accesskey = T getMoreDevtoolsCmd.label = Get More Tools getMoreDevtoolsCmd.accesskey = M
--- a/devtools/client/locales/en-US/toolbox.properties +++ b/devtools/client/locales/en-US/toolbox.properties @@ -1,41 +1,12 @@ # 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/. -# LOCALIZATION NOTE (toolboxToggleButton.errors): Semi-colon list of plural -# forms. -# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals -# #1 number of errors in the current web page -toolboxToggleButton.errors=#1 error;#1 errors - -# LOCALIZATION NOTE (toolboxToggleButton.warnings): Semi-colon list of plural -# forms. -# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals -# #1 number of warnings in the current web page -toolboxToggleButton.warnings=#1 warning;#1 warnings - -# LOCALIZATION NOTE (toolboxToggleButton.tooltip): This string is shown -# as tooltip in the developer toolbar to open/close the developer tools. -# It's using toolboxToggleButton.errors as first and -# toolboxToggleButton.warnings as second argument to show the number of errors -# and warnings. -toolboxToggleButton.tooltip=%1$S, %2$S\nClick to toggle the developer tools. - -# LOCALIZATION NOTE (toolbar.closeButton.tooltip) -# Used as a message in tooltip when overing the close button of the Developer -# Toolbar. -toolbar.closeButton.tooltip=Close Developer Toolbar - -# LOCALIZATION NOTE (toolbar.toolsButton.tooltip) -# Used as a message in tooltip when overing the wrench icon of the Developer -# Toolbar, which toggle the developer toolbox. -toolbar.toolsButton.tooltip=Toggle developer tools - # LOCALIZATION NOTE (toolbox.titleTemplate1): This is the template # used to format the title of the toolbox. # The URL of the page being targeted: %1$S. toolbox.titleTemplate1=Developer Tools - %1$S # LOCALIZATION NOTE (toolbox.titleTemplate2): This is the template # used to format the title of the toolbox. # The page title or other name for the thing being targeted: %1$S
--- a/devtools/client/menus.js +++ b/devtools/client/menus.js @@ -45,33 +45,16 @@ exports.menuitems = [ let window = event.target.ownerDocument.defaultView; gDevToolsBrowser.toggleToolboxCommand(window.gBrowser, Cu.now()); }, keyId: "toggleToolbox", checkbox: true }, { id: "menu_devtools_separator", separator: true }, - { id: "menu_devToolbar", - 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") { - gDevToolsBrowser.getDeveloperToolbar(window).toggle(); - } else { - gDevToolsBrowser.getDeveloperToolbar(window).focusToggle(); - } - }, - keyId: "toggleToolbar", - checkbox: true - }, { id: "menu_webide", l10nKey: "webide", disabled: true, oncommand() { gDevToolsBrowser.openWebIDE(); }, keyId: "webide", },
--- a/devtools/client/preferences/devtools-client.js +++ b/devtools/client/preferences/devtools-client.js @@ -8,19 +8,16 @@ pref("devtools.devedition.promo.url", "h // Only potentially show in beta release #if MOZ_UPDATE_CHANNEL == beta pref("devtools.devedition.promo.enabled", true); #else pref("devtools.devedition.promo.enabled", false); #endif -// Developer toolbar preferences -pref("devtools.toolbar.enabled", true); - // Enable DevTools WebIDE by default pref("devtools.webide.enabled", true); // Toolbox preferences pref("devtools.toolbox.footer.height", 250); pref("devtools.toolbox.sidebar.width", 500); pref("devtools.toolbox.host", "bottom"); pref("devtools.toolbox.previousHost", "side");
--- a/devtools/client/shared/developer-toolbar.js +++ b/devtools/client/shared/developer-toolbar.js @@ -1,31 +1,17 @@ /* 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"; const promise = require("promise"); -const Services = require("Services"); -const { TargetFactory } = require("devtools/client/framework/target"); -const Telemetry = require("devtools/client/shared/telemetry"); -const {LocalizationHelper} = require("devtools/shared/l10n"); -const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties"); - -const NS_XHTML = "http://www.w3.org/1999/xhtml"; - -const { PluralForm } = require("devtools/shared/plural-form"); loader.lazyRequireGetter(this, "gcliInit", "devtools/shared/gcli/commands/index"); -loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/server/actors/webconsole/listeners", true); -loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true); -loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true); -loader.lazyRequireGetter(this, "nodeConstants", "devtools/shared/dom-node-constants"); -loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter"); /** * A collection of utilities to help working with commands */ var CommandUtils = { /** * Caches requisitions created when calling executeOnTarget: * Target => Requisition Promise @@ -110,1218 +96,8 @@ var CommandUtils = { // Error("environment.document is not available in runAt:client commands"); return this.chromeWindow.gBrowser.contentDocumentAsCPOW; } }; }, }; exports.CommandUtils = CommandUtils; - -/** - * Due to a number of panel bugs we need a way to check if we are running on - * Linux. See the comments for TooltipPanel and OutputPanel for further details. - * - * When bug 780102 is fixed all isLinux checks can be removed and we can revert - * to using panels. - */ -loader.lazyGetter(this, "isLinux", function() { - return Services.appinfo.OS == "Linux"; -}); -loader.lazyGetter(this, "isMac", function() { - return Services.appinfo.OS == "Darwin"; -}); - -/** - * A component to manage the global developer toolbar, which contains a GCLI - * and buttons for various developer tools. - * @param chromeWindow The browser window to which this toolbar is attached - */ -function DeveloperToolbar(chromeWindow) { - this._chromeWindow = chromeWindow; - - // Will be setup when show() is called - this.target = null; - - // The `_showPromise` will be set once `show` is called the first time, and resolved - // when the toolbar is shown. Since it will be set to `null` only when `hide` method - // is called, multiple calls to `show` method will returns this promise instead of - // process again all the initialization. - this._showPromise = null; - // The `_hidePromise` will be set once `hide` is called, and resolved when the method - // has finished. Once the toolbar is hidden, both `_showPromise` and `_hidePromise` - // will be set to `null`. - this._hidePromise = null; - - this._doc = chromeWindow.document; - - this._telemetry = new Telemetry(); - this._errorsCount = {}; - this._warningsCount = {}; - this._errorListeners = {}; - - this._onToolboxReady = this._onToolboxReady.bind(this); - this._onToolboxDestroyed = this._onToolboxDestroyed.bind(this); - - EventEmitter.decorate(this); -} -exports.DeveloperToolbar = DeveloperToolbar; - -/** - * Inspector notifications dispatched through the nsIObserverService - */ -const NOTIFICATIONS = { - /** DeveloperToolbar.show() has been called, and we're working on it */ - LOAD: "developer-toolbar-load", - - /** DeveloperToolbar.show() has completed */ - SHOW: "developer-toolbar-show", - - /** DeveloperToolbar.hide() has been called */ - HIDE: "developer-toolbar-hide" -}; - -/** - * Attach notification constants to the object prototype so tests etc can - * use them without needing to import anything - */ -DeveloperToolbar.prototype.NOTIFICATIONS = NOTIFICATIONS; - -/** - * Is the toolbar open? - */ -Object.defineProperty(DeveloperToolbar.prototype, "visible", { - get: function() { - return this._element && !this._element.hidden; - }, - enumerable: true -}); - -var _gSequenceId = 0; - -/** - * Getter for a unique ID. - */ -Object.defineProperty(DeveloperToolbar.prototype, "sequenceId", { - get: function() { - return _gSequenceId++; - }, - enumerable: true -}); - -/** - * Create the <toolbar> element to insert within browser UI - */ -DeveloperToolbar.prototype.createToolbar = function() { - if (this._element) { - return; - } - let toolbar = this._doc.createElement("toolbar"); - toolbar.setAttribute("id", "developer-toolbar"); - toolbar.setAttribute("hidden", "true"); - toolbar.setAttribute("fullscreentoolbar", "true"); - - let close = this._doc.createElement("toolbarbutton"); - close.setAttribute("id", "developer-toolbar-closebutton"); - close.setAttribute("class", "close-icon"); - 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"); - input.setAttribute("rows", "1"); - stack.appendChild(input); - - let hbox = this._doc.createElement("hbox"); - hbox.setAttribute("class", "gclitoolbar-complete-node"); - stack.appendChild(hbox); - - let toolboxBtn = this._doc.createElement("toolbarbutton"); - toolboxBtn.setAttribute("id", "developer-toolbar-toolbox-button"); - toolboxBtn.setAttribute("class", "developer-toolbar-button"); - let toolboxTooltip = L10N.getStr("toolbar.toolsButton.tooltip"); - toolboxBtn.setAttribute("tooltiptext", toolboxTooltip); - let toolboxOpen = gDevToolsBrowser.hasToolboxOpened(this._chromeWindow); - toolboxBtn.setAttribute("checked", toolboxOpen); - toolboxBtn.addEventListener("command", function(event) { - let window = event.target.ownerDocument.defaultView; - gDevToolsBrowser.toggleToolboxCommand(window.gBrowser); - }); - this._errorCounterButton = toolboxBtn; - this._errorCounterButton._defaultTooltipText = toolboxTooltip; - - // On Mac, the close button is on the left, - // while it is on the right on every other platforms. - if (isMac) { - toolbar.appendChild(close); - toolbar.appendChild(stack); - toolbar.appendChild(toolboxBtn); - } else { - toolbar.appendChild(stack); - toolbar.appendChild(toolboxBtn); - toolbar.appendChild(close); - } - - this._element = toolbar; - let bottomBox = this._doc.getElementById("browser-bottombox"); - if (bottomBox) { - bottomBox.appendChild(this._element); - } else { - // SeaMonkey does not have a "browser-bottombox". - let statusBar = this._doc.getElementById("status-bar"); - if (statusBar) { - statusBar.parentNode.insertBefore(this._element, statusBar); - } - } -}; - -/** - * Called from browser.xul in response to menu-click or keyboard shortcut to - * toggle the toolbar - */ -DeveloperToolbar.prototype.toggle = function() { - if (this.visible) { - return this.hide().catch(console.error); - } - return this.show(true).catch(console.error); -}; - -/** - * Called from browser.xul in response to menu-click or keyboard shortcut to - * toggle the toolbar. - * The method returns a promise that would be resolved once focused; if the toolbar is not - * visible yet it will be automatically shown. - */ -DeveloperToolbar.prototype.focus = function() { - if (this.visible) { - // If the toolbar was just inserted, the <textbox> may still have - // its binding in process of being applied and not be focusable yet - return new Promise((resolve, reject) => { - let checkBinding = () => { - // Bail out if the toolbar has been destroyed in the meantime - if (!this._input) { - reject(); - return; - } - // mInputField is a xbl field of <xul:textbox> - if (typeof this._input.mInputField != "undefined") { - this._input.focus(); - resolve(); - } else { - this._input.ownerDocument.defaultView.setTimeout(checkBinding, 50); - } - }; - checkBinding(); - }); - } - - return this.show(true); -}; - -/** - * Called from browser.xul in response to menu-click or keyboard shortcut to - * toggle the toolbar - */ -DeveloperToolbar.prototype.focusToggle = function() { - if (this.visible) { - // If we have focus then the active element is the HTML input contained - // inside the xul input element - let active = this._chromeWindow.document.activeElement; - let position = this._input.compareDocumentPosition(active); - if (position & nodeConstants.DOCUMENT_POSITION_CONTAINED_BY) { - this.hide(); - } else { - this._input.focus(); - } - } else { - this.show(true); - } -}; - -/** - * Even if the user has not clicked on 'Got it' in the intro, we only show it - * once per session. - * Warning this is slightly messed up because this.DeveloperToolbar is not the - * same as this.DeveloperToolbar when in browser.js context. - */ -DeveloperToolbar.introShownThisSession = false; - -/** - * Show the developer toolbar - */ -DeveloperToolbar.prototype.show = function(focus) { - // if `_showPromise` is set, just returns it instead of process all the initialization - // again; ensuring we're focusing the element too if `focus` argument is set to `true`. - if (this._showPromise !== null) { - if (focus) { - return this.focus(); - } - return this._showPromise; - } - - this._showPromise = ((async function() { - // hide() is async, so ensure we don't need to wait for hide() to - // finish. We unconditionally yield here, even if _hidePromise is - // null, so that the spawn call returns a promise before starting - // to do any real work. - await this._hidePromise; - - // Append the browser-level stylesheet to the browser document. - await gDevToolsBrowser.loadBrowserStyleSheet(this._chromeWindow); - - this.createToolbar(); - - Services.prefs.setBoolPref("devtools.toolbar.visible", true); - - this._telemetry.toolOpened("developertoolbar"); - - this._notify(NOTIFICATIONS.LOAD); - - this._input = this._doc.querySelector(".gclitoolbar-input-node"); - - // Initializing GCLI can only be done when we've got content windows to - // write to, so this needs to be done asynchronously. - let panelPromises = [ - TooltipPanel.create(this), - OutputPanel.create(this) - ]; - let panels = await promise.all(panelPromises); - - [ this.tooltipPanel, this.outputPanel ] = panels; - - this._doc.getElementById("menu_devToolbar").setAttribute("checked", "true"); - - this.target = TargetFactory.forTab(this._chromeWindow.gBrowser.selectedTab); - const options = { - environment: CommandUtils.createEnvironment(this, "target"), - document: this.outputPanel.document, - }; - let requisition = await CommandUtils.createRequisition(this.target, options); - this.requisition = requisition; - - // The <textbox> `value` may still be undefined on the XUL binding if - // we fetch it early - let value = this._input.value || ""; - await this.requisition.update(value); - - const Inputter = require("gcli/mozui/inputter").Inputter; - const Completer = require("gcli/mozui/completer").Completer; - const Tooltip = require("gcli/mozui/tooltip").Tooltip; - const FocusManager = require("gcli/ui/focus").FocusManager; - - this.onOutput = this.requisition.commandOutputManager.onOutput; - - this.focusManager = new FocusManager(this._doc, requisition.system.settings); - - this.inputter = new Inputter({ - requisition: this.requisition, - focusManager: this.focusManager, - element: this._input, - }); - - this.completer = new Completer({ - requisition: this.requisition, - inputter: this.inputter, - backgroundElement: this._doc.querySelector(".gclitoolbar-stack-node"), - element: this._doc.querySelector(".gclitoolbar-complete-node"), - }); - - this.tooltip = new Tooltip({ - requisition: this.requisition, - focusManager: this.focusManager, - inputter: this.inputter, - element: this.tooltipPanel.hintElement, - }); - - this.inputter.tooltip = this.tooltip; - - this.focusManager.addMonitoredElement(this.outputPanel._frame); - this.focusManager.addMonitoredElement(this._element); - - this.focusManager.onVisibilityChange.add(this.outputPanel._visibilityChanged, - this.outputPanel); - this.focusManager.onVisibilityChange.add(this.tooltipPanel._visibilityChanged, - this.tooltipPanel); - this.onOutput.add(this.outputPanel._outputChanged, this.outputPanel); - - let tabbrowser = this._chromeWindow.gBrowser; - tabbrowser.tabContainer.addEventListener("TabSelect", this); - tabbrowser.tabContainer.addEventListener("TabClose", this); - tabbrowser.addEventListener("load", this, true); - tabbrowser.addEventListener("beforeunload", this, true); - - gDevTools.on("toolbox-ready", this._onToolboxReady); - gDevTools.on("toolbox-destroyed", this._onToolboxDestroyed); - - this._initErrorsCount(tabbrowser.selectedTab); - - this._element.hidden = false; - - if (focus) { - await this.focus(); - } - this._notify(NOTIFICATIONS.SHOW); - - if (!DeveloperToolbar.introShownThisSession) { - let intro = require("gcli/ui/intro"); - intro.maybeShowIntro(this.requisition.commandOutputManager, - this.requisition.conversionContext, - this.outputPanel); - DeveloperToolbar.introShownThisSession = true; - } - }).bind(this))(); - - return this._showPromise; -}; - -/** - * Hide the developer toolbar. - */ -DeveloperToolbar.prototype.hide = function() { - // If we're already in the process of hiding, just returns the promise - if (this._hidePromise !== null) { - return this._hidePromise; - } - - // If `_showPromise` is `null`, it means `show` method was never called, so just - // returns a resolved promise. - if (this._showPromise === null) { - return promise.resolve(); - } - - // show() is async, so ensure we don't need to wait for show() to finish - this._hidePromise = this._showPromise.then(() => { - this._element.hidden = true; - - Services.prefs.setBoolPref("devtools.toolbar.visible", false); - - this._doc.getElementById("menu_devToolbar").setAttribute("checked", "false"); - this.destroy(); - - this._telemetry.toolClosed("developertoolbar"); - this._notify(NOTIFICATIONS.HIDE); - - // The developer toolbar is now closed, is neither shown or in process of hiding, - // so we're set to `null` both `_showPromise` and `_hidePromise`. - this._showPromise = null; - this._hidePromise = null; - }); - - return this._hidePromise; -}; - -/** - * Initialize the listeners needed for tracking the number of errors for a given - * tab. - * - * @private - * @param nsIDOMNode tab the xul:tab for which you want to track the number of - * errors. - */ -DeveloperToolbar.prototype._initErrorsCount = function(tab) { - let tabId = tab.linkedPanel; - if (tabId in this._errorsCount) { - this._updateErrorsCount(); - return; - } - - let window = tab.linkedBrowser.contentWindow; - let listener = new ConsoleServiceListener(window, { - onConsoleServiceMessage: this._onPageError.bind(this, tabId), - }); - listener.init(); - - this._errorListeners[tabId] = listener; - this._errorsCount[tabId] = 0; - this._warningsCount[tabId] = 0; - - let messages = listener.getCachedMessages(); - messages.forEach(this._onPageError.bind(this, tabId)); - - this._updateErrorsCount(); -}; - -/** - * Stop the listeners needed for tracking the number of errors for a given - * tab. - * - * @private - * @param nsIDOMNode tab the xul:tab for which you want to stop tracking the - * number of errors. - */ -DeveloperToolbar.prototype._stopErrorsCount = function(tab) { - let tabId = tab.linkedPanel; - if (!(tabId in this._errorsCount) || !(tabId in this._warningsCount)) { - this._updateErrorsCount(); - return; - } - - this._errorListeners[tabId].destroy(); - delete this._errorListeners[tabId]; - delete this._errorsCount[tabId]; - delete this._warningsCount[tabId]; - - this._updateErrorsCount(); -}; - -/** - * Hide the developer toolbar - */ -DeveloperToolbar.prototype.destroy = function() { - if (this._input == null) { - // Already destroyed - return; - } - - let tabbrowser = this._chromeWindow.gBrowser; - tabbrowser.tabContainer.removeEventListener("TabSelect", this); - tabbrowser.tabContainer.removeEventListener("TabClose", this); - tabbrowser.removeEventListener("load", this, true); - tabbrowser.removeEventListener("beforeunload", this, true); - - gDevTools.off("toolbox-ready", this._onToolboxReady); - gDevTools.off("toolbox-destroyed", this._onToolboxDestroyed); - - Array.prototype.forEach.call(tabbrowser.tabs, this._stopErrorsCount, this); - - this.focusManager.removeMonitoredElement(this.outputPanel._frame); - this.focusManager.removeMonitoredElement(this._element); - - this.focusManager.onVisibilityChange.remove(this.outputPanel._visibilityChanged, - this.outputPanel); - this.focusManager.onVisibilityChange.remove(this.tooltipPanel._visibilityChanged, - this.tooltipPanel); - this.onOutput.remove(this.outputPanel._outputChanged, this.outputPanel); - - this.tooltip.destroy(); - this.completer.destroy(); - this.inputter.destroy(); - this.focusManager.destroy(); - - this.outputPanel.destroy(); - this.tooltipPanel.destroy(); - delete this._input; - - CommandUtils.destroyRequisition(this.requisition, this.target); - this.target = undefined; - - this._element.remove(); - delete this._element; -}; - -/** - * Utility for sending notifications - * @param topic a NOTIFICATION constant - */ -DeveloperToolbar.prototype._notify = function(topic) { - let data = { toolbar: this }; - data.wrappedJSObject = data; - Services.obs.notifyObservers(data, topic); -}; - -/** - * Update various parts of the UI when the current tab changes - */ -DeveloperToolbar.prototype.handleEvent = function(ev) { - if (ev.type == "TabSelect" || ev.type == "load") { - if (this.visible) { - let tab = this._chromeWindow.gBrowser.selectedTab; - this.target = TargetFactory.forTab(tab); - gcliInit.getSystem(this.target).then(system => { - this.requisition.system = system; - }, error => { - if (!this._chromeWindow.gBrowser.getBrowserForTab(tab)) { - // The tab was closed, suppress the error and print a warning as the - // destroyed tab was likely the cause. - console.warn("An error occurred as the tab was closed while " + - "updating Developer Toolbar state. The error was: ", error); - return; - } - - // Propagate other errors as they're more likely to cause real issues - // and thus should cause tests to fail. - throw error; - }); - - if (ev.type == "TabSelect") { - let toolboxOpen = gDevToolsBrowser.hasToolboxOpened(this._chromeWindow); - this._errorCounterButton.setAttribute("checked", toolboxOpen); - this._initErrorsCount(ev.target); - } - } - } else if (ev.type == "TabClose") { - this._stopErrorsCount(ev.target); - } else if (ev.type == "beforeunload") { - this._onPageBeforeUnload(ev); - } -}; - -/** - * Update toolbox toggle button when toolbox goes on and off - */ -DeveloperToolbar.prototype._onToolboxReady = function() { - this._errorCounterButton.setAttribute("checked", "true"); -}; -DeveloperToolbar.prototype._onToolboxDestroyed = function() { - this._errorCounterButton.setAttribute("checked", "false"); -}; - -/** - * Count a page error received for the currently selected tab. This - * method counts the JavaScript exceptions received and CSS errors/warnings. - * - * @private - * @param string tabId the ID of the tab from where the page error comes. - * @param object pageError the page error object received from the - * PageErrorListener. - */ -DeveloperToolbar.prototype._onPageError = function(tabId, pageError) { - if (pageError.category == "CSS Parser" || - pageError.category == "CSS Loader") { - return; - } - if ((pageError.flags & pageError.warningFlag) || - (pageError.flags & pageError.strictFlag)) { - this._warningsCount[tabId]++; - } else { - this._errorsCount[tabId]++; - } - this._updateErrorsCount(tabId); -}; - -/** - * The |beforeunload| event handler. This function resets the errors count when - * a different page starts loading. - * - * @private - * @param Event ev the beforeunload DOM event. - */ -DeveloperToolbar.prototype._onPageBeforeUnload = function(ev) { - let window = ev.target.defaultView; - if (window.top !== window) { - return; - } - - let tabs = this._chromeWindow.gBrowser.tabs; - Array.prototype.some.call(tabs, function(tab) { - if (tab.linkedBrowser.contentWindow === window) { - let tabId = tab.linkedPanel; - if (tabId in this._errorsCount || tabId in this._warningsCount) { - this._errorsCount[tabId] = 0; - this._warningsCount[tabId] = 0; - this._updateErrorsCount(tabId); - } - return true; - } - return false; - }, this); -}; - -/** - * Update the page errors count displayed in the Web Console button for the - * currently selected tab. - * - * @private - * @param string [changedTabId] Optional. The tab ID that had its page errors - * count changed. If this is provided and it doesn't match the currently - * selected tab, then the button is not updated. - */ -DeveloperToolbar.prototype._updateErrorsCount = function(changedTabId) { - let tabId = this._chromeWindow.gBrowser.selectedTab.linkedPanel; - if (changedTabId && tabId != changedTabId) { - return; - } - - let errors = this._errorsCount[tabId]; - let warnings = this._warningsCount[tabId]; - let btn = this._errorCounterButton; - if (errors) { - let errorsText = L10N.getStr("toolboxToggleButton.errors"); - errorsText = PluralForm.get(errors, errorsText).replace("#1", errors); - - let warningsText = L10N.getStr("toolboxToggleButton.warnings"); - warningsText = PluralForm.get(warnings, warningsText).replace("#1", warnings); - - let tooltiptext = L10N.getFormatStr("toolboxToggleButton.tooltip", - errorsText, warningsText); - - btn.setAttribute("error-count", errors); - btn.setAttribute("tooltiptext", tooltiptext); - } else { - btn.removeAttribute("error-count"); - btn.setAttribute("tooltiptext", btn._defaultTooltipText); - } - - this.emit("errors-counter-updated"); -}; - -/** - * Reset the errors counter for the given tab. - * - * @param Element tab The xul:tab for which you want to reset the page - * errors counters. - */ -DeveloperToolbar.prototype.resetErrorsCount = function(tab) { - let tabId = tab.linkedPanel; - if (tabId in this._errorsCount || tabId in this._warningsCount) { - this._errorsCount[tabId] = 0; - this._warningsCount[tabId] = 0; - this._updateErrorsCount(tabId); - } -}; - -/** - * Creating a OutputPanel is asynchronous - */ -function OutputPanel() { - throw new Error("Use OutputPanel.create()"); -} - -/** - * Panel to handle command line output. - * - * There is a tooltip bug on Windows and OSX that prevents tooltips from being - * positioned properly (bug 786975). There is a Gnome panel bug on Linux that - * causes ugly focus issues (https://bugzilla.gnome.org/show_bug.cgi?id=621848). - * We now use a tooltip on Linux and a panel on OSX & Windows. - * - * If a panel has no content and no height it is not shown when openPopup is - * called on Windows and OSX (bug 692348) ... this prevents the panel from - * appearing the first time it is shown. Setting the panel's height to 1px - * before calling openPopup works around this issue as we resize it ourselves - * anyway. - * - * @param devtoolbar The parent DeveloperToolbar object - */ -OutputPanel.create = function(devtoolbar) { - let outputPanel = Object.create(OutputPanel.prototype); - return outputPanel._init(devtoolbar); -}; - -/** - * @private See OutputPanel.create - */ -OutputPanel.prototype._init = function(devtoolbar) { - return new Promise((resolve, reject) => { - this._devtoolbar = devtoolbar; - this._input = this._devtoolbar._input; - this._toolbar = this._devtoolbar._doc.getElementById("developer-toolbar"); - - /* - <tooltip|panel id="gcli-output" - noautofocus="true" - noautohide="true" - class="gcli-panel"> - <html:iframe xmlns:html="http://www.w3.org/1999/xhtml" - id="gcli-output-frame" - src="chrome://devtools/content/commandline/commandlineoutput.xhtml" - sandbox="allow-same-origin"/> - </tooltip|panel> - */ - - // TODO: Switch back from tooltip to panel when metacity focus issue is fixed: - // https://bugzilla.mozilla.org/show_bug.cgi?id=780102 - this._panel = this._devtoolbar._doc.createElement(isLinux ? "tooltip" : "panel"); - - this._panel.id = "gcli-output"; - this._panel.classList.add("gcli-panel"); - - if (isLinux) { - this.canHide = false; - this._onpopuphiding = this._onpopuphiding.bind(this); - this._panel.addEventListener("popuphiding", this._onpopuphiding, true); - } else { - this._panel.setAttribute("noautofocus", "true"); - this._panel.setAttribute("noautohide", "true"); - - // Bug 692348: On Windows and OSX if a panel has no content and no height - // openPopup fails to display it. Setting the height to 1px alows the panel - // to be displayed before has content or a real height i.e. the first time - // it is displayed. - this._panel.setAttribute("height", "1px"); - } - - this._toolbar.parentElement.insertBefore(this._panel, this._toolbar); - - this._frame = this._devtoolbar._doc.createElementNS(NS_XHTML, "iframe"); - this._frame.id = "gcli-output-frame"; - this._frame.setAttribute("src", "chrome://devtools/content/commandline/commandlineoutput.xhtml"); - this._frame.setAttribute("sandbox", "allow-same-origin"); - this._panel.appendChild(this._frame); - - this.displayedOutput = undefined; - - this._update = this._update.bind(this); - - // Wire up the element from the iframe, and resolve the promise - let onload = () => { - this._frame.removeEventListener("load", onload, true); - - this.document = this._frame.contentDocument; - this._copyTheme(); - - this._div = this.document.getElementById("gcli-output-root"); - this._div.classList.add("gcli-row-out"); - this._div.setAttribute("aria-live", "assertive"); - - let styles = this._toolbar.ownerDocument.defaultView - .getComputedStyle(this._toolbar); - this._div.setAttribute("dir", styles.direction); - - resolve(this); - }; - this._frame.addEventListener("load", onload, true); - }); -}; - -/* Copy the current devtools theme attribute into the iframe, - so it can be styled correctly. */ -OutputPanel.prototype._copyTheme = function() { - if (this.document) { - let theme = this._devtoolbar._doc.getElementById("browser-bottombox") - .getAttribute("devtoolstheme"); - this.document.documentElement.setAttribute("devtoolstheme", theme); - } -}; - -/** - * Prevent the popup from hiding if it is not permitted via this.canHide. - */ -OutputPanel.prototype._onpopuphiding = function(ev) { - // TODO: When we switch back from tooltip to panel we can remove this hack: - // https://bugzilla.mozilla.org/show_bug.cgi?id=780102 - if (isLinux && !this.canHide) { - ev.preventDefault(); - } -}; - -/** - * Display the OutputPanel. - */ -OutputPanel.prototype.show = function() { - if (isLinux) { - this.canHide = false; - } - - // We need to reset the iframe size in order for future size calculations to - // be correct - this._frame.style.minHeight = this._frame.style.maxHeight = 0; - this._frame.style.minWidth = 0; - - this._copyTheme(); - this._panel.openPopup(this._input, "before_start", 0, 0, false, false, null); - this._resize(); - - this._input.focus(); -}; - -/** - * Internal helper to set the height of the output panel to fit the available - * content; - */ -OutputPanel.prototype._resize = function() { - if (this._panel == null || this.document == null || !this._panel.state == "closed") { - return; - } - - // Set max panel width to match any content with a max of the width of the - // browser window. - let maxWidth = this._panel.ownerDocument.documentElement.clientWidth; - - // Adjust max width according to OS. - // We'd like to put this in CSS but we can't: - // body { width: calc(min(-5px, max-content)); } - // #_panel { max-width: -5px; } - switch (Services.appinfo.OS) { - case "Linux": - maxWidth -= 5; - break; - case "Darwin": - maxWidth -= 25; - break; - case "WINNT": - maxWidth -= 5; - break; - } - - this.document.body.style.width = "-moz-max-content"; - let style = this._frame.contentWindow.getComputedStyle(this.document.body); - let frameWidth = parseInt(style.width, 10); - let width = Math.min(maxWidth, frameWidth); - this.document.body.style.width = width + "px"; - - // Set the width of the iframe. - this._frame.style.minWidth = width + "px"; - this._panel.style.maxWidth = maxWidth + "px"; - - // browserAdjustment is used to correct the panel height according to the - // browsers borders etc. - const browserAdjustment = 15; - - // Set max panel height to match any content with a max of the height of the - // browser window. - let maxHeight = - this._panel.ownerDocument.documentElement.clientHeight - browserAdjustment; - let height = Math.min(maxHeight, this.document.documentElement.scrollHeight); - - // Set the height of the iframe. Setting iframe.height does not work. - this._frame.style.minHeight = this._frame.style.maxHeight = height + "px"; - - // Set the height and width of the panel to match the iframe. - this._panel.sizeTo(width, height); - - // Move the panel to the correct position in the case that it has been - // positioned incorrectly. - let screenX = this._input.boxObject.screenX; - let screenY = this._toolbar.boxObject.screenY; - this._panel.moveTo(screenX, screenY - height); -}; - -/** - * Called by GCLI when a command is executed. - */ -OutputPanel.prototype._outputChanged = function(ev) { - if (ev.output.hidden) { - return; - } - - this.remove(); - - this.displayedOutput = ev.output; - - if (this.displayedOutput.completed) { - this._update(); - } else { - this.displayedOutput.promise.then(this._update, this._update) - .catch(console.error); - } -}; - -/** - * Called when displayed Output says it's changed or from outputChanged, which - * happens when there is a new displayed Output. - */ -OutputPanel.prototype._update = function() { - // destroy has been called, bail out - if (this._div == null) { - return; - } - - // Empty this._div - while (this._div.hasChildNodes()) { - this._div.firstChild.remove(); - } - - if (this.displayedOutput.data != null) { - let context = this._devtoolbar.requisition.conversionContext; - this.displayedOutput.convert("dom", context).then(node => { - if (node == null) { - return; - } - - while (this._div.hasChildNodes()) { - this._div.firstChild.remove(); - } - - let links = node.querySelectorAll("*[href]"); - for (let i = 0; i < links.length; i++) { - links[i].setAttribute("target", "_blank"); - } - - this._div.appendChild(node); - this.show(); - }); - } -}; - -/** - * Detach listeners from the currently displayed Output. - */ -OutputPanel.prototype.remove = function() { - if (isLinux) { - this.canHide = true; - } - - if (this._panel && this._panel.hidePopup) { - this._panel.hidePopup(); - } - - if (this.displayedOutput) { - delete this.displayedOutput; - } -}; - -/** - * Detach listeners from the currently displayed Output. - */ -OutputPanel.prototype.destroy = function() { - this.remove(); - - this._panel.removeEventListener("popuphiding", this._onpopuphiding, true); - - this._panel.removeChild(this._frame); - this._toolbar.parentElement.removeChild(this._panel); - - delete this._devtoolbar; - delete this._input; - delete this._toolbar; - delete this._onpopuphiding; - delete this._panel; - delete this._frame; - delete this._content; - delete this._div; - delete this.document; -}; - -/** - * Called by GCLI to indicate that we should show or hide one either the - * tooltip panel or the output panel. - */ -OutputPanel.prototype._visibilityChanged = function(ev) { - if (ev.outputVisible === true) { - // this.show is called by _outputChanged - } else { - if (isLinux) { - this.canHide = true; - } - this._panel.hidePopup(); - } -}; - -/** - * Creating a TooltipPanel is asynchronous - */ -function TooltipPanel() { - throw new Error("Use TooltipPanel.create()"); -} - -/** - * Panel to handle tooltips. - * - * There is a tooltip bug on Windows and OSX that prevents tooltips from being - * positioned properly (bug 786975). There is a Gnome panel bug on Linux that - * causes ugly focus issues (https://bugzilla.gnome.org/show_bug.cgi?id=621848). - * We now use a tooltip on Linux and a panel on OSX & Windows. - * - * If a panel has no content and no height it is not shown when openPopup is - * called on Windows and OSX (bug 692348) ... this prevents the panel from - * appearing the first time it is shown. Setting the panel's height to 1px - * before calling openPopup works around this issue as we resize it ourselves - * anyway. - * - * @param devtoolbar The parent DeveloperToolbar object - */ -TooltipPanel.create = function(devtoolbar) { - let tooltipPanel = Object.create(TooltipPanel.prototype); - return tooltipPanel._init(devtoolbar); -}; - -/** - * @private See TooltipPanel.create - */ -TooltipPanel.prototype._init = function(devtoolbar) { - return new Promise((resolve, reject) => { - this._devtoolbar = devtoolbar; - this._input = devtoolbar._doc.querySelector(".gclitoolbar-input-node"); - this._toolbar = devtoolbar._doc.querySelector("#developer-toolbar"); - this._dimensions = { start: 0, end: 0 }; - - /* - <tooltip|panel id="gcli-tooltip" - type="arrow" - noautofocus="true" - noautohide="true" - class="gcli-panel"> - <html:iframe xmlns:html="http://www.w3.org/1999/xhtml" - id="gcli-tooltip-frame" - src="chrome://devtools/content/commandline/commandlinetooltip.xhtml" - flex="1" - sandbox="allow-same-origin"/> - </tooltip|panel> - */ - - // TODO: Switch back from tooltip to panel when metacity focus issue is fixed: - // https://bugzilla.mozilla.org/show_bug.cgi?id=780102 - this._panel = devtoolbar._doc.createElement(isLinux ? "tooltip" : "panel"); - - this._panel.id = "gcli-tooltip"; - this._panel.classList.add("gcli-panel"); - - if (isLinux) { - this.canHide = false; - this._onpopuphiding = this._onpopuphiding.bind(this); - this._panel.addEventListener("popuphiding", this._onpopuphiding, true); - } else { - this._panel.setAttribute("noautofocus", "true"); - this._panel.setAttribute("noautohide", "true"); - - // Bug 692348: On Windows and OSX if a panel has no content and no height - // openPopup fails to display it. Setting the height to 1px alows the panel - // to be displayed before has content or a real height i.e. the first time - // it is displayed. - this._panel.setAttribute("height", "1px"); - } - - this._toolbar.parentElement.insertBefore(this._panel, this._toolbar); - - this._frame = devtoolbar._doc.createElementNS(NS_XHTML, "iframe"); - this._frame.id = "gcli-tooltip-frame"; - this._frame.setAttribute("src", "chrome://devtools/content/commandline/commandlinetooltip.xhtml"); - this._frame.setAttribute("flex", "1"); - this._frame.setAttribute("sandbox", "allow-same-origin"); - this._panel.appendChild(this._frame); - - /** - * Wire up the element from the iframe, and resolve the promise. - */ - let onload = () => { - this._frame.removeEventListener("load", onload, true); - - this.document = this._frame.contentDocument; - this._copyTheme(); - this.hintElement = this.document.getElementById("gcli-tooltip-root"); - this._connector = this.document.getElementById("gcli-tooltip-connector"); - - let styles = this._toolbar.ownerDocument.defaultView - .getComputedStyle(this._toolbar); - this.hintElement.setAttribute("dir", styles.direction); - - resolve(this); - }; - this._frame.addEventListener("load", onload, true); - }); -}; - -/* Copy the current devtools theme attribute into the iframe, - so it can be styled correctly. */ -TooltipPanel.prototype._copyTheme = function() { - if (this.document) { - let theme = this._devtoolbar._doc.getElementById("browser-bottombox") - .getAttribute("devtoolstheme"); - this.document.documentElement.setAttribute("devtoolstheme", theme); - } -}; - -/** - * Prevent the popup from hiding if it is not permitted via this.canHide. - */ -TooltipPanel.prototype._onpopuphiding = function(ev) { - // TODO: When we switch back from tooltip to panel we can remove this hack: - // https://bugzilla.mozilla.org/show_bug.cgi?id=780102 - if (isLinux && !this.canHide) { - ev.preventDefault(); - } -}; - -/** - * Display the TooltipPanel. - */ -TooltipPanel.prototype.show = function(dimensions) { - if (!dimensions) { - dimensions = { start: 0, end: 0 }; - } - this._dimensions = dimensions; - - // This is nasty, but displaying the panel causes it to re-flow, which can - // change the size it should be, so we need to resize the iframe after the - // panel has displayed - this._panel.ownerDocument.defaultView.setTimeout(() => { - this._resize(); - }, 0); - - if (isLinux) { - this.canHide = false; - } - - this._copyTheme(); - this._resize(); - this._panel.openPopup(this._input, "before_start", dimensions.start * 10, 0, - false, false, null); - this._input.focus(); -}; - -/** - * One option is to spend lots of time taking an average width of characters - * in the current font, dynamically, and weighting for the frequency of use of - * various characters, or even to render the given string off screen, and then - * measure the width. - * Or we could do this... - */ -const AVE_CHAR_WIDTH = 4.5; - -/** - * Display the TooltipPanel. - */ -TooltipPanel.prototype._resize = function() { - if (this._panel == null || this.document == null || !this._panel.state == "closed") { - return; - } - - let offset = 10 + Math.floor(this._dimensions.start * AVE_CHAR_WIDTH); - this._panel.style.marginLeft = offset + "px"; - - /* - // Bug 744906: UX review - Not sure if we want this code to fatten connector - // with param width - let width = Math.floor(this._dimensions.end * AVE_CHAR_WIDTH); - width = Math.min(width, 100); - width = Math.max(width, 10); - this._connector.style.width = width + "px"; - */ - - this._frame.height = this.document.body.scrollHeight; -}; - -/** - * Hide the TooltipPanel. - */ -TooltipPanel.prototype.remove = function() { - if (isLinux) { - this.canHide = true; - } - if (this._panel && this._panel.hidePopup) { - this._panel.hidePopup(); - } -}; - -/** - * Hide the TooltipPanel. - */ -TooltipPanel.prototype.destroy = function() { - this.remove(); - - this._panel.removeEventListener("popuphiding", this._onpopuphiding, true); - - this._panel.removeChild(this._frame); - this._toolbar.parentElement.removeChild(this._panel); - - delete this._connector; - delete this._dimensions; - delete this._input; - delete this._onpopuphiding; - delete this._panel; - delete this._frame; - delete this._toolbar; - delete this._content; - delete this.document; - delete this.hintElement; -}; - -/** - * Called by GCLI to indicate that we should show or hide one either the - * tooltip panel or the output panel. - */ -TooltipPanel.prototype._visibilityChanged = function(ev) { - if (ev.tooltipVisible === true) { - this.show(ev.dimensions); - } else { - if (isLinux) { - this.canHide = true; - } - this._panel.hidePopup(); - } -};
--- a/devtools/client/shared/test/browser.ini +++ b/devtools/client/shared/test/browser.ini @@ -19,18 +19,16 @@ support-files = doc_layoutHelpers-getBoxQuads.html doc_layoutHelpers.html doc_options-view.xul doc_spectrum.html doc_tableWidget_basic.html doc_tableWidget_keyboard_interaction.xul doc_tableWidget_mouse_interaction.xul doc_templater_basic.html - doc_toolbar_basic.html - doc_toolbar_webconsole_errors_count.html dummy.html frame-script-utils.js head.js helper_color_data.js helper_html_tooltip.js helper_inplace_editor.js leakhunt.js shared-head.js @@ -189,18 +187,13 @@ skip-if = !e10s || os == "win" # RDM onl [browser_telemetry_toolboxtabs_netmonitor.js] [browser_telemetry_toolboxtabs_options.js] [browser_telemetry_toolboxtabs_shadereditor.js] [browser_telemetry_toolboxtabs_storage.js] [browser_telemetry_toolboxtabs_styleeditor.js] [browser_telemetry_toolboxtabs_webaudioeditor.js] [browser_telemetry_toolboxtabs_webconsole.js] [browser_templater_basic.js] -[browser_toolbar_basic.js] -skip-if = (e10s && debug) # Bug 1253035 -[browser_toolbar_tooltip.js] -[browser_toolbar_webconsole_errors_count.js] -skip-if = e10s # The developertoolbar error count isn't correct with e10s [browser_treeWidget_basic.js] [browser_treeWidget_keyboard_interaction.js] [browser_treeWidget_mouse_interaction.js] [browser_devices.js] [browser_theme_switching.js]
deleted file mode 100644 --- a/devtools/client/shared/test/browser_toolbar_basic.js +++ /dev/null @@ -1,68 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// Tests that the developer toolbar works properly - -// There are shutdown issues for which multiple rejections are left uncaught. -// See bug 1018184 for resolving these issues. -const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm"); -PromiseTestUtils.whitelistRejectionsGlobally(/Connection closed/); - -const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser"); - -const TEST_URI = TEST_URI_ROOT + "doc_toolbar_basic.html"; - -add_task(async function() { - info("Starting browser_toolbar_basic.js"); - await addTab(TEST_URI); - - let toolbar = gDevToolsBrowser.getDeveloperToolbar(window); - ok(!toolbar.visible, "DeveloperToolbar is not visible in to start"); - - let shown = oneTimeObserve(toolbar.NOTIFICATIONS.SHOW); - document.getElementById("menu_devToolbar").doCommand(); - await shown; - 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"); - - let target = TargetFactory.forTab(gBrowser.selectedTab); - await gDevTools.showToolbox(target, "inspector"); - ok(isChecked(toggleToolbox), "toggle toolbox button is checked"); - - await addTab("about:blank"); - info("Opened a new tab"); - - ok(!isChecked(toggleToolbox), "toggle toolbox button is not checked"); - - gBrowser.removeCurrentTab(); - - let hidden = oneTimeObserve(toolbar.NOTIFICATIONS.HIDE); - document.getElementById("menu_devToolbar").doCommand(); - await hidden; - ok(!toolbar.visible, "DeveloperToolbar is not visible in hidden"); - - shown = oneTimeObserve(toolbar.NOTIFICATIONS.SHOW); - document.getElementById("menu_devToolbar").doCommand(); - await shown; - ok(toolbar.visible, "DeveloperToolbar is visible in after open"); - - ok(isChecked(toggleToolbox), "toggle toolbox button is checked"); - - hidden = oneTimeObserve(toolbar.NOTIFICATIONS.HIDE); - document.getElementById("developer-toolbar-closebutton").doCommand(); - await hidden; - - ok(!toolbar.visible, "DeveloperToolbar is not visible after re-close"); -}); - -function isChecked(b) { - return b.getAttribute("checked") == "true"; -}
deleted file mode 100644 --- a/devtools/client/shared/test/browser_toolbar_tooltip.js +++ /dev/null @@ -1,107 +0,0 @@ -/* 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(async function showToolbar() { - await addTab(TEST_URI); - - info("Starting browser_toolbar_tooltip.js"); - - ok(!toolbar.visible, "DeveloperToolbar is not visible in runTest"); - - let showPromise = observeOnce(toolbar.NOTIFICATIONS.SHOW); - document.getElementById("menu_devToolbar").doCommand(); - await showPromise; -}); - -add_task(async function testDimensions() { - let tooltipPanel = toolbar.tooltipPanel; - - toolbar.focusManager.helpRequest(); - await toolbar.inputter.setInput("help help"); - - 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"); - - 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"); - - 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"); - - 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(async function testThemes() { - let tooltipPanel = toolbar.tooltipPanel; - ok(tooltipPanel.document, "Tooltip panel is initialized"); - - Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark"); - - await toolbar.inputter.setInput(""); - await toolbar.inputter.setInput("help help"); - is(tooltipPanel.document.documentElement.getAttribute("devtoolstheme"), - "dark", "Tooltip panel has correct theme"); - - Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light"); - - await toolbar.inputter.setInput(""); - await toolbar.inputter.setInput("help help"); - is(tooltipPanel.document.documentElement.getAttribute("devtoolstheme"), - "light", "Tooltip panel has correct theme"); -}); - -add_task(async function hideToolbar() { - info("Ending browser_toolbar_tooltip.js"); - await toolbar.inputter.setInput(""); - - ok(toolbar.visible, "DeveloperToolbar is visible in hideToolbar"); - - info("Hide toolbar"); - let hidePromise = observeOnce(toolbar.NOTIFICATIONS.HIDE); - document.getElementById("menu_devToolbar").doCommand(); - await hidePromise; - - ok(!toolbar.visible, "DeveloperToolbar is not visible in hideToolbar"); - - info("Done test"); -}); - -function getLeftMargin() { - 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); - }; - Services.obs.addObserver(resolver, topic, ownsWeak); - }); -}
deleted file mode 100644 --- a/devtools/client/shared/test/browser_toolbar_webconsole_errors_count.js +++ /dev/null @@ -1,250 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// Tests that the developer toolbar errors count works properly. - -const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser"); - -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(() => { - Services.prefs.clearUserPref("javascript.options.strict"); - }); - - ignoreAllUncaughtExceptions(); - addTab(TEST_URI).then(openToolbar); - - function openToolbar(tab) { - tab1 = tab; - ignoreAllUncaughtExceptions(false); - - expectUncaughtException(); - - if (!toolbar.visible) { - toolbar.show(true).then(onOpenToolbar); - } else { - onOpenToolbar(); - } - } - - function onOpenToolbar() { - 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, - }); - } - - function addErrors() { - expectUncaughtException(); - - waitForFocus(function() { - let button = content.document.querySelector("button"); - executeSoon(function() { - EventUtils.synthesizeMouse(button, 3, 2, {}, content); - }); - }, content); - - waitForButtonUpdate({ - name: "button shows one more error after click in page", - errors: 4, - warnings: 1, - callback: () => { - ignoreAllUncaughtExceptions(); - addTab(TEST_URI).then(onOpenSecondTab); - }, - }); - } - - function onOpenSecondTab(tab) { - tab2 = tab; - - ignoreAllUncaughtExceptions(false); - expectUncaughtException(); - - waitForButtonUpdate({ - name: "button shows correct number of errors after new tab is open", - errors: 3, - warnings: 0, - callback: switchToTab1, - }); - } - - function switchToTab1() { - gBrowser.selectedTab = tab1; - waitForButtonUpdate({ - name: "button shows the page errors from tab 1", - errors: 4, - warnings: 1, - callback: openWebConsole.bind(null, tab1, onWebConsoleOpen), - }); - } - - function onWebConsoleOpen(hud) { - dump("lolz!!\n"); - waitForValue({ - name: "web console shows the page errors", - validator: function() { - let selector = ".message[category=exception][severity=error]"; - return hud.outputNode.querySelectorAll(selector).length; - }, - value: 4, - success: checkConsoleOutput.bind(null, hud), - failure: () => { - finish(); - }, - }); - } - - function checkConsoleOutput(hud) { - let msgs = ["foobarBug762996a", "foobarBug762996b", "foobarBug762996load", - "foobarBug762996click", "foobarBug762996consoleLog", - "foobarBug762996css", "fooBug788445"]; - msgs.forEach(function(msg) { - isnot(hud.outputNode.textContent.indexOf(msg), -1, - msg + " found in the Web Console output"); - }); - - hud.jsterm.clearOutput(); - - is(hud.outputNode.textContent.indexOf("foobarBug762996color"), -1, - "clearOutput() worked"); - - expectUncaughtException(); - let button = content.document.querySelector("button"); - EventUtils.synthesizeMouse(button, 2, 2, {}, content); - - waitForButtonUpdate({ - name: "button shows one more error after another click in page", - errors: 5, - // warnings are not repeated by the js engine - warnings: 1, - callback: () => waitForValue(waitForNewError), - }); - - let waitForNewError = { - name: "the Web Console displays the new error", - validator: function() { - return hud.outputNode.textContent.indexOf("foobarBug762996click") > -1; - }, - success: doClearConsoleButton.bind(null, hud), - failure: finish, - }; - } - - function doClearConsoleButton(hud) { - let clearButton = hud.ui.rootElement - .querySelector(".webconsole-clear-console-button"); - EventUtils.synthesizeMouse(clearButton, 2, 2, {}, hud.iframeWindow); - - is(hud.outputNode.textContent.indexOf("foobarBug762996click"), -1, - "clear console button worked"); - is(getErrorsCount(), 0, "page errors counter has been reset"); - let tooltip = getTooltipValues(); - is(tooltip[1], 0, "page warnings counter has been reset"); - - doPageReload(hud); - } - - function doPageReload(hud) { - tab1.linkedBrowser.addEventListener("load", onReload, true); - - ignoreAllUncaughtExceptions(); - content.location.reload(); - - function onReload() { - tab1.linkedBrowser.removeEventListener("load", onReload, true); - ignoreAllUncaughtExceptions(false); - expectUncaughtException(); - - waitForButtonUpdate({ - name: "the Web Console button count has been reset after page reload", - errors: 3, - warnings: 0, - callback: waitForValue.bind(null, waitForConsoleOutputAfterReload), - }); - } - - let waitForConsoleOutputAfterReload = { - name: "the Web Console displays the correct number of errors after reload", - validator: function() { - let selector = ".message[category=exception][severity=error]"; - return hud.outputNode.querySelectorAll(selector).length; - }, - value: 3, - success: function() { - isnot(hud.outputNode.textContent.indexOf("foobarBug762996load"), -1, - "foobarBug762996load found in console output after page reload"); - testEnd(); - }, - failure: testEnd, - }; - } - - function testEnd() { - document.getElementById("developer-toolbar-closebutton").doCommand(); - let target1 = TargetFactory.forTab(tab1); - gDevTools.closeToolbox(target1).then(() => { - gBrowser.removeTab(tab1); - gBrowser.removeTab(tab2); - finish(); - }); - } - - // Utility functions - - function getErrorsCount() { - let count = webconsole.getAttribute("error-count"); - return count ? count : "0"; - } - - function getTooltipValues() { - let matches = webconsole.getAttribute("tooltiptext") - .match(/(\d+) errors?, (\d+) warnings?/); - return matches ? [matches[1], matches[2]] : [0, 0]; - } - - function waitForButtonUpdate(options) { - function check() { - let errors = getErrorsCount(); - let tooltip = getTooltipValues(); - let result = errors == options.errors && tooltip[1] == options.warnings; - if (result) { - ok(true, options.name); - is(errors, tooltip[0], "button error-count is the same as in the tooltip"); - - // Get out of the toolbar event execution loop. - executeSoon(options.callback); - } - return result; - } - - if (!check()) { - info("wait for: " + options.name); - toolbar.on("errors-counter-updated", function onUpdate() { - if (check()) { - toolbar.off("errors-counter-updated", onUpdate); - } - }); - } - } - - function openWebConsole(tab, callback) { - let target = TargetFactory.forTab(tab); - gDevTools.showToolbox(target, "webconsole").then((toolbox) => - callback(toolbox.getCurrentPanel().hud)); - } -}
deleted file mode 100644 --- a/devtools/client/shared/test/doc_toolbar_basic.html +++ /dev/null @@ -1,40 +0,0 @@ -<!doctype html> -<!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> - -<html> -<head> - <meta charset="UTF-8"> - <title>Developer Toolbar Tests</title> - <style type="text/css"> - #single { color: red; } - </style> - <script type="text/javascript"> - /* eslint-disable */ - var a = 1; - </script> -</head> -<body> - -<p id=single> -1 -</p> - -<p class=twin> -2a -</p> - -<p class=twin> -2b -</p> - -<style> -.twin { color: blue; } -</style> -<script> -/* eslint-disable */ -var b = 2; -</script> - -</body> -</html>
deleted file mode 100644 --- a/devtools/client/shared/test/doc_toolbar_webconsole_errors_count.html +++ /dev/null @@ -1,34 +0,0 @@ -<!DOCTYPE HTML> -<!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> -<html> -<head> - <meta charset="UTF-8"> - <title>Developer Toolbar Tests - errors count in the Web Console button</title> - <script type="text/javascript"> - "use strict"; - console.log("foobarBug762996consoleLog"); - window.onload = function() { - window.foobarBug762996load(); - }; - window.foobarBug762996a(); - </script> - <script type="text/javascript"> - "use strict"; - window.foobarBug762996b(); - </script> -</head> -<body> - <p>Hello world! Test for errors count in the Web Console button (developer - toolbar).</p> - <p style="color: foobarBug762996css"><button>click me</button></p> - <script type="text/javascript"> - "use strict"; - let testObj = {}; - document.querySelector("button").onclick = function() { - testObj.fooBug788445 + "warning"; - window.foobarBug762996click(); - }; - </script> -</body> -</html>
--- a/devtools/client/webconsole/hudservice.js +++ b/devtools/client/webconsole/hudservice.js @@ -3,17 +3,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; var Services = require("Services"); loader.lazyRequireGetter(this, "Utils", "devtools/client/webconsole/utils", true); loader.lazyRequireGetter(this, "extend", "devtools/shared/extend", true); loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true); -loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true); loader.lazyRequireGetter(this, "Tools", "devtools/client/definitions", true); loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry"); loader.lazyRequireGetter(this, "NewWebConsoleFrame", "devtools/client/webconsole/new-webconsole", true); loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true); loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true); loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true); loader.lazyRequireGetter(this, "showDoorhanger", "devtools/client/shared/doorhanger", true); loader.lazyRequireGetter(this, "viewSource", "devtools/client/shared/view-source"); @@ -347,27 +346,16 @@ WebConsole.prototype = { * @see webconsole.js::JSTerm * @type object */ get jsterm() { return this.ui ? this.ui.jsterm : null; }, /** - * The clear output button handler. - * @private - */ - _onClearButton() { - if (this.target.isLocalTab) { - gDevToolsBrowser.getDeveloperToolbar(this.browserWindow) - .resetErrorsCount(this.target.tab); - } - }, - - /** * Alias for the WebConsoleFrame.setFilterState() method. * @see webconsole.js::WebConsoleFrame.setFilterState() */ setFilterState() { this.ui && this.ui.setFilterState.apply(this.ui, arguments); }, /**