summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/chrome/test_contextmenu_list.xhtml
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/chrome/test_contextmenu_list.xhtml')
-rw-r--r--toolkit/content/tests/chrome/test_contextmenu_list.xhtml296
1 files changed, 296 insertions, 0 deletions
diff --git a/toolkit/content/tests/chrome/test_contextmenu_list.xhtml b/toolkit/content/tests/chrome/test_contextmenu_list.xhtml
new file mode 100644
index 0000000000..d5d2b1a10b
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_contextmenu_list.xhtml
@@ -0,0 +1,296 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Context Menu on List Tests"
+ onload="setTimeout(startTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+<spacer style="height: 5px"/>
+
+<hbox style="padding-left: 10px;">
+ <spacer style="width: 5ps"/>
+ <richlistbox id="list" context="themenu" style="padding: 0;" oncontextmenu="checkContextMenu(event)">
+ <richlistitem id="item1" style="padding-top: 4px; margin: 0;"><button label="One"/></richlistitem>
+ <richlistitem id="item2" style="height: 22px"><checkbox label="Checkbox"/></richlistitem>
+ <richlistitem id="item3"><button label="Three"/></richlistitem>
+ <richlistitem id="item4"><checkbox label="Four"/></richlistitem>
+ </richlistbox>
+
+ <tree id="tree" rows="5" flex="1" context="themenu" style="-moz-appearance: none; border: 0">
+ <treecols>
+ <treecol label="Name" flex="1"/>
+ <splitter class="tree-splitter"/>
+ <treecol label="Moons"/>
+ </treecols>
+ <treechildren id="treechildren">
+ <treeitem>
+ <treerow>
+ <treecell label="Mercury"/>
+ <treecell label="0"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Venus"/>
+ <treecell label="0"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Earth"/>
+ <treecell label="1"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Mars"/>
+ <treecell label="2"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+ </tree>
+
+ <menu id="menu" label="Menu">
+ <menupopup id="menupopup" onpopupshown="menuTests()" onpopuphidden="nextTest()"
+ oncontextmenu="checkContextMenuForMenu(event)">
+ <menuitem id="menu1" label="Menu 1"/>
+ <menuitem id="menu2" label="Menu 2"/>
+ <menuitem id="menu3" label="Menu 3"/>
+ </menupopup>
+ </menu>
+
+</hbox>
+
+<menupopup id="themenu" onpopupshowing="if (gTestId == -1) event.preventDefault()"
+ onpopupshown="checkPopup()" onpopuphidden="setTimeout(nextTest, 0);">
+ <menuitem label="Item"/>
+</menupopup>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gTestId = -1;
+var gTestElement = "list";
+var gSelectionStep = 0;
+var gContextMenuFired = false;
+
+async function startTest()
+{
+ // These tests check behavior of non-native menus, and use anchored and non-anchored popups
+ // somewhat interchangeably. So disable native context menus for this test.
+ // We will have separate tests for native context menu behavior, see bug 1700727.
+ await SpecialPowers.pushPrefEnv({ set: [["widget.macos.native-context-menus", false]] });
+
+ // first, check if the richlistbox selection changes on a contextmenu mouse event
+ var element = $("list");
+ synthesizeMouse(element.getItemAtIndex(3), 7, 1, { type : "mousedown", button: 2, ctrlKey: true });
+ synthesizeMouse(element, 7, 4, { type : "contextmenu", button: 2 });
+
+ gSelectionStep++;
+ synthesizeMouse(element.getItemAtIndex(1), 7, 1, { type : "mousedown", button: 2, ctrlKey: true, shiftKey: true });
+ synthesizeMouse(element, 7, 4, { type : "contextmenu", button: 2 });
+
+ gSelectionStep++;
+ synthesizeMouse(element.getItemAtIndex(1), 7, 1, { type : "mousedown", button: 2 });
+ synthesizeMouse(element, 7, 4, { type : "contextmenu", button: 2 });
+
+ $("menu").open = true;
+}
+
+function menuTests()
+{
+ gSelectionStep = 0;
+ var element = $("menu");
+ synthesizeMouse(element, 0, 0, { type : "contextmenu", button: 0 });
+ is(gContextMenuFired, true, "context menu fired when menu open");
+
+ gSelectionStep = 1;
+ $("menu").activeChild = $("menu2");
+ synthesizeMouse(element, 0, 0, { type : "contextmenu", button: 0 });
+
+ $("menu").open = false;
+}
+
+function nextTest()
+{
+ gTestId++;
+ if (gTestId > 2) {
+ if (gTestElement == "list") {
+ gTestElement = "tree";
+ gTestId = 0;
+ }
+ else {
+ SimpleTest.finish();
+ return;
+ }
+ }
+ var element = $(gTestElement);
+ element.focus();
+ if (gTestId == 0) {
+ if (gTestElement == "list")
+ element.selectedIndex = 2;
+ element.currentIndex = 2;
+ synthesizeMouse(element, 0, 0, { type : "contextmenu", button: 0 });
+ }
+ else if (gTestId == 1) {
+ synthesizeMouse(element, 7, 4, { type : "contextmenu", button: 2 });
+ }
+ else {
+ element.currentIndex = -1;
+ element.selectedIndex = -1;
+ synthesizeMouse(element, 0, 0, { type : "contextmenu", button: 0 });
+ }
+}
+
+// This is nasty so I'd better explain what's going on.
+// The basic problem is that the synthetic mouse coordinate generated
+// by DOMWindowUtils.sendMouseEvent and also the synthetic mouse coordinate
+// generated internally when contextmenu events are redirected to the focused
+// element are rounded to the nearest device pixel. But this rounding is done
+// while the coordinates are relative to the nearest widget. When this test
+// is run in the mochitest harness, the nearest widget is the main mochitest
+// window, and our document can have a fractional position within that
+// mochitest window. So when we round coordinates for comparison in this
+// test, we need to do so very carefully, especially if the target element
+// also has a fractional position within our document.
+//
+// For example, if the y-offset of our containing IFRAME is 100.4px,
+// and the offset of our expected point is 10.3px in our document, the actual
+// mouse event is dispatched to round(110.7) == 111px. This comes back
+// with a clientY of round(111 - 100.4) == round(10.6) == 11. This is not
+// equal to round(10.3) as you might expect.
+
+function isRoundedX(a, b, msg)
+{
+ is(Math.round(a + window.mozInnerScreenX), Math.round(b + window.mozInnerScreenX), msg);
+}
+
+function isRoundedY(a, b, msg)
+{
+ is(Math.round(a + window.mozInnerScreenY), Math.round(b + window.mozInnerScreenY), msg);
+}
+
+function checkContextMenu(event)
+{
+ var rect = $(gTestElement).getBoundingClientRect();
+
+ var frombase = (gTestId == -1 || gTestId == 1);
+ if (!frombase)
+ rect = event.originalTarget.getBoundingClientRect();
+ var left = frombase ? rect.left + 7 : rect.left;
+ var top = frombase ? rect.top + 4 : rect.bottom;
+
+ isRoundedX(event.clientX, left, gTestElement + " clientX " + gSelectionStep + " " + gTestId + "," + frombase);
+ isRoundedY(event.clientY, top, gTestElement + " clientY " + gSelectionStep + " " + gTestId);
+ ok(event.screenX > left, gTestElement + " screenX " + gSelectionStep + " " + gTestId);
+ ok(event.screenY > top, gTestElement + " screenY " + gSelectionStep + " " + gTestId);
+
+ // context menu from mouse click
+ switch (gTestId) {
+ case -1:
+ // eslint-disable-next-line no-nested-ternary
+ var expected = gSelectionStep == 2 ? 1 : (platformIsMac() ? 3 : 0);
+ is($(gTestElement).selectedIndex, expected, "index after click " + gSelectionStep);
+ break;
+ case 0:
+ if (gTestElement == "list")
+ is(event.originalTarget, $("item3"), "list selection target");
+ else
+ is(event.originalTarget, $("treechildren"), "tree selection target");
+ break;
+ case 1:
+ is(event.originalTarget.id, $("item1").id, "list mouse selection target");
+ break;
+ case 2:
+ is(event.originalTarget, $("list"), "list no selection target");
+ break;
+ }
+}
+
+function checkContextMenuForMenu(event)
+{
+ gContextMenuFired = true;
+
+ var popuprect = (gSelectionStep ? $("menu2") : $("menupopup")).getBoundingClientRect();
+ is(event.clientX, Math.round(popuprect.left), "menu left " + gSelectionStep);
+ // the clientY is off by one sometimes on Windows (when loaded in the testing iframe
+ // but not when loaded separately) so just check for both cases for now
+ ok(event.clientY == Math.round(popuprect.bottom) ||
+ event.clientY - 1 == Math.round(popuprect.bottom), "menu top " + gSelectionStep);
+}
+
+function checkPopup()
+{
+ var menurect = $("themenu").getBoundingClientRect();
+
+ // Context menus are offset by a number of pixels from the mouse click
+ // which activates them. This is so that they don't appear exactly
+ // under the mouse which can cause them to be mistakenly dismissed.
+ // The number of pixels depends on the platform and is defined in
+ // each platform's nsLookAndFeel
+ var contextMenuOffsetX = platformIsMac() ? 1 : 2;
+ var contextMenuOffsetY = platformIsMac() ? -6 : 2;
+ contextMenuOffsetY += parseFloat(getComputedStyle($("themenu")).marginTop);
+ contextMenuOffsetX += parseFloat(getComputedStyle($("themenu")).marginLeft);
+
+ if (gTestId == 0) {
+ if (gTestElement == "list") {
+ var itemrect = $("item3").getBoundingClientRect();
+ isRoundedX(menurect.left, itemrect.left + contextMenuOffsetX,
+ "list selection keyboard left");
+ isRoundedY(menurect.top, itemrect.bottom + contextMenuOffsetY,
+ "list selection keyboard top");
+ }
+ else {
+ var tree = $("tree");
+ var bodyrect = $("treechildren").getBoundingClientRect();
+ isRoundedX(menurect.left, bodyrect.left + contextMenuOffsetX,
+ "tree selection keyboard left");
+ isRoundedY(menurect.top, bodyrect.top +
+ tree.rowHeight * 3 + contextMenuOffsetY,
+ "tree selection keyboard top");
+ }
+ }
+ else if (gTestId == 1) {
+ // activating a context menu with the mouse from position (7, 4).
+ let elementrect = $(gTestElement).getBoundingClientRect();
+ isRoundedX(menurect.left, elementrect.left + 7 + contextMenuOffsetX,
+ gTestElement + " mouse left");
+ isRoundedY(menurect.top, elementrect.top + 4 + contextMenuOffsetY,
+ gTestElement + " mouse top");
+ }
+ else {
+ let elementrect = $(gTestElement).getBoundingClientRect();
+ isRoundedX(menurect.left, elementrect.left + contextMenuOffsetX,
+ gTestElement + " no selection keyboard left");
+ isRoundedY(menurect.top, elementrect.bottom + contextMenuOffsetY,
+ gTestElement + " no selection keyboard top");
+ }
+
+ $("themenu").hidePopup();
+}
+
+function platformIsMac()
+{
+ return navigator.platform.indexOf("Mac") > -1;
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>