diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 34f44dd1da9a..3aed24e970df 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1426,15 +1426,30 @@ var NativeWindow = { } }, + 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) { @@ -1451,36 +1466,46 @@ var NativeWindow = { // 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