Bug 1356415 - get CSS selector in content for contextmenu to fix devtools CPOW;r=mixedpuppy

MozReview-Commit-ID: 3TYaYcS1W0h

--HG--
extra : rebase_source : c3762ff15bbb3e53fa4ec882bd0e2eac797cf131
This commit is contained in:
Julian Descottes 2017-04-26 19:41:19 +02:00
parent a05d6a925c
commit 59ac4a80a5
3 changed files with 47 additions and 14 deletions

View File

@ -51,6 +51,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
"resource:///modules/Feeds.jsm");
XPCOMUtils.defineLazyGetter(this, "findCssSelector", () => {
let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
let { findCssSelector } = require("devtools/shared/inspector/css-logic");
return findCssSelector;
});
Cu.importGlobalProperties(["URL"]);
@ -164,6 +169,7 @@ var handleContentContextMenu = function(event) {
let loadContext = docShell.QueryInterface(Ci.nsILoadContext);
let userContextId = loadContext.originAttributes.userContextId;
let popupNodeSelectors = getNodeSelectors(event.target);
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
let editFlags = SpellCheckHelper.isEditable(event.target, content);
@ -183,13 +189,18 @@ var handleContentContextMenu = function(event) {
let customMenuItems = PageMenuChild.build(event.target);
let principal = doc.nodePrincipal;
sendRpcMessage("contextmenu",
{ editFlags, spellInfo, customMenuItems, addonInfo,
principal, docLocation, charSet, baseURI, referrer,
referrerPolicy, contentType, contentDisposition,
frameOuterWindowID, selectionInfo, disableSetDesktopBg,
loginFillInfo, parentAllowsMixedContent, userContextId },
{ event, popupNode: event.target });
loginFillInfo, parentAllowsMixedContent, userContextId,
popupNodeSelectors,
}, {
event,
popupNode: event.target,
});
} else {
// Break out to the parent window and pass the add-on info along
let browser = docShell.chromeEventHandler;
@ -198,6 +209,7 @@ var handleContentContextMenu = function(event) {
isRemote: false,
event,
popupNode: event.target,
popupNodeSelectors,
browser,
addonInfo,
documentURIObject: doc.documentURIObject,
@ -245,6 +257,28 @@ const PREF_SSL_IMPACT = PREF_SSL_IMPACT_ROOTS.reduce((prefs, root) => {
return prefs.concat(Services.prefs.getChildList(root));
}, []);
/**
* Retrieve the array of CSS selectors corresponding to the provided node. The first item
* of the array is the selector of the node in its owner document. Additional items are
* used if the node is inside a frame, each representing the CSS selector for finding the
* frame element in its parent document.
*
* This format is expected by DevTools in order to handle the Inspect Node context menu
* item.
*
* @param {Node}
* The node for which the CSS selectors should be computed
* @return {Array} array of css selectors (strings).
*/
function getNodeSelectors(node) {
let selectors = [];
while (node) {
selectors.push(findCssSelector(node));
node = node.ownerGlobal.frameElement;
}
return selectors;
}
function getSerializedSecurityInfo(docShell) {
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]

View File

@ -33,6 +33,7 @@ function openContextMenu(aMessage) {
gContextMenuContentData = { isRemote: true,
event: aMessage.objects.event,
popupNode: aMessage.objects.popupNode,
popupNodeSelectors: data.popupNodeSelectors,
browser,
editFlags: data.editFlags,
spellInfo,
@ -620,7 +621,7 @@ nsContextMenu.prototype = {
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.target);
return gDevToolsBrowser.inspectNode(gBrowser.selectedTab, this.targetSelectors);
},
/**
@ -702,6 +703,12 @@ nsContextMenu.prototype = {
// Remember the node that was clicked.
this.target = aNode;
// Remember the CSS selectors corresponding to clicked node. gContextMenuContentData
// can be null if the menu was triggered by tests in which case use an empty array.
this.targetSelectors = gContextMenuContentData
? gContextMenuContentData.popupNodeSelectors
: [];
let ownerDoc = this.target.ownerDocument;
this.ownerDoc = ownerDoc;

View File

@ -24,7 +24,6 @@ loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", t
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
loader.lazyRequireGetter(this, "BrowserMenus", "devtools/client/framework/browser-menus");
loader.lazyRequireGetter(this, "findCssSelector", "devtools/shared/inspector/css-logic", true);
loader.lazyRequireGetter(this, "appendStyleSheet", "devtools/client/shared/stylesheet-utils", true);
loader.lazyImporter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm");
@ -307,16 +306,9 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
}
},
async inspectNode(tab, node) {
async inspectNode(tab, nodeSelectors) {
let target = TargetFactory.forTab(tab);
// Generate a cross iframes query selector
let selectors = [];
while (node) {
selectors.push(findCssSelector(node));
node = node.ownerDocument.defaultView.frameElement;
}
let toolbox = await gDevTools.showToolbox(target, "inspector");
let inspector = toolbox.getCurrentPanel();
@ -326,12 +318,12 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
// Evaluate the cross iframes query selectors
async function querySelectors(nodeFront) {
let selector = selectors.pop();
let selector = nodeSelectors.pop();
if (!selector) {
return nodeFront;
}
nodeFront = await inspector.walker.querySelector(nodeFront, selector);
if (selectors.length > 0) {
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];