Bug 1359855 - Inline jsonview main module to keep it working before user action. r=jdescottes,Honza draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 13 Jul 2017 15:33:38 +0200
changeset 614027 d0b3ba39a442b7ce15af35ecb40730a8a25efd33
parent 614026 d93261c33d30cdd94bd59d9de0fed26956c7d1a8
child 614028 8c04f02c311452f74b8c98ae0368ada30a0c13bf
push id69893
push userbmo:poirot.alex@gmail.com
push dateSun, 23 Jul 2017 20:50:47 +0000
reviewersjdescottes, Honza
bugs1359855
milestone56.0a1
Bug 1359855 - Inline jsonview main module to keep it working before user action. r=jdescottes,Honza MozReview-Commit-ID: 3COOvQtYn0E
devtools/client/devtools-startup.js
devtools/client/framework/devtools.js
devtools/client/jsonview/main.js
devtools/client/jsonview/moz.build
--- a/devtools/client/devtools-startup.js
+++ b/devtools/client/devtools-startup.js
@@ -188,16 +188,17 @@ DevToolsStartup.prototype = {
       this.hookWindow(window);
 
       if (devtoolsFlag) {
         this.handleDevToolsFlag(window);
         // This listener is called for all Firefox windows, but we want to execute
         // that command only once
         devtoolsFlag = false;
       }
+      JsonView.initialize();
     };
     Services.obs.addObserver(onWindowReady, "browser-delayed-startup-finished");
   },
 
   /**
    * Register listeners to all possible entry points for Developer Tools.
    * But instead of implementing the actual actions, defer to DevTools codebase.
    * In most cases, it only needs to call this.initDevTools which handles the rest.
@@ -522,10 +523,72 @@ DevToolsStartup.prototype = {
             "                     a TCP port or Unix domain socket path. Defaults to TCP port\n" +
             "                     6000. Use WebSocket protocol if ws: prefix is specified.\n",
   /* eslint-disable max-len */
 
   classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
 };
 
+/**
+ * Singleton object that represents the JSON View in-content tool.
+ * It has the same lifetime as the browser.
+ */
+const JsonView = {
+  initialized: false,
+
+  initialize: function () {
+    // Prevent loading the frame script multiple times if we call this more than once.
+    if (this.initialized) {
+      return;
+    }
+    this.initialized = true;
+
+    // Load JSON converter module. This converter is responsible
+    // for handling 'application/json' documents and converting
+    // them into a simple web-app that allows easy inspection
+    // of the JSON data.
+    Services.ppmm.loadProcessScript(
+      "resource://devtools/client/jsonview/converter-observer.js",
+      true);
+
+    // Register for messages coming from the child process.
+    // This is never removed as there is no particular need to unregister
+    // it during shutdown.
+    Services.ppmm.addMessageListener(
+      "devtools:jsonview:save", this.onSave);
+  },
+
+  // Message handlers for events from child processes
+
+  /**
+   * Save JSON to a file needs to be implemented here
+   * in the parent process.
+   */
+  onSave: function (message) {
+    let chrome = Services.wm.getMostRecentWindow("navigator:browser");
+    let browser = chrome.gBrowser.selectedBrowser;
+    if (message.data.url === null) {
+      // Save original contents
+      chrome.saveBrowser(browser, false, message.data.windowID);
+    } else {
+      // The following code emulates saveBrowser, but:
+      // - Uses the given blob URL containing the custom contents to save.
+      // - Obtains the file name from the URL of the document, not the blob.
+      let persistable = browser.QueryInterface(Ci.nsIFrameLoaderOwner)
+        .frameLoader.QueryInterface(Ci.nsIWebBrowserPersistable);
+      persistable.startPersistence(message.data.windowID, {
+        onDocumentReady(doc) {
+          let uri = chrome.makeURI(doc.documentURI, doc.characterSet);
+          let filename = chrome.getDefaultFileName(undefined, uri, doc, null);
+          chrome.internalSave(message.data.url, doc, filename, null, doc.contentType,
+            false, null, null, null, doc, false, null, undefined);
+        },
+        onError(status) {
+          throw new Error("JSON Viewer's onSave failed in startPersistence");
+        }
+      });
+    }
+  }
+};
+
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
   [DevToolsStartup]);
