зеркало из https://github.com/mozilla/gecko-dev.git
Bug 921102 - 3 - Open/copy markup-view attribute links; r=bgrins
This part adds contextual menu items that become enabled when the user right clicks on an attribute that has a link. Depending on the nature of the link, a new tab will be opened or a node selected. The user can also choose to copy the link in the clipboard. --HG-- extra : rebase_source : 00128a076003ebac34096d81d9e326bee6631259 extra : histedit_source : c1d67e84e9d57280040e5831233df523fff904e2
This commit is contained in:
Родитель
10665e2af7
Коммит
3a5e7d4a71
|
@ -692,6 +692,9 @@ InspectorPanel.prototype = {
|
|||
unique.hidden = true;
|
||||
}
|
||||
|
||||
// Enable/Disable the link open/copy items.
|
||||
this._setupNodeLinkMenu();
|
||||
|
||||
// Enable the "edit HTML" item if the selection is an element and the root
|
||||
// actor has the appropriate trait (isOuterHTMLEditable)
|
||||
let editHTML = this.panelDoc.getElementById("node-menu-edithtml");
|
||||
|
@ -750,6 +753,56 @@ InspectorPanel.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Link menu items can be shown or hidden depending on the context and
|
||||
* selected node, and their labels can vary.
|
||||
*/
|
||||
_setupNodeLinkMenu: function InspectorPanel_setupNodeLinkMenu() {
|
||||
let linkSeparator = this.panelDoc.getElementById("node-menu-link-separator");
|
||||
let linkFollow = this.panelDoc.getElementById("node-menu-link-follow");
|
||||
let linkCopy = this.panelDoc.getElementById("node-menu-link-copy");
|
||||
|
||||
// Hide all by default.
|
||||
linkSeparator.setAttribute("hidden", "true");
|
||||
linkFollow.setAttribute("hidden", "true");
|
||||
linkCopy.setAttribute("hidden", "true");
|
||||
|
||||
// Get information about the right-clicked node.
|
||||
let popupNode = this.panelDoc.popupNode;
|
||||
if (!popupNode || !popupNode.classList.contains("link")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let type = popupNode.dataset.type;
|
||||
// Bug 1158822 will make "resource" type URLs open in devtools, but for now
|
||||
// they're considered like "uri".
|
||||
if (type === "uri" || type === "resource") {
|
||||
// First make sure the target can resolve relative URLs.
|
||||
this.target.actorHasMethod("inspector", "resolveRelativeURL").then(canResolve => {
|
||||
if (!canResolve) {
|
||||
return;
|
||||
}
|
||||
|
||||
linkSeparator.removeAttribute("hidden");
|
||||
|
||||
// Links can't be opened in new tabs in the browser toolbox.
|
||||
if (!this.target.chrome) {
|
||||
linkFollow.removeAttribute("hidden");
|
||||
linkFollow.setAttribute("label", this.strings.GetStringFromName(
|
||||
"inspector.menu.openUrlInNewTab.label"));
|
||||
}
|
||||
linkCopy.removeAttribute("hidden");
|
||||
linkCopy.setAttribute("label", this.strings.GetStringFromName(
|
||||
"inspector.menu.copyUrlToClipboard.label"));
|
||||
}, console.error);
|
||||
} else if (type === "idref") {
|
||||
linkSeparator.removeAttribute("hidden");
|
||||
linkFollow.removeAttribute("hidden");
|
||||
linkFollow.setAttribute("label", this.strings.formatStringFromName(
|
||||
"inspector.menu.selectElement.label", [popupNode.dataset.link], 1));
|
||||
}
|
||||
},
|
||||
|
||||
_initMarkup: function InspectorPanel_initMarkup() {
|
||||
let doc = this.panelDoc;
|
||||
|
||||
|
@ -1037,6 +1090,51 @@ InspectorPanel.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is here for the benefit of the node-menu-link-follow menu item
|
||||
* in the inspector contextual-menu. It's behavior depends on which node was
|
||||
* right-clicked when the menu was opened.
|
||||
*/
|
||||
followAttributeLink: function InspectorPanel_followLink(e) {
|
||||
let type = this.panelDoc.popupNode.dataset.type;
|
||||
let link = this.panelDoc.popupNode.dataset.link;
|
||||
|
||||
// "resource" type links should open appropriate tool instead (bug 1158822).
|
||||
if (type === "uri" || type === "resource") {
|
||||
// Open link in a new tab.
|
||||
// When the inspector menu was setup on click (see _setupNodeLinkMenu), we
|
||||
// already checked that resolveRelativeURL existed.
|
||||
this.inspector.resolveRelativeURL(link, this.selection.nodeFront).then(url => {
|
||||
let browserWin = this.target.tab.ownerDocument.defaultView;
|
||||
browserWin.openUILinkIn(url, "tab");
|
||||
}, console.error);
|
||||
} else if (type == "idref") {
|
||||
// Select the node in the same document.
|
||||
this.walker.document(this.selection.nodeFront).then(doc => {
|
||||
this.walker.querySelector(doc, "#" + CSS.escape(link)).then(node => {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
this.selection.setNodeFront(node);
|
||||
}, console.error);
|
||||
}, console.error);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is here for the benefit of the node-menu-link-copy menu item
|
||||
* in the inspector contextual-menu. It's behavior depends on which node was
|
||||
* right-clicked when the menu was opened.
|
||||
*/
|
||||
copyAttributeLink: function InspectorPanel_copyLink(e) {
|
||||
let link = this.panelDoc.popupNode.dataset.link;
|
||||
// When the inspector menu was setup on click (see _setupNodeLinkMenu), we
|
||||
// already checked that resolveRelativeURL existed.
|
||||
this.inspector.resolveRelativeURL(link, this.selection.nodeFront).then(url => {
|
||||
clipboardHelper.copyString(url);
|
||||
}, console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger a high-priority layout change for things that need to be
|
||||
* updated immediately
|
||||
|
|
|
@ -91,11 +91,15 @@
|
|||
label="&inspectorScrollNodeIntoView.label;"
|
||||
accesskey="&inspectorScrollNodeIntoView.accesskey;"
|
||||
oncommand="inspector.scrollNodeIntoView()"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="node-menu-delete"
|
||||
label="&inspectorHTMLDelete.label;"
|
||||
accesskey="&inspectorHTMLDelete.accesskey;"
|
||||
oncommand="inspector.deleteNode()"/>
|
||||
<menuseparator id="node-menu-link-separator"/>
|
||||
<menuitem id="node-menu-link-follow"
|
||||
oncommand="inspector.followAttributeLink()"/>
|
||||
<menuitem id="node-menu-link-copy"
|
||||
oncommand="inspector.copyAttributeLink()"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="node-menu-pseudo-hover"
|
||||
label=":hover" type="checkbox"
|
||||
|
|
|
@ -1815,16 +1815,6 @@ MarkupContainer.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// output-parser generated links handling.
|
||||
if (target.nodeName === "a") {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
let browserWin = this.markup._inspector.target
|
||||
.tab.ownerDocument.defaultView;
|
||||
browserWin.openUILinkIn(target.href, "tab");
|
||||
return;
|
||||
}
|
||||
|
||||
// target is the MarkupContainer itself.
|
||||
this._isMouseDown = true;
|
||||
this.hovered = false;
|
||||
|
|
|
@ -72,3 +72,36 @@ inspector.collapsePane=Collapse pane
|
|||
# that expands the right panel (rules, computed, box-model, etc...) in the
|
||||
# inspector UI.
|
||||
inspector.expandPane=Expand pane
|
||||
|
||||
# LOCALIZATION NOTE (inspector.menu.openUrlInNewTab.label): This is the label of
|
||||
# a menu item in the inspector contextual-menu that appears when the user right-
|
||||
# clicks on the attribute of a node in the inspector that is a URL, and that
|
||||
# allows to open that URL in a new tab.
|
||||
inspector.menu.openUrlInNewTab.label=Open Link in New Tab
|
||||
|
||||
# LOCALIZATION NOTE (inspector.menu.copyUrlToClipboard.label): This is the label
|
||||
# of a menu item in the inspector contextual-menu that appears when the user
|
||||
# right-clicks on the attribute of a node in the inspector that is a URL, and
|
||||
# that allows to copy that URL in the clipboard.
|
||||
inspector.menu.copyUrlToClipboard.label=Copy Link Address
|
||||
|
||||
# LOCALIZATION NOTE (inspector.menu.openFileInDebugger.label): This is the label
|
||||
# of a menu item in the inspector contextual-menu that appears when the user
|
||||
# right-clicks on the attribute of a node in the inspector that is a URL to a
|
||||
# javascript filename, and that allows to open the corresponding file in the
|
||||
# debugger.
|
||||
inspector.menu.openFileInDebugger.label=Open File in Debugger
|
||||
|
||||
# LOCALIZATION NOTE (inspector.menu.openFileInStyleEditor.label): This is the
|
||||
# label of a menu item in the inspector contextual-menu that appears when the
|
||||
# user right-clicks on the attribute of a node in the inspector that is a URL to
|
||||
# a css filename, and that allows to open the corresponding file in the style
|
||||
# editor.
|
||||
inspector.menu.openFileInStyleEditor.label=Open File in Style-Editor
|
||||
|
||||
# LOCALIZATION NOTE (inspector.menu.selectElement.label): This is the label of a
|
||||
# menu item in the inspector contextual-menu that appears when the user right-
|
||||
# clicks on the attribute of a node in the inspector that is the ID of another
|
||||
# element in the DOM (like with <label for="input-id">), and that allows to
|
||||
# select that element in the inspector.
|
||||
inspector.menu.selectElement.label=Select Element #%S
|
||||
|
|
|
@ -3471,6 +3471,30 @@ var InspectorActor = exports.InspectorActor = protocol.ActorClass({
|
|||
}, {
|
||||
request: {url: Arg(0), maxDim: Arg(1, "nullable:number")},
|
||||
response: RetVal("imageData")
|
||||
}),
|
||||
|
||||
/**
|
||||
* Resolve a URL to its absolute form, in the scope of a given content window.
|
||||
* @param {String} url.
|
||||
* @param {NodeActor} node If provided, the owner window of this node will be
|
||||
* used to resolve the URL. Otherwise, the top-level content window will be
|
||||
* used instead.
|
||||
* @return {String} url.
|
||||
*/
|
||||
resolveRelativeURL: method(function(url, node) {
|
||||
let document = isNodeDead(node)
|
||||
? this.window.document
|
||||
: nodeDocument(node.rawNode);
|
||||
|
||||
if (!document) {
|
||||
return url;
|
||||
} else {
|
||||
let baseURI = Services.io.newURI(document.location.href, null, null);
|
||||
return Services.io.newURI(url, null, baseURI).spec;
|
||||
}
|
||||
}, {
|
||||
request: {url: Arg(0, "string"), node: Arg(1, "nullable:domnode")},
|
||||
response: {value: RetVal("string")}
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ skip-if = buildapp == 'mulet'
|
|||
[test_inspector-release.html]
|
||||
[test_inspector-reload.html]
|
||||
[test_inspector-remove.html]
|
||||
[test_inspector-resolve-url.html]
|
||||
[test_inspector-retain.html]
|
||||
[test_inspector-scroll-into-view.html]
|
||||
[test_inspector-traversal.html]
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=921102
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 921102</title>
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
Components.utils.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
const {Promise: promise} = Components.utils.import("resource://gre/modules/Promise.jsm", {});
|
||||
const inspector = devtools.require("devtools/server/actors/inspector");
|
||||
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
var gInspector;
|
||||
var gDoc;
|
||||
|
||||
addTest(function() {
|
||||
let url = document.getElementById("inspectorContent").href;
|
||||
attachURL(url, function(err, client, tab, doc) {
|
||||
gDoc = doc;
|
||||
let {InspectorFront} = devtools.require("devtools/server/actors/inspector");
|
||||
gInspector = InspectorFront(client, tab);
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
|
||||
addTest(function() {
|
||||
info("Resolve a relative URL without providing a context node");
|
||||
gInspector.resolveRelativeURL("test.png?id=4#wow").then(url => {
|
||||
is(url, "chrome://mochitests/content/chrome/toolkit/devtools/server/tests/" +
|
||||
"mochitest/test.png?id=4#wow");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
|
||||
addTest(function() {
|
||||
info("Resolve an absolute URL without providing a context node");
|
||||
gInspector.resolveRelativeURL("chrome://mochitests/content/chrome/toolkit/" +
|
||||
"devtools/server/").then(url => {
|
||||
is(url, "chrome://mochitests/content/chrome/toolkit/devtools/server/");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
|
||||
addTest(function() {
|
||||
info("Resolve a relative URL providing a context node");
|
||||
let node = gDoc.querySelector(".big-horizontal");
|
||||
gInspector.resolveRelativeURL("test.png?id=4#wow", node).then(url => {
|
||||
is(url, "chrome://mochitests/content/chrome/toolkit/devtools/server/tests/" +
|
||||
"mochitest/test.png?id=4#wow");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
|
||||
addTest(function() {
|
||||
info("Resolve an absolute URL providing a context node");
|
||||
let node = gDoc.querySelector(".big-horizontal");
|
||||
gInspector.resolveRelativeURL("chrome://mochitests/content/chrome/toolkit/" +
|
||||
"devtools/server/", node).then(url => {
|
||||
is(url, "chrome://mochitests/content/chrome/toolkit/devtools/server/");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
|
||||
addTest(function() {
|
||||
gInspector = gDoc = null;
|
||||
runNextTest();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=921102">Mozilla Bug 921102</a>
|
||||
<a id="inspectorContent" target="_blank" href="inspector_getImageData.html">Test Document</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче