Bug 1569569 - Make HUDService specific to the browser console. r=nchevobbe
authorAlexandre Poirot <poirot.alex@gmail.com>
Wed, 31 Jul 2019 21:56:54 +0000
changeset 485758 3d68ad734f218fb45c01a88756289b237e39a81c
parent 485757 82d6d3db39180b3499b2a4a31ddce20691ea8b44
child 485759 89d98ab86ef6685128953747ed36d09a852de62e
push id36373
push userrmaries@mozilla.com
push dateFri, 02 Aug 2019 03:50:33 +0000
treeherdermozilla-central@22bda3da7ce3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnchevobbe
bugs1569569
milestone70.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
Bug 1569569 - Make HUDService specific to the browser console. r=nchevobbe Differential Revision: https://phabricator.services.mozilla.com/D40021
devtools/client/webconsole/browser-console.js
devtools/client/webconsole/hudservice.js
devtools/client/webconsole/panel.js
devtools/client/webconsole/test/mochitest/browser_webconsole_observer_notifications.js
devtools/client/webconsole/webconsole.js
devtools/docs/tools/console-panel.md
--- a/devtools/client/webconsole/browser-console.js
+++ b/devtools/client/webconsole/browser-console.js
@@ -3,16 +3,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var Services = require("Services");
 var WebConsole = require("devtools/client/webconsole/webconsole");
 
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
+loader.lazyRequireGetter(
+  this,
+  "HUDService",
+  "devtools/client/webconsole/hudservice",
+  true
+);
 
 /**
  * A BrowserConsole instance is an interactive console initialized *per target*
  * that displays console log data as well as provides an interactive terminal to
  * manipulate the target's document content.
  *
  * This object only wraps the iframe that holds the Browser Console UI. This is
  * meant to be an integration point between the Firefox UI and the Browser Console
@@ -35,17 +41,17 @@ class BrowserConsole extends WebConsole 
    */
   constructor(
     target,
     iframeWindow,
     chromeWindow,
     hudService,
     fissionSupport = false
   ) {
-    super(target, iframeWindow, chromeWindow, hudService, true, fissionSupport);
+    super(target, iframeWindow, chromeWindow, true, fissionSupport);
 
     this._telemetry = new Telemetry();
     this._bcInitializer = null;
     this._bcDestroyer = null;
   }
 
   /**
    * Initialize the Browser Console instance.
@@ -54,17 +60,17 @@ class BrowserConsole extends WebConsole 
    *         A promise for the initialization.
    */
   init() {
     if (this._bcInitializer) {
       return this._bcInitializer;
     }
 
     // Only add the shutdown observer if we've opened a Browser Console window.
-    ShutdownObserver.init(this.hudService);
+    ShutdownObserver.init();
 
     const window = this.iframeWindow;
 
     // Make sure that the closing of the Browser Console window destroys this
     // instance.
     window.addEventListener(
       "unload",
       () => {
@@ -94,45 +100,43 @@ class BrowserConsole extends WebConsole 
 
     this._bcDestroyer = (async () => {
       // browserconsole is not connected with a toolbox so we pass -1 as the
       // toolbox session id.
       this._telemetry.toolClosed("browserconsole", -1, this);
 
       await super.destroy();
       await this.target.destroy();
-      this.hudService._browserConsoleID = null;
       this.chromeWindow.close();
     })();
 
     return this._bcDestroyer;
   }
 }
 
 /**
  * The ShutdownObserver listens for app shutdown and saves the current state
  * of the Browser Console for session restore.
  */
 var ShutdownObserver = {
   _initialized: false,
 
-  init(hudService) {
+  init() {
     if (this._initialized) {
       return;
     }
 
     Services.obs.addObserver(this, "quit-application-granted");
 
     this._initialized = true;
-    this.hudService = hudService;
   },
 
   observe(message, topic) {
     if (topic == "quit-application-granted") {
-      this.hudService.storeBrowserConsoleSessionState();
+      HUDService.storeBrowserConsoleSessionState();
       this.uninit();
     }
   },
 
   uninit() {
     Services.obs.removeObserver(this, "quit-application-granted");
   },
 };
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -3,106 +3,75 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var Services = require("Services");
 loader.lazyRequireGetter(this, "Tools", "devtools/client/definitions", true);
 loader.lazyRequireGetter(
   this,
-  "gDevTools",
-  "devtools/client/framework/devtools",
-  true
-);
-loader.lazyRequireGetter(
-  this,
   "DebuggerClient",
   "devtools/shared/client/debugger-client",
   true
 );
 loader.lazyRequireGetter(this, "l10n", "devtools/client/webconsole/utils/l10n");
 loader.lazyRequireGetter(
   this,
   "BrowserConsole",
   "devtools/client/webconsole/browser-console"
 );
 
 const BC_WINDOW_FEATURES =
   "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
-function HUDService() {
-  this.consoles = new Map();
-}
+function HUDService() {}
 
 HUDService.prototype = {
-  _browserConsoleID: null,
+  _browserConsole: null,
   _browserConsoleInitializing: null,
 
-  /**
-   * Keeps a reference for each Web Console / Browser Console that is created.
-   * @type Map
-   */
-  consoles: null,
-
   _browerConsoleSessionState: false,
 
   storeBrowserConsoleSessionState() {
     this._browerConsoleSessionState = !!this.getBrowserConsole();
   },
 
   getBrowserConsoleSessionState() {
     return this._browerConsoleSessionState;
   },
 
   /**
-   * Get the current context, which is the main application window.
-   *
-   * @returns nsIDOMWindow
-   */
-  currentContext() {
-    return Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
-  },
-
-  /**
    * Open a Browser Console for the given target.
    *
    * @see devtools/framework/target.js for details about targets.
    *
    * @param object target
    *        The target that the browser console will connect to.
    * @param nsIDOMWindow iframeWindow
    *        The window where the browser console UI is already loaded.
    * @param Boolean fissionSupport
    * @return object
    *         A promise object for the opening of the new BrowserConsole instance.
    */
   async openBrowserConsole(target, win, fissionSupport = false) {
     const hud = new BrowserConsole(target, win, win, this, fissionSupport);
-    this._browserConsoleID = hud.hudId;
-    this.consoles.set(hud.hudId, hud);
+    this._browserConsole = hud;
+    hud.once("destroyed", () => {
+      this._browserConsole = null;
+    });
     await hud.init();
     return hud;
   },
 
   /**
-   * Returns the console instance for a given id.
-   *
-   * @param string id
-   * @returns Object
-   */
-  getHudReferenceById(id) {
-    return this.consoles.get(id);
-  },
-
-  /**
    * Toggle the Browser Console.
    */
   async toggleBrowserConsole() {
-    if (this._browserConsoleID) {
-      const hud = this.getHudReferenceById(this._browserConsoleID);
+    if (this._browserConsole) {
+      const hud = this._browserConsole;
       return hud.destroy();
     }
 
     if (this._browserConsoleInitializing) {
       return this._browserConsoleInitializing;
     }
 
     const fissionSupport = Services.prefs.getBoolPref(
@@ -196,13 +165,13 @@ HUDService.prototype = {
   /**
    * Get the Browser Console instance, if open.
    *
    * @return object|null
    *         A BrowserConsole instance or null if the Browser Console is not
    *         open.
    */
   getBrowserConsole() {
-    return this.getHudReferenceById(this._browserConsoleID);
+    return this._browserConsole;
   },
 };
 
 exports.HUDService = new HUDService();
--- a/devtools/client/webconsole/panel.js
+++ b/devtools/client/webconsole/panel.js
@@ -62,22 +62,17 @@ WebConsolePanel.prototype = {
           });
         });
       }
 
       const webConsoleUIWindow = iframe.contentWindow.wrappedJSObject;
       const chromeWindow = iframe.ownerDocument.defaultView;
 
       // Open the Web Console.
-      this.hud = new WebConsole(
-        this.target,
-        webConsoleUIWindow,
-        chromeWindow,
-        this
-      );
+      this.hud = new WebConsole(this.target, webConsoleUIWindow, chromeWindow);
       await this.hud.init();
 
       // Pipe 'reloaded' event from WebConsoleUI to WebConsolePanel.
       // These events are listened by the Toolbox.
       this.hud.ui.on("reloaded", () => {
         this.emit("reloaded");
       });
 
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_observer_notifications.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_observer_notifications.js
@@ -14,16 +14,18 @@ let destroyed = false;
 
 add_task(async function() {
   setupObserver();
   await openNewTabAndConsole(TEST_URI);
   await waitFor(() => created);
 
   await closeTabAndToolbox(gBrowser.selectedTab);
   await waitFor(() => destroyed);
+
+  ok("We received both created and destroyed events");
 });
 
 function setupObserver() {
   const observer = {
     QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
     observe: function observe(subject, topic) {
       subject = subject.QueryInterface(Ci.nsISupportsString);
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -29,16 +29,17 @@ loader.lazyRequireGetter(
   "devtools/client/shared/view-source"
 );
 loader.lazyRequireGetter(
   this,
   "openDocLink",
   "devtools/client/shared/link",
   true
 );
+const EventEmitter = require("devtools/shared/event-emitter");
 
 var gHudId = 0;
 const isMacOS = Services.appinfo.OS === "Darwin";
 
 /**
  * A WebConsole instance is an interactive console initialized *per target*
  * that displays console log data as well as provides an interactive terminal to
  * manipulate the target's document content.
@@ -51,43 +52,43 @@ class WebConsole {
   /*
    * @constructor
    * @param object target
    *        The target that the web console will connect to.
    * @param nsIDOMWindow iframeWindow
    *        The window where the web console UI is already loaded.
    * @param nsIDOMWindow chromeWindow
    *        The window of the web console owner.
-   * @param object hudService
-   *        The parent HUD Service
    * @param bool isBrowserConsole
    */
   constructor(
     target,
     iframeWindow,
     chromeWindow,
-    hudService,
     isBrowserConsole = false,
     fissionSupport = false
   ) {
     this.iframeWindow = iframeWindow;
     this.chromeWindow = chromeWindow;
     this.hudId = "hud_" + ++gHudId;
     this.target = target;
     this.browserWindow = this.chromeWindow.top;
-    this.hudService = hudService;
     this.isBrowserConsole = isBrowserConsole;
     this.fissionSupport = fissionSupport;
 
     const element = this.browserWindow.document.documentElement;
     if (element.getAttribute("windowtype") != gDevTools.chromeWindowType) {
-      this.browserWindow = this.hudService.currentContext();
+      this.browserWindow = Services.wm.getMostRecentWindow(
+        gDevTools.chromeWindowType
+      );
     }
     this.ui = new WebConsoleUI(this);
     this._destroyer = null;
+
+    EventEmitter.decorate(this);
   }
 
   /**
    * Getter for the window that can provide various utilities that the web
    * console makes use of, like opening links, managing popups, etc.  In
    * most cases, this will be |this.browserWindow|, but in some uses (such as
    * the Browser Toolbox), there is no browser window, so an alternative window
    * hosts the utilities there.
@@ -373,26 +374,27 @@ class WebConsole {
    *
    * @return object
    *         A promise object that is resolved once the Web Console is closed.
    */
   destroy() {
     if (!this.hudId) {
       return;
     }
-    this.hudService.consoles.delete(this.hudId);
 
     if (this.ui) {
       this.ui.destroy();
     }
 
     if (this._parserService) {
       this._parserService.stop();
       this._parserService = null;
     }
 
     const id = Utils.supportsString(this.hudId);
     Services.obs.notifyObservers(id, "web-console-destroyed");
     this.hudId = null;
+
+    this.emit("destroyed");
   }
 }
 
 module.exports = WebConsole;
--- a/devtools/docs/tools/console-panel.md
+++ b/devtools/docs/tools/console-panel.md
@@ -4,68 +4,68 @@ The Console panel is responsible for ren
 
 ## Architecture
 
 Internal architecture of the Console panel (the client side) is described
 on the following diagram.
 
 <figure class="hero">
   <pre class="diagram">
-┌───────────────────────────────────┐                         ┌───────────────────────────────────┐
-│             DevTools              │                         │          WebConsolePanel          │
-│  [client/framework/devtools.js]   │            ┌ ─ ─ ─ ─ ─ ─│            [panel.js]             │
-└───────────────────────────────────┘                         └───────────────────────────────────┘
-                  │                              │                              │
-                                                                                │
-        openBrowserConsole()             openWebConsole()                       │
-                                                                                │
-                  │                              │                              │
-                                                 ▼                              │
-                  │            ┌───────────────────────────────────┐            │
-                               │            HUDService             │            │
-                  └ ─ ─ ─ ─ ─ ▶│          [hudservice.js]          │          {hud}
-                               └───────────────────────────────────┘            │
-                                                 │                              │
-                                                 │                              │
-                                                 │                              │
-                                                 │                              │
-                               ┌─────────────{consoles}────────────┐            │
-                               │                                   │            │
-                               │                                   │            │
-                               │                                   │            │
-                               ▼ n                                 ▼ n          ▼ 1
-                  ┌────────────────────────┐                       ┌────────────────────────┐
-                  │     BrowserConsole     │                       │       WebConsole       │
-                  │  [browser-console.js]  │─ ─ ─ ─ ─extends─ ─ ─ ▶│    [webconsole.js]     │
-                  └────────────────────────┘                       └────────────────────────┘
-                                                                                │
-                                                                              {ui}
-                                                                                │
-                                                                                ▼ 1
-                                                                   ┌────────────────────────┐                     ┌─────────────────────────────────┐
-                                                                   │      WebConsoleUI      │                    1│    WebConsoleConnectionProxy    │
-                                                                   │   [webconsole-ui.js]   │─────{proxy}────────▶│[webconsole-connection-proxy.js] │
-                                                                   └────────────────────────┘                     └─────────────────────────────────┘
-                                                                                │                                                  │
-                                                                                │
-                                                                           {wrapper}                                               │
-                                                                                │
-                                                                                │                                                  │
-                                                                                ▼ 1
-                                                                   ┌────────────────────────┐                                      │
-                                                                   │   WebConsoleWrapper    │
-                                                                   │[webconsole-wrapper.js] │◀ ─ ─ ─ ─ ─ ─ calls methods from─ ─ ─ ┘
-                                                                   └────────────────────────┘
-                                                                                │
-                                                                            <renders>
-                                                                                │
-                                                                                ▼
-                                                                   ┌────────────────────────┐
-                                                                   │          App           │
-                                                                   └────────────────────────┘
+┌───────────────────────────────────┐          ┌───────────────────────────────────┐
+│             DevTools              │          │          WebConsolePanel          │
+│  [client/framework/devtools.js]   │          │            [panel.js]             │
+└───────────────────────────────────┘          └───────────────────────────────────┘
+                  │                                               │
+                                                                  │
+        openBrowserConsole() or                                   │
+        toggleBrowserConsole()                                    │
+                  │                                               │
+                  ▼                                               │
+┌───────────────────────────────────┐                             │
+│            HUDService             │                             │
+│          [hudservice.js]          │                           {hud}
+└───────────────────────────────────┘                             │
+                  │                                               │
+                  │                                               │
+                  │                                               │
+          {_browserConsole}                                       │
+                  │                                               │
+                  │                                               │
+                  │                                               │
+                  │                                               │
+                  ▼ 0..1                                          ▼ 1
+      ┌────────────────────────┐                       ┌────────────────────────┐
+      │     BrowserConsole     │                       │       WebConsole       │
+      │  [browser-console.js]  │─ ─ ─ ─ ─extends─ ─ ─ ▶│    [webconsole.js]     │
+      └────────────────────────┘                       └────────────────────────┘
+                                                                  │
+                                                                {ui}
+                                                                  │
+                                                                  ▼ 1
+                                                     ┌────────────────────────┐                     ┌─────────────────────────────────┐
+                                                     │      WebConsoleUI      │                    1│    WebConsoleConnectionProxy    │
+                                                     │   [webconsole-ui.js]   │─────{proxy}────────▶│[webconsole-connection-proxy.js] │
+                                                     └────────────────────────┘                     └─────────────────────────────────┘
+                                                                  │                                                  │
+                                                                  │
+                                                             {wrapper}                                               │
+                                                                  │
+                                                                  │                                                  │
+                                                                  ▼ 1
+                                                     ┌────────────────────────┐                                      │
+                                                     │   WebConsoleWrapper    │
+                                                     │[webconsole-wrapper.js] │◀ ─ ─ ─ ─ ─ ─ calls methods from─ ─ ─ ┘
+                                                     └────────────────────────┘
+                                                                  │
+                                                              <renders>
+                                                                  │
+                                                                  ▼
+                                                     ┌────────────────────────┐
+                                                     │          App           │
+                                                     └────────────────────────┘
     </pre>
   <figcaption>Elements between curly bracket on arrows represent the property name of the reference (for example, the WebConsolePanel as a `hud` property that is a reference to the WebConsole instance)</figcaption>
 </figure>
 
 ## Components
 
 The Console panel UI is built on top of [React](../frontend/react.md). It defines set of React components in `components` directory
 The React architecture is described on the following diagram.