Bug 1372520 - use DevToolsShim to inspectNode in nContextMenu;r=mixedpuppy,bgrins draft
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 14 Jun 2017 17:52:50 +0200
changeset 597747 915dc2c3e499475104db12737cf506d3557b1f98
parent 597746 7b000741a7c7ebb0b26bea78b643787a3fccd541
child 634306 09ab6b50efdaea7e4810bf59703d1c10bfde016c
push id65014
push userjdescottes@mozilla.com
push dateTue, 20 Jun 2017 22:19:49 +0000
reviewersmixedpuppy, bgrins
bugs1372520
milestone56.0a1
Bug 1372520 - use DevToolsShim to inspectNode in nContextMenu;r=mixedpuppy,bgrins As devtools become optional, nsContextMenu needs to check if devtools are installed before displaying the devtools-related menu entries. Rather than loading devtools classing and calling APIs, use APIs provided by the DevToolsShim, that will stay in mozilla-central. MozReview-Commit-ID: CxqabTjhckC
browser/base/content/nsContextMenu.js
devtools/client/framework/devtools-browser.js
devtools/client/framework/devtools.js
devtools/shim/DevToolsShim.jsm
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -13,16 +13,18 @@ Components.utils.import("resource://gre/
 
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
   "resource://gre/modules/LoginHelper.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
   "resource://gre/modules/WebNavigationFrames.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
   "resource://gre/modules/ContextualIdentityService.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "DevToolsShim",
+  "chrome://devtools-shim/content/DevToolsShim.jsm");
 
 var gContextMenuContentData = null;
 
 function openContextMenu(aMessage) {
   let data = aMessage.data;
   let browser = aMessage.target;
 
   let spellInfo = data.spellInfo;
@@ -295,17 +297,21 @@ nsContextMenu.prototype = {
                   this.isContentSelected);
     this.showItem("context-viewpartialsource-mathml",
                   this.onMathML && !this.isContentSelected);
 
     var shouldShow = !(this.isContentSelected ||
                        this.onImage || this.onCanvas ||
                        this.onVideo || this.onAudio ||
                        this.onLink || this.onTextInput);
-    var showInspect = this.inTabBrowser && gPrefService.getBoolPref("devtools.inspector.enabled");
+
+    var showInspect = DevToolsShim.isInstalled() &&
+                      this.inTabBrowser &&
+                      gPrefService.getBoolPref("devtools.inspector.enabled", false);
+
     this.showItem("context-viewsource", shouldShow);
     this.showItem("context-viewinfo", shouldShow);
     // The page info is broken for WebExtension popups, as the browser is
     // destroyed when the popup is closed.
     this.setItemAttr("context-viewinfo", "disabled", this.webExtBrowserType === "popup");
     this.showItem("inspect-separator", showInspect);
     this.showItem("context-inspect", showInspect);
 
@@ -622,20 +628,17 @@ nsContextMenu.prototype = {
     gSync.initPageContextMenu(this);
   },
 
   openPasswordManager() {
     LoginHelper.openPasswordManager(window, gContextMenuContentData.documentURIObject.host);
   },
 
   inspectNode() {
-    let gBrowser = this.browser.ownerGlobal.gBrowser;
-    let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
-    let { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
-    return gDevToolsBrowser.inspectNode(gBrowser.selectedTab, this.targetSelectors);
+    return DevToolsShim.inspectNode(gBrowser.selectedTab, this.targetSelectors);
   },
 
   /**
    * Set various context menu attributes based on the state of the world.
    * Note: If the context menu is on a remote process the supplied parameters
    * will be overwritten with data from gContextMenuContentData.
    *
    * @param {Object} aNode The node that this menu is being opened on.
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -302,51 +302,16 @@ var gDevToolsBrowser = exports.gDevTools
     let win = Services.wm.getMostRecentWindow("devtools:webide");
     if (win) {
       win.focus();
     } else {
       Services.ww.openWindow(null, "chrome://webide/content/", "webide", "chrome,centerscreen,resizable", null);
     }
   },
 
-  async inspectNode(tab, nodeSelectors) {
-    let target = TargetFactory.forTab(tab);
-
-    let toolbox = await gDevTools.showToolbox(target, "inspector");
-    let inspector = toolbox.getCurrentPanel();
-
-    // new-node-front tells us when the node has been selected, whether the
-    // browser is remote or not.
-    let onNewNode = inspector.selection.once("new-node-front");
-
-    // Evaluate the cross iframes query selectors
-    async function querySelectors(nodeFront) {
-      let selector = nodeSelectors.pop();
-      if (!selector) {
-        return nodeFront;
-      }
-      nodeFront = await inspector.walker.querySelector(nodeFront, selector);
-      if (nodeSelectors.length > 0) {
-        let { nodes } = await inspector.walker.children(nodeFront);
-        // This is the NodeFront for the document node inside the iframe
-        nodeFront = nodes[0];
-      }
-      return querySelectors(nodeFront);
-    }
-    let nodeFront = await inspector.walker.getRootNode();
-    nodeFront = await querySelectors(nodeFront);
-    // Select the final node
-    inspector.selection.setNodeFront(nodeFront, "browser-context-menu");
-
-    await onNewNode;
-    // Now that the node has been selected, wait until the inspector is
-    // fully updated.
-    await inspector.once("inspector-updated");
-  },
-
   _getContentProcessTarget(processId) {
     // Create a DebuggerServer in order to connect locally to it
     if (!DebuggerServer.initialized) {
       DebuggerServer.init();
       DebuggerServer.addBrowserActors();
     }
     DebuggerServer.allowChromeProcess = true;
 
--- a/devtools/client/framework/devtools.js
+++ b/devtools/client/framework/devtools.js
@@ -570,16 +570,63 @@ DevTools.prototype = {
    *
    * Create a BrowserToolbox process linked to the provided addon id.
    */
   initBrowserToolboxProcessForAddon: function (addonID) {
     BrowserToolboxProcess.init({ addonID });
   },
 
   /**
+   * Called from the DevToolsShim, used by nsContextMenu.js.
+   *
+   * @param {XULTab} tab
+   *        The browser tab on which inspect node was used.
+   * @param {Array} selectors
+   *        An array of CSS selectors to find the target node. Several selectors can be
+   *        needed if the element is nested in frames and not directly in the root
+   *        document.
+   * @return {Promise} a promise that resolves when the node is selected in the inspector
+   *         markup view.
+   */
+  async inspectNode(tab, nodeSelectors) {
+    let target = TargetFactory.forTab(tab);
+
+    let toolbox = await gDevTools.showToolbox(target, "inspector");
+    let inspector = toolbox.getCurrentPanel();
+
+    // new-node-front tells us when the node has been selected, whether the
+    // browser is remote or not.
+    let onNewNode = inspector.selection.once("new-node-front");
+
+    // Evaluate the cross iframes query selectors
+    async function querySelectors(nodeFront) {
+      let selector = nodeSelectors.pop();
+      if (!selector) {
+        return nodeFront;
+      }
+      nodeFront = await inspector.walker.querySelector(nodeFront, selector);
+      if (nodeSelectors.length > 0) {
+        let { nodes } = await inspector.walker.children(nodeFront);
+        // This is the NodeFront for the document node inside the iframe
+        nodeFront = nodes[0];
+      }
+      return querySelectors(nodeFront);
+    }
+    let nodeFront = await inspector.walker.getRootNode();
+    nodeFront = await querySelectors(nodeFront);
+    // Select the final node
+    inspector.selection.setNodeFront(nodeFront, "browser-context-menu");
+
+    await onNewNode;
+    // Now that the node has been selected, wait until the inspector is
+    // fully updated.
+    await inspector.once("inspector-updated");
+  },
+
+  /**
    * Either the SDK Loader has been destroyed by the add-on contribution
    * workflow, or firefox is shutting down.
 
    * @param {boolean} shuttingDown
    *        True if firefox is currently shutting down. We may prevent doing
    *        some cleanups to speed it up. Otherwise everything need to be
    *        cleaned up in order to be able to load devtools again.
    */
--- a/devtools/shim/DevToolsShim.jsm
+++ b/devtools/shim/DevToolsShim.jsm
@@ -172,16 +172,36 @@ this.DevToolsShim = {
    */
   restoreScratchpadSession: function (scratchpads) {
     if (!this.isInstalled()) {
       return;
     }
     this.gDevTools.restoreScratchpadSession(scratchpads);
   },
 
+  /**
+   * Called from nsContextMenu.js in mozilla-central when using the Inspect Element
+   * context menu item.
+   *
+   * @param {XULTab} tab
+   *        The browser tab on which inspect node was used.
+   * @param {Array} selectors
+   *        An array of CSS selectors to find the target node. Several selectors can be
+   *        needed if the element is nested in frames and not directly in the root
+   *        document.
+   * @return {Promise} a promise that resolves when the node is selected in the inspector
+   *         markup view or that resolves immediately if DevTools are not installed.
+   */
+  inspectNode: function (tab, selectors) {
+    if (!this.isInstalled()) {
+      return Promise.resolve();
+    }
+    return this.gDevTools.inspectNode(tab, selectors);
+  },
+
   _onDevToolsRegistered: function () {
     // Register all pending event listeners on the real gDevTools object.
     for (let [event, listener] of this.listeners) {
       this.gDevTools.on(event, listener);
     }
 
     for (let tool of this.tools) {
       this.gDevTools.registerTool(tool);