Bug 339725 - SVG <a> with xlink:href don't show HTML link features in context menu, r?jaws,longsonr
MozReview-Commit-ID: Kg9dONwXCrB
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -876,24 +876,27 @@ nsContextMenu.prototype = {
*/
_setTargetForNodesWithChildren(editFlags, rangeParent, rangeOffset) {
// Second, bubble out, looking for items of interest that can have childen.
// Always pick the innermost link, background image, etc.
var elem = this.target;
while (elem) {
if (elem.nodeType == Node.ELEMENT_NODE) {
// Link?
+ const XLINKNS = "http://www.w3.org/1999/xlink";
if (!this.onLink &&
// Be consistent with what hrefAndLinkNodeForClickEvent
// does in browser.js
(this._isXULTextLinkLabel(elem) ||
(elem instanceof HTMLAnchorElement && elem.href) ||
+ (elem instanceof SVGAElement &&
+ (elem.href || elem.hasAttributeNS(XLINKNS, "href"))) ||
(elem instanceof HTMLAreaElement && elem.href) ||
elem instanceof HTMLLinkElement ||
- elem.getAttributeNS("http://www.w3.org/1999/xlink", "type") == "simple")) {
+ elem.getAttributeNS(XLINKNS, "type") == "simple")) {
// Target is a link or a descendant of a link.
this.onLink = true;
// Remember corresponding element.
this.link = elem;
this.linkURL = this.getLinkURL();
this.linkURI = this.getLinkURI();
@@ -1670,18 +1673,23 @@ nsContextMenu.prototype = {
// Voila!
return node;
},
// Generate fully qualified URL for clicked-on link.
getLinkURL() {
var href = this.link.href;
- if (href)
+ if (href) {
+ // Handle SVG links:
+ if (typeof href == "object" && href.animVal) {
+ return href.animVal;
+ }
return href;
+ }
href = this.link.getAttribute("href") ||
this.link.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (!href || !href.match(/\S/)) {
// Without this we try to save as the current doc,
// for example, HTML case also throws if empty
throw "Empty href";
--- a/browser/base/content/test/general/browser_contextmenu.js
+++ b/browser/base/content/test/general/browser_contextmenu.js
@@ -973,16 +973,69 @@ add_task(async function test_link_sendli
async onContextMenuShown() {
await openMenuItemSubmenu("context-sendlinktodevice");
}
});
restoreRemoteClients(oldGetter);
});
+add_task(async function test_svg_link() {
+ await test_contextmenu("#svg-with-link > a",
+ ["context-openlinkintab", true,
+ ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
+ // We need a blank entry here because the containers submenu is
+ // dynamically generated with no ids.
+ ...(hasContainers ? ["", null] : []),
+ "context-openlink", true,
+ "context-openlinkprivate", true,
+ "---", null,
+ "context-bookmarklink", true,
+ "context-savelink", true,
+ ...(hasPocket ? ["context-savelinktopocket", true] : []),
+ "context-copylink", true,
+ "context-searchselect", true
+ ]
+ );
+
+ await test_contextmenu("#svg-with-link2 > a",
+ ["context-openlinkintab", true,
+ ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
+ // We need a blank entry here because the containers submenu is
+ // dynamically generated with no ids.
+ ...(hasContainers ? ["", null] : []),
+ "context-openlink", true,
+ "context-openlinkprivate", true,
+ "---", null,
+ "context-bookmarklink", true,
+ "context-savelink", true,
+ ...(hasPocket ? ["context-savelinktopocket", true] : []),
+ "context-copylink", true,
+ "context-searchselect", true
+ ]
+ );
+
+ await test_contextmenu("#svg-with-link3 > a",
+ ["context-openlinkintab", true,
+ ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
+ // We need a blank entry here because the containers submenu is
+ // dynamically generated with no ids.
+ ...(hasContainers ? ["", null] : []),
+ "context-openlink", true,
+ "context-openlinkprivate", true,
+ "---", null,
+ "context-bookmarklink", true,
+ "context-savelink", true,
+ ...(hasPocket ? ["context-savelinktopocket", true] : []),
+ "context-copylink", true,
+ "context-searchselect", true
+ ]
+ );
+});
+
add_task(async function test_cleanup_html() {
gBrowser.removeCurrentTab();
});
/**
* Selects the text of the element that matches the provided `selector`
*
* @param {String} selector
--- a/browser/base/content/test/general/subtst_contextmenu.html
+++ b/browser/base/content/test/general/subtst_contextmenu.html
@@ -64,10 +64,13 @@ Browser context menu subtest.
<div id="test-select-text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>
<div id="test-select-text-link">http://mozilla.com</div>
<a id="test-image-link" href="#"><img src="ctxmenu-image.png"></a>
<input id="test-select-input-text" type="text" value="input">
<input id="test-select-input-text-type-password" type="password" value="password">
<embed id="test-plugin" style="width: 200px; height: 200px;" type="application/x-test"></embed>
<img id="test-longdesc" src="ctxmenu-image.png" longdesc="http://www.mozilla.org"></embed>
<iframe id="test-srcdoc" width="98" height="98" srcdoc="Hello World" style="border: 1px solid black"></iframe>
+<svg id="svg-with-link" width=10 height=10><a xlink:href="http://example.com/"><circle cx="50%" cy="50%" r="50%" fill="blue"/></a></svg>
+<svg id="svg-with-link2" width=10 height=10><a xlink:href="http://example.com/" xlink:type="simple"><circle cx="50%" cy="50%" r="50%" fill="green"/></a></svg>
+<svg id="svg-with-link3" width=10 height=10><a href="http://example.com/"><circle cx="50%" cy="50%" r="50%" fill="red"/></a></svg>
</body>
</html>