Source code
Revision control
Copy as Markdown
Other Tools
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width; initial-scale=1.0">
  <title>Exercising the slider.snapMultiplier code</title>
  <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
  <script type="application/javascript" src="apz_test_utils.js"></script>
  <script src="/tests/SimpleTest/paint_listener.js"></script>
</head>
<body>
  <div id="scrollable" style="width: 300px; height: 300px; overflow: auto">
    <div id="filler" style="height: 2000px; background-image: linear-gradient(red,blue)"></div>
  </div>
</body>
<script type="text/javascript">
async function test() {
  // Note that this pref is a read-once-on-startup pref so we can't change it
  // and have the change take effect. Instead we just use the value to determine
  // what the expected behaviour is.
  var snapMultiplier = SpecialPowers.getIntPref("slider.snapMultiplier");
  // Much of the code below is "inlined" from promiseVerticalScrollbarDrag. Reusing
  // that code was nontrivial given the modifications we needed to make, and
  // would have increased the complexity of that helper function more than I'd
  // like. However if any bugfixes are made to that function this code might
  // need to be updated as well.
  var scrollableDiv = document.getElementById("scrollable");
  var boundingClientRect = scrollableDiv.getBoundingClientRect();
  var verticalScrollbarWidth = boundingClientRect.width - scrollableDiv.clientWidth;
  if (verticalScrollbarWidth == 0) {
    ok(true, "No scrollbar, can't do this test");
    return;
  }
  // register a scroll listener for the initial drag
  let scrollPromise = new Promise(resolve => {
    scrollableDiv.addEventListener("scroll", resolve, {once: true});
  });
  var upArrowHeight = verticalScrollbarWidth; // assume square scrollbar buttons
  var mouseX = scrollableDiv.clientWidth + (verticalScrollbarWidth / 2);
  var mouseY = upArrowHeight + 5; // start dragging somewhere in the thumb
  dump("Starting drag at " + mouseX + ", " + mouseY + " from top-left of #" + scrollableDiv.id + "\n");
  // Move the mouse to the scrollbar thumb and drag it down
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousedown",
  });
  // drag down by 100 pixels
  mouseY += 100;
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });
  // wait here until the scroll event listener is triggered.
  await scrollPromise;
  var savedScrollPos = scrollableDiv.scrollTop;
  ok(savedScrollPos > 0, "Scrolled to " + savedScrollPos);
  // register a new scroll event listener. The next mousemove below will either
  // trigger the snapback behaviour (if snapMultiplier > 0) or trigger a vertical
  // scroll (if snapMultiplier == 0) because of the x- and y-coordinates we move
  // the mouse to. This allows us to wait for a scroll event in either case.
  // If we only triggered the snapback case then waiting for the scroll to
  // "not happen" in the other case would be more error-prone.
  scrollPromise = new Promise(resolve => {
    scrollableDiv.addEventListener("scroll", resolve, {once: true});
  });
  // Add 2 to snapMultipler just to make sure we get far enough away from the scrollbar
  var snapBackDistance = (snapMultiplier + 2) * verticalScrollbarWidth;
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX + snapBackDistance,
    offsetY: mouseY + 10,
    type: "mousemove",
  });
  // wait here until the scroll happens
  await scrollPromise;
  if (snapMultiplier > 0) {
    ok(scrollableDiv.scrollTop == 0, "Scroll position snapped back to " + scrollableDiv.scrollTop);
  } else {
    ok(scrollableDiv.scrollTop > savedScrollPos, "Scroll position increased to " + scrollableDiv.scrollTop);
  }
  // Now we move the mouse back to the old position to ensure the scroll position
  // gets restored properly
  scrollPromise = new Promise(resolve => {
    scrollableDiv.addEventListener("scroll", resolve, {once: true});
  });
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });
  // wait here until the scroll happens
  await scrollPromise;
  ok(scrollableDiv.scrollTop == savedScrollPos, "Scroll position was restored to " + scrollableDiv.scrollTop);
  // Release mouse and ensure the scroll position stuck
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mouseup",
  });
  // Flush everything just to be safe
  await promiseOnlyApzControllerFlushed();
  ok(scrollableDiv.scrollTop == savedScrollPos, "Final scroll position was " + scrollableDiv.scrollTop);
}
waitUntilApzStable()
.then(test)
.then(subtestDone, subtestFailed);
</script>
</html>