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
--- 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);