Bug 714789 - Don't show "Open in new tab" for non-openable links [r=mfinkle]
authorMatt Brubeck <mbrubeck@mozilla.com>
Fri, 06 Jan 2012 11:44:33 -0800
changeset 85188 909cbc7fa325649c25ec4c3e481012e173116ef2
parent 85187 555ca2958f6f146ac075496ec7a1dfe9f0238781
child 85189 5cabc9128f1eef2f3a96a10f2136c2d22d4f42dd
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs714789
milestone12.0a1
Bug 714789 - Don't show "Open in new tab" for non-openable links [r=mfinkle]
mobile/android/chrome/content/browser.js
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -57,16 +57,18 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyServiceGetter(this, "Haptic",
   "@mozilla.org/widget/hapticfeedback;1", "nsIHapticFeedback");
 
 XPCOMUtils.defineLazyServiceGetter(this, "DOMUtils",
   "@mozilla.org/inspector/dom-utils;1", "inIDOMUtils");
 
 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.
 const kPanDeceleration = 0.999;
 
 // The number of ms to consider events over for a swipe gesture.
 const kSwipeLength = 500;
 
@@ -917,29 +919,28 @@ 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 });
 
                  let newtabStrings = Strings.browser.GetStringFromName("newtabpopup.opened");
                  let label = PluralForm.get(1, newtabStrings).replace("#1", 1);
                  NativeWindow.toast.show(label, "short");
                });
@@ -1002,16 +1003,42 @@ var NativeWindow = {
         matches: function(aElt) {
           if (aElt.mozMatchesSelector)
             return aElt.mozMatchesSelector(aSelector);
           return false;
         }
       }
     },
 
+    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);
       if (!rootElement)
         rootElement = ElementTouchHelper.anyElementFromPoint(BrowserApp.selectedBrowser.contentWindow, aX, aY)
 
       this.menuitems = null;
       let element = rootElement;
@@ -1024,17 +1051,17 @@ var NativeWindow = {
           // it is not already in the list
           if ((!this.menuitems || !this.menuitems[item.id]) && item.matches(element)) {
             if (!this.menuitems)
               this.menuitems = {};
             this.menuitems[item.id] = item;
           }
         }
 
-        if (this.linkContext.matches(element) || this.textContext.matches(element))
+        if (this.linkOpenableContext.matches(element) || this.textContext.matches(element))
           break;
         element = element.parentNode;
       }
 
       // only send the contextmenu event to content if we are planning to show a context menu (i.e. not on every long tap)
       if (this.menuitems) {
         BrowserEventHandler.blockClick = true;
         let event = rootElement.ownerDocument.createEvent("MouseEvent");
@@ -1119,17 +1146,17 @@ var NativeWindow = {
 
       href = aLink.getAttributeNS(kXLinkNamespace, "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";
       }
 
-      return Util.makeURLAbsolute(aLink.baseURI, href);
+      return this.makeURLAbsolute(aLink.baseURI, href);
     }
   }
 };
 
 
 function nsBrowserAccess() {
 }