diff --git a/mobile/chrome/content/browser.js b/mobile/chrome/content/browser.js index ba8d67d1ff5..1438f2f2cff 100644 --- a/mobile/chrome/content/browser.js +++ b/mobile/chrome/content/browser.js @@ -1527,9 +1527,9 @@ const ContentTouchHandler = { document.addEventListener("CancelTouchSequence", this, false); // Context menus have the following flow: - // [parent] mousedown -> TapDown -> Browser:MouseDown - // [child] Browser:MouseDown -> contextmenu -> Browser:ContextMenu - // [parent] Browser:ContextMenu -> ...* -> TapLong + // [parent] mousedown -> TapLong -> Browser:MouseLong + // [child] Browser:MouseLong -> contextmenu -> Browser:ContextMenu + // [parent] Browser:ContextMenu -> ...* // // * = Here some time will elapse. Although we get the context menu we need // ASAP, we do not act on the context menu until we receive a LongTap. @@ -1583,7 +1583,7 @@ const ContentTouchHandler = { this.tapDouble(aEvent.clientX, aEvent.clientY, aEvent.modifiers); break; case "TapLong": - this.tapLong(); + this.tapLong(aEvent.clientX, aEvent.clientY); break; } } @@ -1597,7 +1597,13 @@ const ContentTouchHandler = { switch (aMessage.name) { case "Browser:ContextMenu": // Long tap - this._contextMenu = { name: aMessage.name, json: aMessage.json, target: aMessage.target }; + let contextMenu = { name: aMessage.name, json: aMessage.json, target: aMessage.target }; + if (ContextHelper.showPopup(contextMenu)) { + // Stop all input sequences + let event = document.createEvent("Events"); + event.initEvent("CancelTouchSequence", true, false); + document.dispatchEvent(event); + } break; case "Browser:Highlight": { @@ -1679,16 +1685,8 @@ const ContentTouchHandler = { this._dispatchMouseEvent("Browser:ZoomToPoint", aX, aY, { width: width }); }, - tapLong: function tapLong() { - if (this._contextMenu) { - if (ContextHelper.showPopup(this._contextMenu)) { - // Stop all input sequences - let event = document.createEvent("Events"); - event.initEvent("CancelTouchSequence", true, false); - document.dispatchEvent(event); - } - this._contextMenu = null; - } + tapLong: function tapLong(aX, aY) { + this._dispatchMouseEvent("Browser:MouseLong", aX, aY); }, toString: function toString() { diff --git a/mobile/chrome/content/content.js b/mobile/chrome/content/content.js index e502b1499ae..da164a36906 100644 --- a/mobile/chrome/content/content.js +++ b/mobile/chrome/content/content.js @@ -311,8 +311,8 @@ function Content() { addMessageListener("Browser:Blur", this); addMessageListener("Browser:KeyEvent", this); - addMessageListener("Browser:MouseDown", this); addMessageListener("Browser:MouseOver", this); + addMessageListener("Browser:MouseLong", this); addMessageListener("Browser:MouseUp", this); addMessageListener("Browser:SaveAs", this); addMessageListener("Browser:ZoomToPoint", this); @@ -424,19 +424,6 @@ Content.prototype = { } break; - case "Browser:MouseDown": { - let element = elementFromPoint(x, y); - if (!element) - return; - - ContextHandler.messageId = json.messageId; - - let event = content.document.createEvent("PopupEvents"); - event.initEvent("contextmenu", true, true); - element.dispatchEvent(event); - break; - } - case "Browser:MouseOver": { let element = elementFromPoint(x, y); if (!element) @@ -465,6 +452,19 @@ Content.prototype = { break; } + case "Browser:MouseLong": { + let element = elementFromPoint(x, y); + if (!element) + return; + + ContextHandler.messageId = json.messageId; + + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + element.dispatchEvent(event); + break; + } + case "Browser:MouseUp": { this._formAssistant.focusSync = true; let element = elementFromPoint(x, y); diff --git a/mobile/chrome/tests/browser_tap_content.html b/mobile/chrome/tests/browser_tap_content.html index 95fe8d3c506..e39161d9e38 100644 --- a/mobile/chrome/tests/browser_tap_content.html +++ b/mobile/chrome/tests/browser_tap_content.html @@ -5,7 +5,9 @@
A plain link
- A blank page - nothing interesting + A blank page - no context menu +
+ A blank page - nothing interesting
diff --git a/mobile/chrome/tests/browser_tapping.js b/mobile/chrome/tests/browser_tapping.js index 6360aac157a..b74c890072f 100644 --- a/mobile/chrome/tests/browser_tapping.js +++ b/mobile/chrome/tests/browser_tapping.js @@ -35,14 +35,6 @@ function checkEvents(aEvents) { } let gContextTypes = ""; -function dumpMessages(aMessage) { - if (aMessage.name == "Browser:ContextMenu") { - aMessage.json.types.forEach(function(aType) { - gContextTypes.push(aType); - }) - } -} - function clearContextTypes() { gContextTypes = []; @@ -67,6 +59,22 @@ function checkContextTypes(aTypes) { return true; } +function waitForContextMenu(aCallback, aNextTest) { + clearContextTypes(); + + let browser = gCurrentTab.browser; + browser.messageManager.addMessageListener("Browser:ContextMenu", function(aMessage) { + browser.messageManager.removeMessageListener(aMessage.name, arguments.callee); + aMessage.json.types.forEach(function(aType) { + gContextTypes.push(aType); + }); + setTimeout(function() { + aCallback(aMessage.json); + clearContextTypes(); + aNextTest(); + }, 0); + }); +} function test() { // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()" @@ -80,7 +88,7 @@ function test() { window.addEventListener("TapSingle", dumpEvents, true); window.addEventListener("TapDouble", dumpEvents, true); window.addEventListener("TapLong", dumpEvents, true); - + // Wait for the tab to load, then do the tests messageManager.addMessageListener("pageshow", function() { if (gCurrentTab.browser.currentURI.spec == testURL) { @@ -120,14 +128,17 @@ gTests.push({ let height = browser.getBoundingClientRect().height; // Should fire "TapSingle" - // XXX not working? WTF? info("Test good single tap"); clearEvents(); EventUtils.synthesizeMouse(browser, width / 2, height / 2, {}); - todo(checkEvents(["TapSingle"]), "Fired a good single tap"); - clearEvents(); - setTimeout(function() { gCurrentTest.doubleTapTest(); }, 500); + // We wait a bit because of the delay allowed for double clicking on device + // where it is not native + setTimeout(function() { + ok(checkEvents(["TapSingle"]), "Fired a good single tap"); + clearEvents(); + gCurrentTest.doubleTapTest(); + }, kDoubleClickInterval); }, doubleTapTest: function() { @@ -173,7 +184,7 @@ gTests.push({ EventUtils.synthesizeMouse(browser, width / 2, height * 3 / 4, { type: "mouseup" }); ok(checkEvents([]), "Fired a pan which should be seen as a non event"); clearEvents(); - + setTimeout(function() { gCurrentTest.longTapFailTest(); }, 500); }, @@ -200,76 +211,63 @@ gTests.push({ let width = browser.getBoundingClientRect().width; let height = browser.getBoundingClientRect().height; - info("Test a good long pan"); - clearEvents(); - EventUtils.synthesizeMouse(browser, width / 2, height / 4, { type: "mousedown" }); - setTimeout(function() { + window.addEventListener("TapLong", function() { + window.removeEventListener("TapLong", arguments.callee, true); EventUtils.synthesizeMouse(browser, width / 2, height / 4, { type: "mouseup" }); ok(checkEvents(["TapLong"]), "Fired a good long tap"); clearEvents(); + }, true); - gCurrentTest.contextPlainLinkTest(); - }, 500); + browser.messageManager.addMessageListener("Browser:ContextMenu", function(aMessage) { + browser.messageManager.removeMessageListener(aMessage.name, arguments.callee); + setTimeout(gCurrentTest.contextPlainLinkTest, 0); + }); + + info("Test a good long pan"); + clearEvents(); + EventUtils.synthesizeMouse(browser, width / 2, height / 4, { type: "mousedown" }); }, contextPlainLinkTest: function() { + waitForContextMenu(function(aJSON) { + is(aJSON.linkTitle, "A blank page - nothing interesting", "Text content should be the content of the second link"); + ok(checkContextTypes(["link","link-saveable","link-openable"]), "Plain link context types"); + }, gCurrentTest.contextPlainImageTest); + let browser = gCurrentTab.browser; - browser.messageManager.addMessageListener("Browser:ContextMenu", dumpMessages); + let linkDisabled = browser.contentDocument.getElementById("link-disabled"); + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + linkDisabled.dispatchEvent(event); let link = browser.contentDocument.getElementById("link-single"); - let linkRect = link.getBoundingClientRect(); - - clearContextTypes(); - EventUtils.synthesizeMouseForContent(link, linkRect.width/2, linkRect.height/4, { type: "mousedown" }, window); - setTimeout(function() { - EventUtils.synthesizeMouseForContent(link, linkRect.width/2, linkRect.height/4, { type: "mouseup" }, window); - ok(checkContextTypes(["link","link-saveable","link-openable"]), "Plain link context types"); - clearContextTypes(); - - gCurrentTest.contextPlainImageTest(); - }, 500); + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + link.dispatchEvent(event); }, contextPlainImageTest: function() { - let browser = gCurrentTab.browser; - browser.messageManager.addMessageListener("Browser:ContextMenu", dumpMessages); - - let img = browser.contentDocument.getElementById("img-single"); - let imgRect = img.getBoundingClientRect(); - - clearContextTypes(); - EventUtils.synthesizeMouseForContent(img, imgRect.width/2, imgRect.height/2, { type: "mousedown" }, window); - setTimeout(function() { - EventUtils.synthesizeMouseForContent(img, 1, 1, { type: "mouseup" }, window); + waitForContextMenu(function() { ok(checkContextTypes(["image","image-shareable","image-loaded"]), "Plain image context types"); - clearContextTypes(); + }, gCurrentTest.contextNestedImageTest); - gCurrentTest.contextNestedImageTest(); - }, 500); + let browser = gCurrentTab.browser; + let img = browser.contentDocument.getElementById("img-single"); + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + img.dispatchEvent(event); }, contextNestedImageTest: function() { - let browser = gCurrentTab.browser; - browser.messageManager.addMessageListener("Browser:ContextMenu", dumpMessages); - - let img = browser.contentDocument.getElementById("img-nested"); - let imgRect = img.getBoundingClientRect(); - - clearContextTypes(); - EventUtils.synthesizeMouseForContent(img, 1, 1, { type: "mousedown" }, window); - setTimeout(function() { - EventUtils.synthesizeMouseForContent(img, 1, 1, { type: "mouseup" }, window); + waitForContextMenu(function() { ok(checkContextTypes(["link","link-saveable","image","image-shareable","image-loaded","link-openable"]), "Nested image context types"); - clearContextTypes(); + }, runNextTest); - gCurrentTest.lastTest(); - }, 500); - }, - - lastTest: function() { - gCurrentTab.browser.messageManager.removeMessageListener("Browser:ContextMenu", dumpMessages); - - runNextTest(); + let browser = gCurrentTab.browser; + let img = browser.contentDocument.getElementById("img-nested"); + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + img.dispatchEvent(event); } });