diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 51298a13e125..6c297651e789 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -62,6 +62,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "DOMUtils", const kStateActive = 0x00000001; // :active pseudoclass for elements +const kXLinkNamespace = "http://www.w3.org/1999/xlink"; + // TODO: Take into account ppi in these units? // The ratio of velocity that is retained every ms. @@ -922,19 +924,18 @@ var NativeWindow = { contextmenus: { items: {}, // a list of context menu items that we may show textContext: null, // saved selector for text input areas - linkContext: null, // saved selector for links + _contextId: 0, // id to assign to new context menu items if they are added init: function() { this.textContext = this.SelectorContext("input[type='text'],input[type='password'],textarea"); - this.linkContext = this.SelectorContext("a:not([href='']),area:not([href='']),link"); this.imageContext = this.SelectorContext("img"); Services.obs.addObserver(this, "Gesture:LongPress", false); // TODO: These should eventually move into more appropriate classes this.add(Strings.browser.GetStringFromName("contextmenu.openInNewTab"), - this.linkContext, + this.linkOpenableContext, function(aTarget) { let url = NativeWindow.contextmenus._getLinkURL(aTarget); BrowserApp.addTab(url, { selected: false, parentId: BrowserApp.selectedTab.id }); @@ -1007,6 +1008,32 @@ var NativeWindow = { } }, + linkOpenableContext: { + matches: function linkOpenableContextMatches(aElement) { + if (aElement.nodeType == Ci.nsIDOMNode.ELEMENT_NODE && + ((aElement instanceof Ci.nsIDOMHTMLAnchorElement && aElement.href) || + (aElement instanceof Ci.nsIDOMHTMLAreaElement && aElement.href) || + aElement instanceof Ci.nsIDOMHTMLLinkElement || + aElement.getAttributeNS(kXLinkNamespace, "type") == "simple")) { + let uri; + try { + let url = NativeWindow.contextmenus._getLinkURL(aElement); + uri = Services.io.newURI(url, null, null); + } catch (e) { + return false; + } + + let scheme = uri.scheme; + if (!scheme) + return false; + + let dontOpen = /^(mailto|javascript|news|snews)$/; + return (scheme && !dontOpen.test(scheme)); + } + return false; + } + }, + _sendToContent: function(aX, aY) { // initially we look for nearby clickable elements. If we don't find one we fall back to using whatever this click was on let rootElement = ElementTouchHelper.elementFromPoint(BrowserApp.selectedBrowser.contentWindow, aX, aY); @@ -1029,7 +1056,7 @@ var NativeWindow = { } } - if (this.linkContext.matches(element) || this.textContext.matches(element)) + if (this.linkOpenableContext.matches(element) || this.textContext.matches(element)) break; element = element.parentNode; } @@ -1124,7 +1151,7 @@ var NativeWindow = { throw "Empty href"; } - return Util.makeURLAbsolute(aLink.baseURI, href); + return this.makeURLAbsolute(aLink.baseURI, href); } } };