Bug 708048 - Use highlight element for context menu title. r=kats
authorWes Johnston <wjohnston@mozilla.com>
Thu, 18 Oct 2012 15:02:37 -0700
changeset 110846 1adde03021f9b5842a8d702f24d5be2f7747c2fd
parent 110845 a5dbfe84e1783b3208a86f45235ff49a6e50b915
child 110847 52b59d7cff7c7fe85e4664a163ee3cd6df17e374
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewerskats
bugs708048
milestone19.0a1
Bug 708048 - Use highlight element for context menu title. r=kats
mobile/android/chrome/content/browser.js
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1421,71 +1421,96 @@ var NativeWindow = {
           // The image must be loaded to allow saving
           let request = aElement.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
           return (request && (request.imageStatus & request.STATUS_SIZE_AVAILABLE));
         }
         return false;
       }
     },
 
+    get _target() {
+      if (this._targetRef)
+        return this._targetRef.get();
+      return null;
+    },
+  
+    set _target(aTarget) {
+      if (aTarget)
+        this._targetRef = Cu.getWeakReference(aTarget);
+      else this._targetRef = null;
+    },
+
     _sendToContent: function(aX, aY) {
       // _highlightElement should already be fluffed to find nearby clickable elements
-      let rootElement = BrowserEventHandler._highlightElement;
+      let target = BrowserEventHandler._highlightElement;
+      if (!target)
+        return;
 
       this.menuitems = {};
       let menuitemsSet = false;
-      let element = rootElement;
-      if (!element)
-        return;
+      this._target = target;
+
+      // now walk up the tree and for each node look for any context menu items that apply
+      let element = target;
 
       while (element) {
         for each (let item in this.items) {
           if (!this.menuitems[item.id] && item.matches(element, aX, aY)) {
             this.menuitems[item.id] = item;
             menuitemsSet = true;
           }
         }
 
         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 (menuitemsSet) {
-        let event = rootElement.ownerDocument.createEvent("MouseEvent");
+        let event = target.ownerDocument.createEvent("MouseEvent");
         event.initMouseEvent("contextmenu", true, true, content,
                              0, aX, aY, aX, aY, false, false, false, false,
                              0, null);
-        rootElement.ownerDocument.defaultView.addEventListener("contextmenu", this, false);
-        rootElement.dispatchEvent(event);
-      } else if (SelectionHandler.canSelect(rootElement)) {
+        target.ownerDocument.defaultView.addEventListener("contextmenu", this, false);
+        target.dispatchEvent(event);
+      } else {
+        this._target = null;
         BrowserEventHandler._cancelTapHighlight();
-        SelectionHandler.startSelection(rootElement, aX, aY);
+
+        if (SelectionHandler.canSelect(target))
+          SelectionHandler.startSelection(target, aX, aY);
       }
     },
 
     _show: function(aEvent) {
       BrowserEventHandler._cancelTapHighlight();
-      if (aEvent.defaultPrevented)
+      let popupNode = this._target;
+      this._target = null;
+      if (aEvent.defaultPrevented || !popupNode)
         return;
 
       Haptic.performSimpleAction(Haptic.LongPress);
 
-      let popupNode = aEvent.originalTarget;
       let title = "";
-      if (popupNode.hasAttribute("title")) {
-        title = popupNode.getAttribute("title")
-      } else if ((popupNode instanceof Ci.nsIDOMHTMLAnchorElement && popupNode.href) ||
-              (popupNode instanceof Ci.nsIDOMHTMLAreaElement && popupNode.href)) {
-        title = this._getLinkURL(popupNode);
-      } else if (popupNode instanceof Ci.nsIImageLoadingContent && popupNode.currentURI) {
-        title = popupNode.currentURI.spec;
-      } else if (popupNode instanceof Ci.nsIDOMHTMLMediaElement) {
-        title = (popupNode.currentSrc || popupNode.src);
+
+      // spin through the tree looking for a title for this context menu
+      let node = popupNode;
+      while(node && !title) {
+        if (node.hasAttribute("title")) {
+          title = node.getAttribute("title")
+        } else if ((node instanceof Ci.nsIDOMHTMLAnchorElement && node.href) ||
+                (node instanceof Ci.nsIDOMHTMLAreaElement && node.href)) {
+          title = this._getLinkURL(node);
+        } else if (node instanceof Ci.nsIImageLoadingContent && node.currentURI) {
+          title = node.currentURI.spec;
+        } else if (node instanceof Ci.nsIDOMHTMLMediaElement) {
+          title = (node.currentSrc || node.src);
+        }
+        node = node.parentNode;
       }
 
       // convert this.menuitems object to an array for sending to native code
       let itemArray = [];
       for each (let item in this.menuitems) {
         itemArray.push(item.getValue(popupNode));
       }