--- a/devtools/client/framework/devtools.js
+++ b/devtools/client/framework/devtools.js
@@ -19,17 +19,16 @@ loader.lazyImporter(this, "ScratchpadMan
 // Dependencies required for addon sdk compatibility layer.
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
 loader.lazyImporter(this, "BrowserToolboxProcess", "resource://devtools/client/framework/ToolboxProcess.jsm");
 
 const {defaultTools: DefaultTools, defaultThemes: DefaultThemes} =
   require("devtools/client/definitions");
 const EventEmitter = require("devtools/shared/event-emitter");
-const {JsonView} = require("devtools/client/jsonview/main");
 const AboutDevTools = require("devtools/client/framework/about-devtools-toolbox");
 const {Task} = require("devtools/shared/task");
 const {getTheme, setTheme, addThemeObserver, removeThemeObserver} =
   require("devtools/client/shared/theme");
 
 const FORBIDDEN_IDS = new Set(["toolbox", ""]);
 const MAX_ORDINAL = 99;
 
@@ -39,19 +38,16 @@ const MAX_ORDINAL = 99;
  */
 function DevTools() {
   this._tools = new Map();     // Map<toolId, tool>
   this._themes = new Map();    // Map<themeId, theme>
   this._toolboxes = new Map(); // Map<target, toolbox>
   // List of toolboxes that are still in process of creation
   this._creatingToolboxes = new Map(); // Map<target, toolbox Promise>
 
-  // JSON Viewer for 'application/json' documents.
-  JsonView.initialize();
-
   AboutDevTools.register();
 
   EventEmitter.decorate(this);
 
   // Listen for changes to the theme pref.
   this._onThemeChanged = this._onThemeChanged.bind(this);
   addThemeObserver(this._onThemeChanged);
 
@@ -639,18 +635,16 @@ DevTools.prototype = {
       }
       AboutDevTools.unregister();
     }
 
     for (let [key, ] of this.getToolDefinitionMap()) {
       this.unregisterTool(key, true);
     }
 
-    JsonView.destroy();
-
     gDevTools.unregisterDefaults();
 
     removeThemeObserver(this._onThemeChanged);
 
     // Do not unregister devtools from the DevToolsShim if the destroy is caused by an
     // application shutdown. For instance SessionStore needs to save the Scratchpad
     // manager state on shutdown.
     if (!shuttingDown) {
deleted file mode 100644
--- a/devtools/client/jsonview/main.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* 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 { Ci } = require("chrome");
-const Services = require("Services");
-
-/**
- * Singleton object that represents the JSON View in-content tool.
- * It has the same lifetime as the browser. Initialization done by
- * DevTools() object from devtools/client/framework/devtools.js
- */
-var JsonView = {
-  initialize: function () {
-    // Load JSON converter module. This converter is responsible
-    // for handling 'application/json' documents and converting
-    // them into a simple web-app that allows easy inspection
-    // of the JSON data.
-    Services.ppmm.loadProcessScript(
-      "resource://devtools/client/jsonview/converter-observer.js",
-      true);
-
-    // Register for messages coming from the child process.
-    Services.ppmm.addMessageListener(
-      "devtools:jsonview:save", this.onSave);
-  },
-
-  destroy: function () {
-    Services.ppmm.removeMessageListener(
-      "devtools:jsonview:save", this.onSave);
-  },
-
-  // Message handlers for events from child processes
-
-  /**
-   * Save JSON to a file needs to be implemented here
-   * in the parent process.
-   */
-  onSave: function (message) {
-    let chrome = Services.wm.getMostRecentWindow("navigator:browser");
-    let browser = chrome.gBrowser.selectedBrowser;
-    if (message.data.url === null) {
-      // Save original contents
-      chrome.saveBrowser(browser, false, message.data.windowID);
-    } else {
-      // The following code emulates saveBrowser, but:
-      // - Uses the given blob URL containing the custom contents to save.
-      // - Obtains the file name from the URL of the document, not the blob.
-      let persistable = browser.QueryInterface(Ci.nsIFrameLoaderOwner)
-        .frameLoader.QueryInterface(Ci.nsIWebBrowserPersistable);
-      persistable.startPersistence(message.data.windowID, {
-        onDocumentReady(doc) {
-          let uri = chrome.makeURI(doc.documentURI, doc.characterSet);
-          let filename = chrome.getDefaultFileName(undefined, uri, doc, null);
-          chrome.internalSave(message.data.url, doc, filename, null, doc.contentType,
-            false, null, null, null, doc, false, null, undefined);
-        },
-        onError(status) {
-          throw new Error("JSON Viewer's onSave failed in startPersistence");
-        }
-      });
-    }
-  }
-};
-
-// Exports from this module
-module.exports.JsonView = JsonView;
--- a/devtools/client/jsonview/moz.build
+++ b/devtools/client/jsonview/moz.build
@@ -9,16 +9,15 @@ DIRS += [
     'css',
     'lib'
 ]
 
 DevToolsModules(
     'converter-child.js',
     'converter-observer.js',
     'json-viewer.js',
-    'main.js',
     'viewer-config.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Developer Tools: JSON Viewer')