1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/tests/chrome/window_largemenu.xul Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,379 @@ 1.4 +<?xml version="1.0"?> 1.5 +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> 1.6 + 1.7 +<window title="Large Menu Tests" 1.8 + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 1.9 + 1.10 + <script type="application/javascript" 1.11 + src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/> 1.12 + 1.13 +<!-- 1.14 + This test checks that a large menu is displayed with arrow buttons 1.15 + and is on the screen. 1.16 + --> 1.17 + 1.18 +<script> 1.19 +<![CDATA[ 1.20 + 1.21 +var gOverflowed = false, gUnderflowed = false; 1.22 +var gContextMenuTests = false; 1.23 +var gScreenY = -1; 1.24 +var gTestIndex = 0; 1.25 +var gTests = ["open normal", "open flipped position", "open with scrolling", 1.26 + "open after scrolling", "open small again", 1.27 + "menu movement", "panel movement", 1.28 + "context menu enough space below", 1.29 + "context menu more space above", 1.30 + "context menu too big either side", 1.31 + "context menu larger than screen"]; 1.32 + 1.33 +function getScreenXY(element) 1.34 +{ 1.35 + var screenX, screenY; 1.36 + var mouseFn = function(event) { 1.37 + screenX = event.screenX - 1; 1.38 + screenY = event.screenY - 1; 1.39 + } 1.40 + 1.41 + // a hacky way to get the screen position of an element without using the box object 1.42 + window.addEventListener("mousedown", mouseFn, false); 1.43 + synthesizeMouse(element, 1, 1, { }); 1.44 + window.removeEventListener("mousedown", mouseFn, false); 1.45 + 1.46 + return [screenX, screenY]; 1.47 +} 1.48 + 1.49 +function hidePopup() { 1.50 + window.requestAnimationFrame( 1.51 + function() { 1.52 + setTimeout( 1.53 + function() { 1.54 + document.getElementById("popup").hidePopup(); 1.55 + }, 0); 1.56 + }); 1.57 +} 1.58 + 1.59 +function runTests() 1.60 +{ 1.61 + [, gScreenY] = getScreenXY(document.documentElement); 1.62 + nextTest(); 1.63 +} 1.64 + 1.65 +function nextTest() 1.66 +{ 1.67 + gOverflowed = false, gUnderflowed = false; 1.68 + 1.69 + var y = screen.height; 1.70 + if (gTestIndex == 1) // open flipped position test: 1.71 + y -= 100; 1.72 + else 1.73 + y /= 2; 1.74 + 1.75 + var popup = document.getElementById("popup"); 1.76 + if (gTestIndex == 2) { 1.77 + // add some more menuitems so that scrolling will be necessary 1.78 + for (var t = 1; t <= 30; t++) { 1.79 + var menu = document.createElement("menuitem"); 1.80 + menu.setAttribute("label", "More" + t); 1.81 + popup.appendChild(menu); 1.82 + } 1.83 + } 1.84 + else if (gTestIndex == 4) { 1.85 + for (var t = 1; t <= 30; t++) 1.86 + popup.removeChild(popup.lastChild); 1.87 + } 1.88 + 1.89 + window.requestAnimationFrame(function() { 1.90 + setTimeout( 1.91 + function() { 1.92 + popup.openPopupAtScreen(100, y, false); 1.93 + }, 0); 1.94 + }); 1.95 +} 1.96 + 1.97 +function popupShown() 1.98 +{ 1.99 + if (gTests[gTestIndex] == "menu movement") 1.100 + return testPopupMovement(); 1.101 + 1.102 + if (gContextMenuTests) 1.103 + return contextMenuPopupShown(); 1.104 + 1.105 + var popup = document.getElementById("popup"); 1.106 + var rect = popup.getBoundingClientRect(); 1.107 + var sbo = document.getAnonymousNodes(popup)[0].scrollBoxObject; 1.108 + var expectedScrollPos = 0; 1.109 + 1.110 + if (gTestIndex == 0) { 1.111 + // the popup should be in the center of the screen 1.112 + // note that if the height is odd, the y-offset will have been rounded 1.113 + // down when we pass the fractional value to openPopupAtScreen above. 1.114 + is(Math.round(rect.top) + gScreenY, Math.floor(screen.height / 2), 1.115 + gTests[gTestIndex] + " top"); 1.116 + ok(Math.round(rect.bottom) + gScreenY < screen.height, 1.117 + gTests[gTestIndex] + " bottom"); 1.118 + ok(!gOverflowed && !gUnderflowed, gTests[gTestIndex] + " overflow") 1.119 + } 1.120 + else if (gTestIndex == 1) { 1.121 + // the popup was supposed to open 100 pixels from the bottom, but that 1.122 + // would put it off screen so it should be flipped to have its bottom 1.123 + // edge 100 pixels from the bottom 1.124 + ok(Math.round(rect.top) + gScreenY >= screen.top, gTests[gTestIndex] + " top"); 1.125 + is(Math.round(rect.bottom) + gScreenY, screen.height - 100, 1.126 + gTests[gTestIndex] + " bottom"); 1.127 + ok(!gOverflowed && !gUnderflowed, gTests[gTestIndex] + " overflow") 1.128 + } 1.129 + else if (gTestIndex == 2) { 1.130 + // the popup is too large so ensure that it is on screen 1.131 + ok(Math.round(rect.top) + gScreenY >= screen.top, gTests[gTestIndex] + " top"); 1.132 + ok(Math.round(rect.bottom) + gScreenY <= screen.height, gTests[gTestIndex] + " bottom"); 1.133 + ok(gOverflowed && !gUnderflowed, gTests[gTestIndex] + " overflow") 1.134 + 1.135 + sbo.scrollTo(0, 40); 1.136 + expectedScrollPos = 40; 1.137 + } 1.138 + else if (gTestIndex == 3) { 1.139 + expectedScrollPos = 40; 1.140 + } 1.141 + else if (gTestIndex == 4) { 1.142 + // note that if the height is odd, the y-offset will have been rounded 1.143 + // down when we pass the fractional value to openPopupAtScreen above. 1.144 + is(Math.round(rect.top) + gScreenY, Math.floor(screen.height / 2), 1.145 + gTests[gTestIndex] + " top"); 1.146 + ok(Math.round(rect.bottom) + gScreenY < screen.height, 1.147 + gTests[gTestIndex] + " bottom"); 1.148 + ok(!gOverflowed && gUnderflowed, gTests[gTestIndex] + " overflow") 1.149 + } 1.150 + 1.151 + var sx = { }, sy = { }; 1.152 + sbo.getPosition(sx, sy); 1.153 + is(sy.value, expectedScrollPos, "menu scroll position"); 1.154 + 1.155 + hidePopup(); 1.156 +} 1.157 + 1.158 +function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); } 1.159 +function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); } 1.160 + 1.161 +var oldx, oldy, waitSteps = 0; 1.162 +function moveWindowTo(x, y, callback, arg) 1.163 +{ 1.164 + if (!waitSteps) { 1.165 + oldx = window.screenX; 1.166 + oldy = window.screenY; 1.167 + window.moveTo(x, y); 1.168 + 1.169 + waitSteps++; 1.170 + setTimeout(moveWindowTo, 100, x, y, callback, arg); 1.171 + return; 1.172 + } 1.173 + 1.174 + if (window.screenX == oldx && window.screenY == oldy) { 1.175 + if (waitSteps++ > 10) { 1.176 + ok(false, "Window never moved properly to " + x + "," + y); 1.177 + window.opener.wrappedJSObject.SimpleTest.finish(); 1.178 + window.close(); 1.179 + } 1.180 + 1.181 + setTimeout(moveWindowTo, 100, x, y, callback, arg); 1.182 + } 1.183 + else { 1.184 + waitSteps = 0; 1.185 + callback(arg); 1.186 + } 1.187 +} 1.188 + 1.189 +function popupHidden() 1.190 +{ 1.191 + gTestIndex++; 1.192 + if (gTestIndex == gTests.length) { 1.193 + window.opener.wrappedJSObject.SimpleTest.finish(); 1.194 + window.close(); 1.195 + } 1.196 + else if (gTests[gTestIndex] == "context menu enough space below") { 1.197 + gContextMenuTests = true; 1.198 + moveWindowTo(window.screenX, screen.availTop + 10, 1.199 + function () synthesizeMouse(document.getElementById("label"), 4, 4, { type: "contextmenu", button: 2 })); 1.200 + } 1.201 + else if (gTests[gTestIndex] == "menu movement") { 1.202 + document.getElementById("popup").openPopup( 1.203 + document.getElementById("label"), "after_start", 0, 0, false, false); 1.204 + } 1.205 + else if (gTests[gTestIndex] == "panel movement") { 1.206 + document.getElementById("panel").openPopup( 1.207 + document.getElementById("label"), "after_start", 0, 0, false, false); 1.208 + } 1.209 + else if (gContextMenuTests) { 1.210 + contextMenuPopupHidden(); 1.211 + } 1.212 + else { 1.213 + nextTest(); 1.214 + } 1.215 +} 1.216 + 1.217 +function contextMenuPopupShown() 1.218 +{ 1.219 + var popup = document.getElementById("popup"); 1.220 + var rect = popup.getBoundingClientRect(); 1.221 + var labelrect = document.getElementById("label").getBoundingClientRect(); 1.222 + 1.223 + is(rect.left, labelrect.left + 6, gTests[gTestIndex] + " left"); 1.224 + switch (gTests[gTestIndex]) { 1.225 + case "context menu enough space below": 1.226 + is(rect.top, labelrect.top + 6, gTests[gTestIndex] + " top"); 1.227 + break; 1.228 + case "context menu more space above": 1.229 + is(rect.top, labelrect.top - rect.height + 2, gTests[gTestIndex] + " top"); 1.230 + break; 1.231 + case "context menu too big either side": 1.232 + [, gScreenY] = getScreenXY(document.documentElement); 1.233 + // compare against the available size as well as the total size, as some 1.234 + // platforms allow the menu to overlap os chrome and others do not 1.235 + var pos = (screen.availTop + screen.availHeight - rect.height) - gScreenY; 1.236 + var availPos = (screen.top + screen.height - rect.height) - gScreenY; 1.237 + ok(rect.top == pos || rect.top == availPos, 1.238 + gTests[gTestIndex] + " top"); 1.239 + break; 1.240 + case "context menu larger than screen": 1.241 + ok(rect.top == -(gScreenY - screen.availTop) || rect.top == -(gScreenY - screen.top), gTests[gTestIndex] + " top"); 1.242 + break; 1.243 + } 1.244 + 1.245 + hidePopup(); 1.246 +} 1.247 + 1.248 +function contextMenuPopupHidden() 1.249 +{ 1.250 + var screenAvailBottom = screen.availTop + screen.availHeight; 1.251 + 1.252 + if (gTests[gTestIndex] == "context menu more space above") { 1.253 + moveWindowTo(window.screenX, screenAvailBottom - 80, nextContextMenuTest, -1); 1.254 + } 1.255 + else if (gTests[gTestIndex] == "context menu too big either side") { 1.256 + moveWindowTo(window.screenX, screenAvailBottom / 2 - 80, nextContextMenuTest, screenAvailBottom / 2 + 120); 1.257 + } 1.258 + else if (gTests[gTestIndex] == "context menu larger than screen") { 1.259 + nextContextMenuTest(screen.availHeight + 80); 1.260 + } 1.261 +} 1.262 + 1.263 +function nextContextMenuTest(desiredHeight) 1.264 +{ 1.265 + if (desiredHeight >= 0) { 1.266 + var popup = document.getElementById("popup"); 1.267 + var height = popup.getBoundingClientRect().height; 1.268 + var itemheight = document.getElementById("firstitem").getBoundingClientRect().height; 1.269 + while (height < desiredHeight) { 1.270 + var menu = document.createElement("menuitem"); 1.271 + menu.setAttribute("label", "Item"); 1.272 + popup.appendChild(menu); 1.273 + height += itemheight; 1.274 + } 1.275 + } 1.276 + 1.277 + synthesizeMouse(document.getElementById("label"), 4, 4, { type: "contextmenu", button: 2 }); 1.278 +} 1.279 + 1.280 +function testPopupMovement() 1.281 +{ 1.282 + var button = document.getElementById("label"); 1.283 + var isPanelTest = (gTests[gTestIndex] == "panel movement"); 1.284 + var popup = document.getElementById(isPanelTest ? "panel" : "popup"); 1.285 + 1.286 + var screenX, screenY, buttonScreenX, buttonScreenY; 1.287 + var rect = popup.getBoundingClientRect(); 1.288 + 1.289 + var overlapOSChrome = (navigator.platform.indexOf("Mac") == -1); 1.290 + popup.moveTo(1, 1); 1.291 + [screenX, screenY] = getScreenXY(popup); 1.292 + 1.293 + var expectedx = 1, expectedy = 1; 1.294 + if (!isPanelTest && !overlapOSChrome) { 1.295 + if (screen.availLeft >= 1) expectedx = screen.availLeft; 1.296 + if (screen.availTop >= 1) expectedy = screen.availTop; 1.297 + } 1.298 + is(screenX, expectedx, gTests[gTestIndex] + " (1, 1) x"); 1.299 + is(screenY, expectedy, gTests[gTestIndex] + " (1, 1) y"); 1.300 + 1.301 + popup.moveTo(100, 8000); 1.302 + if (isPanelTest) { 1.303 + expectedy = 8000; 1.304 + } 1.305 + else { 1.306 + expectedy = (overlapOSChrome ? screen.height + screen.top : screen.availHeight + screen.availTop) - 1.307 + Math.round(rect.height); 1.308 + } 1.309 + 1.310 + [screenX, screenY] = getScreenXY(popup); 1.311 + is(screenX, 100, gTests[gTestIndex] + " (100, 8000) x"); 1.312 + is(screenY, expectedy, gTests[gTestIndex] + " (100, 8000) y"); 1.313 + 1.314 + popup.moveTo(6000, 100); 1.315 + 1.316 + if (isPanelTest) { 1.317 + expectedx = 6000; 1.318 + } 1.319 + else { 1.320 + expectedx = (overlapOSChrome ? screen.width + screen.left : screen.availWidth + screen.availLeft) - 1.321 + Math.round(rect.width); 1.322 + } 1.323 + 1.324 + [screenX, screenY] = getScreenXY(popup); 1.325 + is(screenX, expectedx, gTests[gTestIndex] + " (6000, 100) x"); 1.326 + is(screenY, 100, gTests[gTestIndex] + " (6000, 100) y"); 1.327 + 1.328 + is(popup.left, "", gTests[gTestIndex] + " left is empty after moving"); 1.329 + is(popup.top, "", gTests[gTestIndex] + " top is empty after moving"); 1.330 + popup.setAttribute("left", "80"); 1.331 + popup.setAttribute("top", "82"); 1.332 + [screenX, screenY] = getScreenXY(popup); 1.333 + is(screenX, 80, gTests[gTestIndex] + " set left and top x"); 1.334 + is(screenY, 82, gTests[gTestIndex] + " set left and top y"); 1.335 + popup.moveTo(95, 98); 1.336 + [screenX, screenY] = getScreenXY(popup); 1.337 + is(screenX, 95, gTests[gTestIndex] + " move after set left and top x"); 1.338 + is(screenY, 98, gTests[gTestIndex] + " move after set left and top y"); 1.339 + is(popup.left, "95", gTests[gTestIndex] + " left is set after moving"); 1.340 + is(popup.top, "98", gTests[gTestIndex] + " top is set after moving"); 1.341 + popup.removeAttribute("left"); 1.342 + popup.removeAttribute("top"); 1.343 + 1.344 + popup.moveTo(-1, -1); 1.345 + [screenX, screenY] = getScreenXY(popup); 1.346 + [buttonScreenX, buttonScreenY] = getScreenXY(button); 1.347 + is(screenX, buttonScreenX, gTests[gTestIndex] + " original x"); 1.348 + is(screenY, buttonScreenY + button.getBoundingClientRect().height, gTests[gTestIndex] + " original y"); 1.349 + 1.350 + popup.hidePopup(); 1.351 +} 1.352 + 1.353 +window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTests, window); 1.354 + 1.355 +]]> 1.356 +</script> 1.357 + 1.358 +<button id="label" label="OK" context="popup"/> 1.359 +<menupopup id="popup" onpopupshown="popupShown();" onpopuphidden="popupHidden();" 1.360 + onoverflow="gOverflowed = true" onunderflow="gUnderflowed = true;"> 1.361 + <menuitem id="firstitem" label="1"/> 1.362 + <menuitem label="2"/> 1.363 + <menuitem label="3"/> 1.364 + <menuitem label="4"/> 1.365 + <menuitem label="5"/> 1.366 + <menuitem label="6"/> 1.367 + <menuitem label="7"/> 1.368 + <menuitem label="8"/> 1.369 + <menuitem label="9"/> 1.370 + <menuitem label="10"/> 1.371 + <menuitem label="11"/> 1.372 + <menuitem label="12"/> 1.373 + <menuitem label="13"/> 1.374 + <menuitem label="14"/> 1.375 + <menuitem label="15"/> 1.376 +</menupopup> 1.377 + 1.378 +<panel id="panel" onpopupshown="testPopupMovement();" onpopuphidden="popupHidden();" style="margin: 0"> 1.379 + <button label="OK"/> 1.380 +</panel> 1.381 + 1.382 +</window>