text: // Copyright 2009 The Closure Library Authors. All Rights Reserved.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS-IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  goog.provide('goog.events.MouseWheelHandlerTest');
  goog.setTestOnly('goog.events.MouseWheelHandlerTest');
  
  goog.require('goog.dom');
  goog.require('goog.events');
  goog.require('goog.events.BrowserEvent');
  goog.require('goog.events.MouseWheelEvent');
  goog.require('goog.events.MouseWheelHandler');
  goog.require('goog.functions');
  goog.require('goog.string');
  goog.require('goog.testing.PropertyReplacer');
  goog.require('goog.testing.events');
  goog.require('goog.testing.jsunit');
  goog.require('goog.userAgent');
  
  var log;
  var stubs = new goog.testing.PropertyReplacer();
  
  var DEFAULT_TYPE = 'mousewheel';
  var GECKO_TYPE = 'DOMMouseScroll';
  
  var HORIZONTAL = 'h';
  var VERTICAL = 'v';
  
  var mouseWheelEvent;
  var mouseWheelEventRtl;
  var mouseWheelHandler;
  var mouseWheelHandlerRtl;
  
  function setUpPage() {
    log = goog.dom.getElement('log');
  }
  
  function setUp() {
    stubs.remove(goog, 'userAgent');
  }
  
  function tearDown() {
    stubs.reset();
    goog.dispose(mouseWheelHandler);
    goog.dispose(mouseWheelHandlerRtl);
    mouseWheelHandlerRtl = null;
    mouseWheelHandler = null;
    mouseWheelEvent = null;
    mouseWheelEventRtl = null;
  }
  
  function tearDownPage() {
    // Create interactive demo.
    mouseWheelHandler = new goog.events.MouseWheelHandler(document.body);
  
    goog.events.listen(
        mouseWheelHandler, goog.events.MouseWheelHandler.EventType.MOUSEWHEEL,
        function(e) {
          log.innerHTML += goog.string.subs(
              '<br />(deltaX, deltaY): (%s, %s)', e.deltaX, e.deltaY);
        });
  }
  
  function testIeStyleMouseWheel() {
    goog.userAgent = {OPERA: false, IE: true, GECKO: false, WEBKIT: false};
  
    createHandlerAndListen();
  
    // Non-gecko, non-webkit events get wheelDelta divided by -40 to get detail.
    handleEvent(createFakeMouseWheelEvent(DEFAULT_TYPE, 120));
    assertMouseWheelEvent(-3, 0, -3);
  
    handleEvent(createFakeMouseWheelEvent(DEFAULT_TYPE, -120));
    assertMouseWheelEvent(3, 0, 3);
  
    handleEvent(createFakeMouseWheelEvent(DEFAULT_TYPE, 1200));
    assertMouseWheelEvent(-30, 0, -30);
  }
  
  function testNullBody() {
    goog.userAgent = {OPERA: false, IE: true, GECKO: false, WEBKIT: false};
    var documentObjectWithNoBody = {};
    goog.testing.events.mixinListenable(documentObjectWithNoBody);
    mouseWheelHandler =
        new goog.events.MouseWheelHandler(documentObjectWithNoBody);
  }
  
  function testGeckoStyleMouseWheel() {
    goog.userAgent = {OPERA: false, IE: false, GECKO: true, WEBKIT: false};
  
    createHandlerAndListen();
  
    handleEvent(createFakeMouseWheelEvent(GECKO_TYPE, null, 3));
    assertMouseWheelEvent(3, 0, 3);
  
    handleEvent(createFakeMouseWheelEvent(GECKO_TYPE, null, -12));
    assertMouseWheelEvent(-12, 0, -12);
  
    // Really big values should get truncated to +-3.
    handleEvent(createFakeMouseWheelEvent(GECKO_TYPE, null, 1200));
    assertMouseWheelEvent(3, 0, 3);
  
    handleEvent(createFakeMouseWheelEvent(GECKO_TYPE, null, -1200));
    assertMouseWheelEvent(-3, 0, -3);
  
    // Test scrolling with the additional axis property.
    handleEvent(createFakeMouseWheelEvent(GECKO_TYPE, null, 3, VERTICAL));
    assertMouseWheelEvent(3, 0, 3);
  
    handleEvent(createFakeMouseWheelEvent(GECKO_TYPE, null, 3, HORIZONTAL));
    assertMouseWheelEvent(3, 3, 0);
  
    handleEvent(createFakeMouseWheelEvent(GECKO_TYPE, null, -3, HORIZONTAL));
    assertMouseWheelEvent(-3, -3, 0);
  }
  
  function testWebkitStyleMouseWheel_ieStyle() {
    goog.userAgent =
        {OPERA: false, IE: false, GECKO: false, WEBKIT: true, WINDOWS: true};
  
    createHandlerAndListen();
  
    // IE-style Webkit events get wheelDelta divided by -40 to get detail.
    handleEvent(createFakeWebkitMouseWheelEvent(-40, 0));
    assertMouseWheelEvent(1, 1, 0);
  
    handleEvent(createFakeWebkitMouseWheelEvent(120, 0));
    assertMouseWheelEvent(-3, -3, 0);
  
    handleEvent(createFakeWebkitMouseWheelEvent(0, 120));
    assertMouseWheelEvent(-3, 0, -3);
  
    handleEvent(createFakeWebkitMouseWheelEvent(0, -40));
    assertMouseWheelEvent(1, 0, 1);
  
    handleEvent(createFakeWebkitMouseWheelEvent(80, -40));
    assertMouseWheelEvent(-2, -2, 1);
  }
  
  function testWebkitStyleMouseWheel_ieStyleOnLinux() {
    goog.userAgent = {
      OPERA: false,
      IE: false,
      GECKO: false,
      WEBKIT: true,
      WINDOWS: false,
      LINUX: true
    };
    runWebKitContinousAndDiscreteEventsTest();
  }
  
  function testWebkitStyleMouseWheel_ieStyleOnMac() {
    goog.userAgent = {
      OPERA: false,
      IE: false,
      GECKO: false,
      WEBKIT: true,
      WINDOWS: false,
      MAC: true
    };
    runWebKitContinousAndDiscreteEventsTest();
  }
  
  function runWebKitContinousAndDiscreteEventsTest() {
    goog.userAgent.isVersionOrHigher = goog.functions.TRUE;
  
    createHandlerAndListen();
  
    // IE-style wheel events.
    handleEvent(createFakeWebkitMouseWheelEvent(0, -40));
    assertMouseWheelEvent(1, 0, 1);
  
    handleEvent(createFakeWebkitMouseWheelEvent(80, -40));
    assertMouseWheelEvent(-2, -2, 1);
  
    // Even in Webkit versions that usually behave in IE style, sometimes wheel
    // events don't behave; this has been observed for instance with Macbook
    // and Chrome OS touchpads in Webkit 534.10+.
    handleEvent(createFakeWebkitMouseWheelEvent(-3, 5));
    assertMouseWheelEvent(-5, 3, -5);
  
    handleEvent(createFakeWebkitMouseWheelEvent(4, -7));
    assertMouseWheelEvent(7, -4, 7);
  }
  
  function testWebkitStyleMouseWheel_nonIeStyle() {
    goog.userAgent =
        {OPERA: false, IE: false, GECKO: false, WEBKIT: true, WINDOWS: false};
  
    goog.userAgent.isVersionOrHigher = goog.functions.FALSE;
  
    createHandlerAndListen();
  
    // non-IE-style Webkit events do not get wheelDelta scaled
    handleEvent(createFakeWebkitMouseWheelEvent(-1, 0));
    assertMouseWheelEvent(1, 1, 0);
  
    handleEvent(createFakeWebkitMouseWheelEvent(3, 0));
    assertMouseWheelEvent(-3, -3, 0);
  
    handleEvent(createFakeWebkitMouseWheelEvent(0, 3));
    assertMouseWheelEvent(-3, 0, -3);
  
    handleEvent(createFakeWebkitMouseWheelEvent(0, -1));
    assertMouseWheelEvent(1, 0, 1);
  
    handleEvent(createFakeWebkitMouseWheelEvent(2, -1));
    assertMouseWheelEvent(-2, -2, 1);
  }
  
  function testMaxDeltaX() {
    goog.userAgent =
        {OPERA: false, IE: false, GECKO: false, WEBKIT: true, WINDOWS: true};
  
    createHandlerAndListen();
  
    // IE-style Webkit events get wheelDelta divided by -40 to get detail.
    handleEvent(createFakeWebkitMouseWheelEvent(-120, 0));
    assertMouseWheelEvent(3, 3, 0);
  
    mouseWheelHandler.setMaxDeltaX(3);
    mouseWheelHandlerRtl.setMaxDeltaX(3);
    handleEvent(createFakeWebkitMouseWheelEvent(-120, 0));
    assertMouseWheelEvent(3, 3, 0);
  
    mouseWheelHandler.setMaxDeltaX(2);
    mouseWheelHandlerRtl.setMaxDeltaX(2);
    handleEvent(createFakeWebkitMouseWheelEvent(-120, 0));
    assertMouseWheelEvent(3, 2, 0);
  
    handleEvent(createFakeWebkitMouseWheelEvent(0, -120));
    assertMouseWheelEvent(3, 0, 3);
  }
  
  function testMaxDeltaY() {
    goog.userAgent =
        {OPERA: false, IE: false, GECKO: false, WEBKIT: true, WINDOWS: true};
  
    createHandlerAndListen();
  
    // IE-style Webkit events get wheelDelta divided by -40 to get detail.
    handleEvent(createFakeWebkitMouseWheelEvent(0, -120));
    assertMouseWheelEvent(3, 0, 3);
  
    mouseWheelHandler.setMaxDeltaY(3);
    mouseWheelHandlerRtl.setMaxDeltaY(3);
    handleEvent(createFakeWebkitMouseWheelEvent(0, -120));
    assertMouseWheelEvent(3, 0, 3);
  
    mouseWheelHandler.setMaxDeltaY(2);
    mouseWheelHandlerRtl.setMaxDeltaY(2);
    handleEvent(createFakeWebkitMouseWheelEvent(0, -120));
    assertMouseWheelEvent(3, 0, 2);
  
    handleEvent(createFakeWebkitMouseWheelEvent(-120, 0));
    assertMouseWheelEvent(3, 3, 0);
  }
  
  // Be sure to call this after setting up goog.userAgent mock and not before.
  function createHandlerAndListen() {
    mouseWheelHandler =
        new goog.events.MouseWheelHandler(goog.dom.getElement('foo'));
  
    goog.events.listen(
        mouseWheelHandler, goog.events.MouseWheelHandler.EventType.MOUSEWHEEL,
        function(e) { mouseWheelEvent = e; });
  
    mouseWheelHandlerRtl =
        new goog.events.MouseWheelHandler(goog.dom.getElement('fooRtl'));
  
    goog.events.listen(
        mouseWheelHandlerRtl, goog.events.MouseWheelHandler.EventType.MOUSEWHEEL,
        function(e) { mouseWheelEventRtl = e; });
  }
  
  function handleEvent(event) {
    mouseWheelHandler.handleEvent(event);
    mouseWheelHandlerRtl.handleEvent(event);
  }
  
  function assertMouseWheelEvent(expectedDetail, expectedDeltaX, expectedDeltaY) {
    assertTrue('event should be non-null', !!mouseWheelEvent);
    assertTrue(
        'event should have correct JS type',
        mouseWheelEvent instanceof goog.events.MouseWheelEvent);
    assertEquals(
        'event should have correct detail property', expectedDetail,
        mouseWheelEvent.detail);
    assertEquals(
        'event should have correct deltaX property', expectedDeltaX,
        mouseWheelEvent.deltaX);
    assertEquals(
        'event should have correct deltaY property', expectedDeltaY,
        mouseWheelEvent.deltaY);
  
    // RTL
    assertTrue('event should be non-null', !!mouseWheelEventRtl);
    assertTrue(
        'event should have correct JS type',
        mouseWheelEventRtl instanceof goog.events.MouseWheelEvent);
    assertEquals(
        'event should have correct detail property', expectedDetail,
        mouseWheelEventRtl.detail);
    assertEquals(
        'event should have correct deltaX property', -expectedDeltaX,
        mouseWheelEventRtl.deltaX);
    assertEquals(
        'event should have correct deltaY property', expectedDeltaY,
        mouseWheelEventRtl.deltaY);
  }
  
  function createFakeMouseWheelEvent(
      type, opt_wheelDelta, opt_detail, opt_axis, opt_wheelDeltaX,
      opt_wheelDeltaY) {
    var event = {
      type: type,
      wheelDelta: goog.isDef(opt_wheelDelta) ? opt_wheelDelta : undefined,
      detail: goog.isDef(opt_detail) ? opt_detail : undefined,
      axis: opt_axis || undefined,
      wheelDeltaX: goog.isDef(opt_wheelDeltaX) ? opt_wheelDeltaX : undefined,
      wheelDeltaY: goog.isDef(opt_wheelDeltaY) ? opt_wheelDeltaY : undefined,
  
      // These two are constants defined on the event in FF3.1 and later.
      // It doesn't matter exactly what they are, and it doesn't affect
      // our simulations of other browsers.
      HORIZONTAL_AXIS: HORIZONTAL,
      VERTICAL_AXIS: VERTICAL
    };
    return new goog.events.BrowserEvent(event);
  }
  
  function createFakeWebkitMouseWheelEvent(wheelDeltaX, wheelDeltaY) {
    return createFakeMouseWheelEvent(
        DEFAULT_TYPE,
        Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY) ? wheelDeltaX : wheelDeltaY,
        undefined, undefined, wheelDeltaX, wheelDeltaY);
  }
  