toolkit/content/tests/widgets/test_popupanchor.xul

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 <?xml version="1.0"?>
     2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
     3 <?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
     5 <window title="Popup Anchor Tests"
     6   xmlns:html="http://www.w3.org/1999/xhtml"
     7   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
     9   <panel id="testPanel"
    10          type="arrow"
    11          animate="false"
    12          noautohide="true">
    13   </panel>
    15   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
    17 <script>
    18 <![CDATA[
    19 var anchor, panel, arrow;
    21 function is_close(got, exp, msg) {
    22   // on some platforms we see differences of a fraction of a pixel - so
    23   // allow any difference of < 1 pixels as being OK.
    24   ok(Math.abs(got - exp) < 1, msg + ": " + got + " should be equal(-ish) to " + exp);
    25 }
    27 function isArrowPositionedOn(side, offset) {
    28   var arrowRect = arrow.getBoundingClientRect();
    29   var arrowMidX = (arrowRect.left + arrowRect.right) / 2;
    30   var arrowMidY = (arrowRect.top + arrowRect.bottom) / 2;
    31   var panelRect = panel.getBoundingClientRect();
    32   var panelMidX = (panelRect.left + panelRect.right) / 2;
    33   var panelMidY = (panelRect.top + panelRect.bottom) / 2;
    34   // First check the "flip" of the panel is correct.  If we are expecting the
    35   // arrow to be pointing to the left side of the anchor, the arrow must
    36   // also be on the left side of the panel (and vice-versa)
    37   // XXX - on OSX, the arrow seems to always be exactly in the center, hence
    38   // the 'equals' sign in the "<=" and ">=" comparisons.  NFI why though...
    39   switch (side) {
    40     case "left":
    41       ok(arrowMidX <= panelMidX, "arrow should be on the left of the panel");
    42       break;
    43     case "right":
    44       ok(arrowMidX >= panelMidX, "arrow should be on the right of the panel");
    45       break;
    46     case "top":
    47       ok(arrowMidY <= panelMidY, "arrow should be on the top of the panel");
    48       break;
    49     case "bottom":
    50       ok(arrowMidY >= panelMidY, "arrow should be on the bottom of the panel");
    51       break;
    52     default:
    53       ok(false, "invalid position " + where);
    54       break;
    55   }
    56   // Now check the arrow really is pointing where we expect.  The middle of
    57   // the arrow should be pointing exactly to the left (or right) side of the
    58   // anchor rect, +- any offsets.
    59   if (offset === null) // special case - explicit 'null' means 'don't check offset'
    60     return;
    61   offset = offset || 0; // no param means no offset expected.
    62   var anchorRect = anchor.getBoundingClientRect();
    63   var anchorPos = anchorRect[side];
    64   switch (side) {
    65     case "left":
    66     case "right":
    67       is_close(arrowMidX - anchorPos, offset, "arrow should be " + offset + "px from " + side + " side of anchor");
    68       is_close(panelRect.top, anchorRect.bottom, "top of panel should be at bottom of anchor");
    69       break;
    70     case "top":
    71     case "bottom":
    72       is_close(arrowMidY - anchorPos, offset, "arrow should be " + offset + "px from " + side + " side of anchor");
    73       is_close(panelRect.right, anchorRect.left, "right of panel should be left of anchor");
    74       break;
    75     default:
    76       ok(false, "unknown side " + side);
    77       break;
    78   }
    79 }
    81 function openSlidingPopup(position, callback) {
    82   panel.setAttribute("flip", "slide");
    83   _openPopup(position, callback);
    84 }
    86 function openPopup(position, callback) {
    87   panel.setAttribute("flip", "both");
    88   _openPopup(position, callback);
    89 }
    91 function _openPopup(position, callback) {
    92   // this is very ugly: the panel CSS sets the arrow's list-style-image based
    93   // on the 'side' attribute.  If the setting of the 'side' attribute causes
    94   // the image to change, we may get the popupshown event before the new
    95   // image has loaded - which causes the size of the arrow to be incorrect
    96   // for a brief moment - right when we are measuring it!
    97   // So we work around this in 2 steps:
    98   // * Force the 'side' attribute to a value which causes the CSS to not
    99   //   specify an image - then when the popup gets shown, the correct image
   100   //   is set, causing a load() event on the image element.
   101   // * Listen to *both* popupshown and the image load event.  When both have
   102   //   fired (the order is indeterminate) we start the test.
   103   panel.setAttribute("side", "noside");
   104   var numEvents = 0;
   105   function onEvent() {
   106     if (++numEvents == 2) // after both panel 'popupshown' and image 'load'
   107       callback();
   108   };
   109   panel.addEventListener("popupshown", function popupshown() {
   110     panel.removeEventListener("popupshown", popupshown);
   111     onEvent();
   112   });
   113   arrow.addEventListener("load", function imageload() {
   114     arrow.removeEventListener("load", imageload);
   115     onEvent();
   116   });
   117   panel.openPopup(anchor, position);
   118 }
   120 var tests = [
   121   // A panel with the anchor after_end - the anchor should not move on resize
   122   ['simpleResizeHorizontal', 'middle', function(next) {
   123     openPopup("after_end", function() {
   124       isArrowPositionedOn("right");
   125       var origPanelRect = panel.getBoundingClientRect();
   126       panel.sizeTo(100, 100);
   127       isArrowPositionedOn("right"); // should not have flipped, so still "right"
   128       panel.sizeTo(origPanelRect.width, origPanelRect.height);
   129       isArrowPositionedOn("right"); // should not have flipped, so still "right"
   130       next();
   131     });
   132   }],
   134   ['simpleResizeVertical', 'middle', function(next) {
   135     openPopup("start_after", function() {
   136       isArrowPositionedOn("bottom");
   137       var origPanelRect = panel.getBoundingClientRect();
   138       panel.sizeTo(100, 100);
   139       isArrowPositionedOn("bottom"); // should not have flipped
   140       panel.sizeTo(origPanelRect.width, origPanelRect.height);
   141       isArrowPositionedOn("bottom"); // should not have flipped
   142       next();
   143     });
   144   }],
   146   ['flippingResizeHorizontal', 'middle', function(next) {
   147     openPopup("after_end", function() {
   148       isArrowPositionedOn("right");
   149       panel.sizeTo(anchor.getBoundingClientRect().left + 50, 50);
   150       isArrowPositionedOn("left"); // check it flipped and has zero offset.
   151       next();
   152     });
   153   }],
   155   ['flippingResizeVertical', 'middle', function(next) {
   156     openPopup("start_after", function() {
   157       isArrowPositionedOn("bottom");
   158       panel.sizeTo(50, anchor.getBoundingClientRect().top + 50);
   159       isArrowPositionedOn("top"); // check it flipped and has zero offset.
   160       next();
   161     });
   162   }],
   164   ['simpleMoveToAnchorHorizontal', 'middle', function(next) {
   165     openPopup("after_end", function() {
   166       isArrowPositionedOn("right");
   167       panel.moveToAnchor(anchor, "after_end", 20, 0);
   168       // the anchor and the panel should have moved 20px right without flipping.
   169       isArrowPositionedOn("right", 20);
   170       panel.moveToAnchor(anchor, "after_end", -20, 0);
   171       // the anchor and the panel should have moved 20px left without flipping.
   172       isArrowPositionedOn("right", -20);
   173       next();
   174     });
   175   }],
   177   ['simpleMoveToAnchorVertical', 'middle', function(next) {
   178     openPopup("start_after", function() {
   179       isArrowPositionedOn("bottom");
   180       panel.moveToAnchor(anchor, "start_after", 0, 20);
   181       // the anchor and the panel should have moved 20px down without flipping.
   182       isArrowPositionedOn("bottom", 20);
   183       panel.moveToAnchor(anchor, "start_after", 0, -20);
   184       // the anchor and the panel should have moved 20px up without flipping.
   185       isArrowPositionedOn("bottom", -20);
   186       next();
   187     });
   188   }],
   190   // Do a moveToAnchor that causes the panel to flip horizontally
   191   ['flippingMoveToAnchorHorizontal', 'middle', function(next) {
   192     var anchorRight = anchor.getBoundingClientRect().right;
   193     // Size the panel such that it only just fits from the left-hand side of
   194     // the window to the right of the anchor - thus, it will fit when
   195     // anchored to the right-hand side of the anchor.
   196     panel.sizeTo(anchorRight - 10, 100);
   197     openPopup("after_end", function() {
   198       isArrowPositionedOn("right");
   199       // Ask for it to be anchored 1/2 way between the left edge of the window
   200       // and the anchor right - it can't fit with the panel on the left/arrow
   201       // on the right, so it must flip (arrow on the left, panel on the right)
   202       var offset = Math.floor(-anchorRight / 2);
   203       panel.moveToAnchor(anchor, "after_end", offset, 0);
   204       isArrowPositionedOn("left", offset); // should have flipped and have the offset.
   205       // resize back to original and move to a zero offset - it should flip back.
   206       panel.sizeTo(anchorRight - 10, 100);
   207       panel.moveToAnchor(anchor, "after_end", 0, 0);
   208       isArrowPositionedOn("right"); // should have flipped back and no offset
   209       next();
   210     });
   211   }],
   213   // Do a moveToAnchor that causes the panel to flip vertically
   214   ['flippingMoveToAnchorVertical', 'middle', function(next) {
   215     var anchorBottom = anchor.getBoundingClientRect().bottom;
   216     // See comments above in flippingMoveToAnchorHorizontal, but read
   217     // "top/bottom" instead of "left/right"
   218     panel.sizeTo(100, anchorBottom - 10);
   219     openPopup("start_after", function() {
   220       isArrowPositionedOn("bottom");
   221       var offset = Math.floor(-anchorBottom / 2);
   222       panel.moveToAnchor(anchor, "start_after", 0, offset);
   223       isArrowPositionedOn("top", offset);
   224       panel.sizeTo(100, anchorBottom - 10);
   225       panel.moveToAnchor(anchor, "start_after", 0, 0);
   226       isArrowPositionedOn("bottom");
   227       next();
   228     });
   229   }],
   231   ['veryWidePanel-after_end', 'middle', function(next) {
   232     openSlidingPopup("after_end", function() {
   233       var origArrowRect = arrow.getBoundingClientRect();
   234       // Now move it such that the arrow can't be at either end of the panel but
   235       // instead somewhere in the middle as that is the only way things fit,
   236       // meaning the arrow should "slide" down the panel.
   237       panel.sizeTo(window.innerWidth - 10, 60);
   238       is(panel.getBoundingClientRect().width, window.innerWidth - 10, "width is what we requested.")
   239       // the arrow should not have moved.
   240       var curArrowRect = arrow.getBoundingClientRect();
   241       is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
   242       is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
   243       next();
   244     });
   245   }],
   247   ['veryWidePanel-before_start', 'middle', function(next) {
   248     openSlidingPopup("before_start", function() {
   249       var origArrowRect = arrow.getBoundingClientRect();
   250       // Now size it such that the arrow can't be at either end of the panel but
   251       // instead somewhere in the middle as that is the only way things fit.
   252       panel.sizeTo(window.innerWidth - 10, 60);
   253       is(panel.getBoundingClientRect().width, window.innerWidth - 10, "width is what we requested")
   254       // the arrow should not have moved.
   255       var curArrowRect = arrow.getBoundingClientRect();
   256       is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
   257       is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
   258       next();
   259     });
   260   }],
   262   ['veryTallPanel-start_after', 'middle', function(next) {
   263     openSlidingPopup("start_after", function() {
   264       var origArrowRect = arrow.getBoundingClientRect();
   265       // Now move it such that the arrow can't be at either end of the panel but
   266       // instead somewhere in the middle as that is the only way things fit,
   267       // meaning the arrow should "slide" down the panel.
   268       panel.sizeTo(100, window.innerHeight - 10);
   269       is(panel.getBoundingClientRect().height, window.innerHeight - 10, "height is what we requested.")
   270       // the arrow should not have moved.
   271       var curArrowRect = arrow.getBoundingClientRect();
   272       is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
   273       is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
   274       next();
   275     });
   276   }],
   278   ['veryTallPanel-start_before', 'middle', function(next) {
   279     openSlidingPopup("start_before", function() {
   280       var origArrowRect = arrow.getBoundingClientRect();
   281       // Now size it such that the arrow can't be at either end of the panel but
   282       // instead somewhere in the middle as that is the only way things fit.
   283       panel.sizeTo(100, window.innerHeight - 10);
   284       is(panel.getBoundingClientRect().height, window.innerHeight - 10, "height is what we requested")
   285       // the arrow should not have moved.
   286       var curArrowRect = arrow.getBoundingClientRect();
   287       is_close(curArrowRect.left, origArrowRect.left, "arrow should not have moved");
   288       is_close(curArrowRect.top, origArrowRect.top, "arrow should not have moved up or down");
   289       next();
   290     });
   291   }],
   293   // Tests against the anchor at the right-hand side of the window
   294   ['afterend', 'right', function(next) {
   295     openPopup("after_end", function() {
   296       // when we request too far to the right/bottom, the panel gets shrunk
   297       // and moved.  The amount it is shrunk by is how far it is moved.
   298       var panelRect = panel.getBoundingClientRect();
   299       // panel was requested 100px wide - calc offset based on actual width.
   300       var offset = panelRect.width - 100;
   301       isArrowPositionedOn("right", offset);
   302       next();
   303     });
   304   }],
   306   ['after_start', 'right', function(next) {
   307     openPopup("after_start", function() {
   308       // See above - we are still too far to the right, but the anchor is
   309       // on the other side.
   310       var panelRect = panel.getBoundingClientRect();
   311       var offset = panelRect.width - 100;
   312       isArrowPositionedOn("right", offset);
   313       next();
   314     });
   315   }],
   317   // Tests against the anchor at the left-hand side of the window
   318   ['after_start', 'left', function(next) {
   319     openPopup("after_start", function() {
   320       var panelRect = panel.getBoundingClientRect();
   321       is(panelRect.left, 0, "panel remains within the screen");
   322       // not sure how to determine the offset here, so given we have checked
   323       // the panel is as left as possible while still being inside the window,
   324       // we just don't check the offset.
   325       isArrowPositionedOn("left", null);
   326       next();
   327     });
   328   }],
   329 ]
   331 function runTests() {
   332   var testIter = Iterator(tests);
   333   function runNextTest() {
   334     let name, anchorPos, test;
   335     try {
   336       let index;
   337       [index, [name, anchorPos, test]] = testIter.next();
   338     } catch (err if err instanceof StopIteration) {
   339       // out of tests
   340       panel.hidePopup();
   341       SimpleTest.finish();
   342       return;
   343     }
   344     SimpleTest.info("sub-test " + anchorPos + "." + name + " starting");
   345     // first arrange for the anchor to be where the test requires it.
   346     panel.hidePopup();
   347     panel.sizeTo(100, 50);
   348     // hide all the anchors here, then later we make one of them visible.
   349     document.getElementById("anchor-left-wrapper").style.display = "none";
   350     document.getElementById("anchor-middle-wrapper").style.display = "none";
   351     document.getElementById("anchor-right-wrapper").style.display = "none";
   352     switch(anchorPos) {
   353       case 'middle':
   354         anchor = document.getElementById("anchor-middle");
   355         document.getElementById("anchor-middle-wrapper").style.display = "block";
   356         break;
   357       case 'left':
   358         anchor = document.getElementById("anchor-left");
   359         document.getElementById("anchor-left-wrapper").style.display = "block";
   360         break;
   361       case 'right':
   362         anchor = document.getElementById("anchor-right");
   363         document.getElementById("anchor-right-wrapper").style.display = "block";
   364         break;
   365       default:
   366         SimpleTest.ok(false, "Bad anchorPos: " + anchorPos);
   367         runNextTest();
   368         return;
   369     }
   370     try {
   371       test(runNextTest);
   372     } catch (ex) {
   373       SimpleTest.ok(false, "sub-test " + anchorPos + "." + name + " failed: " + ex.toString() + "\n" + ex.stack);
   374       runNextTest();
   375     }
   376   }
   377   runNextTest();
   378 }
   380 SimpleTest.waitForExplicitFinish();
   382 addEventListener("load", function() {
   383   // anchor is set by the test runner above
   384   panel = document.getElementById("testPanel");
   385   arrow = SpecialPowers.wrap(document).getAnonymousElementByAttribute(panel, "anonid", "arrow");
   386   // Cancel the arrow panel slide-in transition (bug 767133) so the size and
   387   // position are "stable" enough to test without jumping through hoops...
   388   arrow.style.transition = "none";
   389   runTests();
   390 });
   392 ]]>
   393 </script>
   395 <body xmlns="http://www.w3.org/1999/xhtml">
   396 <!-- Our tests assume at least 100px around the anchor on all sides, else the
   397      panel may flip when we don't expect it to
   398 -->
   399 <div id="anchor-middle-wrapper" style="margin: 100px 100px 100px 100px;">
   400   <p>The anchor --&gt; <span id="anchor-middle">v</span> &lt;--</p>
   401 </div>
   402 <div id="anchor-left-wrapper" style="text-align: left; display: none;">
   403   <p><span id="anchor-left">v</span> &lt;-- The anchor;</p>
   404 </div>
   405 <div id="anchor-right-wrapper" style="text-align: right; display: none;">
   406   <p>The anchor --&gt; <span id="anchor-right">v</span></p>
   407 </div>
   408 </body>
   410 </window>

mercurial