| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>touchscreen_test</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <script src="test_bootstrap.js"></script> | |
| <script type="text/javascript"> | |
| goog.require('bot.Touchscreen'); | |
| goog.require('bot.action'); | |
| goog.require('bot.dom'); | |
| goog.require('goog.Promise'); | |
| goog.require('goog.events'); | |
| goog.require('goog.events.EventType'); | |
| goog.require('goog.math.Coordinate'); | |
| goog.require('goog.testing.jsunit'); | |
| goog.require('goog.userAgent'); | |
| </script> | |
| <script type="text/javascript"> | |
| var captureTarget; | |
| var target; | |
| var lowerTarget; | |
| var innerCaptureTarget; | |
| var noTouchTarget; | |
| var coordsTarget; | |
| var touchscreen; | |
| var events = []; | |
| var TOUCH_EVENTS = [ | |
| goog.events.EventType.TOUCHSTART, | |
| goog.events.EventType.TOUCHEND, | |
| goog.events.EventType.TOUCHMOVE, | |
| goog.events.EventType.MOUSEMOVE, | |
| goog.events.EventType.MOUSEDOWN, | |
| goog.events.EventType.MOUSEOUT, | |
| goog.events.EventType.MOUSEOVER, | |
| goog.events.EventType.MOUSEUP, | |
| goog.events.EventType.CLICK, | |
| goog.events.EventType.MSPOINTERCANCEL, | |
| goog.events.EventType.MSPOINTERDOWN, | |
| goog.events.EventType.MSPOINTERMOVE, | |
| goog.events.EventType.MSPOINTEROVER, | |
| goog.events.EventType.MSPOINTEROUT, | |
| goog.events.EventType.MSPOINTERUP | |
| ]; | |
| function setUpPage() { | |
| target = document.getElementById('target'); | |
| lowerTarget = document.getElementById('lower'); | |
| captureTarget = document.getElementById('captureTarget'); | |
| innerCaptureTarget = document.getElementById('innerCaptureTarget'); | |
| noTouchTarget = document.getElementById('notouch'); | |
| coordsTarget = document.getElementById('coordsTarget'); | |
| } | |
| function setUp() { | |
| touchscreen = new bot.Touchscreen(); | |
| events = []; | |
| goog.events.removeAll(target); | |
| goog.events.removeAll(lowerTarget); | |
| goog.events.removeAll(captureTarget); | |
| goog.events.removeAll(innerCaptureTarget); | |
| goog.events.removeAll(noTouchTarget); | |
| goog.events.removeAll(coordsTarget); | |
| goog.events.listen(target, TOUCH_EVENTS, function(e) { | |
| events.push(e.type); | |
| events.push(e.target); | |
| if (e.type == goog.events.EventType.TOUCHSTART || | |
| e.type == goog.events.EventType.TOUCHEND || | |
| e.type == goog.events.EventType.TOUCHMOVE) { | |
| var event = e.getBrowserEvent(); | |
| events.push(event.changedTouches.length); | |
| } | |
| }); | |
| goog.events.listen(lowerTarget, TOUCH_EVENTS, function(e) { | |
| events.push(e.type); | |
| events.push(e.target); | |
| }); | |
| goog.events.listen(captureTarget, TOUCH_EVENTS, function(e) { | |
| if (e.type == goog.events.EventType.MSPOINTERDOWN) { | |
| captureTarget.msSetPointerCapture(e.getBrowserEvent().pointerId); | |
| } | |
| events.push(e.type); | |
| events.push(e.target); | |
| }); | |
| goog.events.listen(noTouchTarget, TOUCH_EVENTS, function(e) { | |
| events.push(e.type); | |
| events.push(e.target); | |
| }); | |
| goog.events.listen(coordsTarget, goog.events.EventType.TOUCHSTART, | |
| function(e) { | |
| var event = e.getBrowserEvent(); | |
| if (event.changedTouches.length == 1) { | |
| events.push(event.changedTouches[0].clientX); | |
| events.push(event.changedTouches[0].clientY); | |
| events.push(event.changedTouches[0].pageX); | |
| events.push(event.changedTouches[0].pageY); | |
| } | |
| }); | |
| } | |
| function msPointerDownEvents(elem) { | |
| return [goog.events.EventType.MOUSEMOVE, elem].concat( | |
| [goog.events.EventType.MSPOINTEROVER, elem], | |
| [goog.events.EventType.MOUSEOVER, elem], | |
| [goog.events.EventType.MSPOINTERDOWN, elem], | |
| [goog.events.EventType.MOUSEDOWN, elem]); | |
| } | |
| function msPointerMoveEvents(elem) { | |
| return [goog.events.EventType.MSPOINTERMOVE, elem].concat( | |
| [goog.events.EventType.MOUSEMOVE, elem]); | |
| } | |
| function msPointerUpEventsWithClick(elem) { | |
| return [goog.events.EventType.MSPOINTERUP, elem].concat( | |
| [goog.events.EventType.MOUSEUP, elem], | |
| [goog.events.EventType.CLICK, elem], | |
| [goog.events.EventType.MSPOINTEROUT, elem], | |
| [goog.events.EventType.MOUSEOUT, elem]); | |
| } | |
| function msPointerUpEventsWithoutClick(elem) { | |
| return [goog.events.EventType.MSPOINTERUP, elem].concat( | |
| [goog.events.EventType.MOUSEUP, elem], | |
| [goog.events.EventType.MSPOINTEROUT, elem], | |
| [goog.events.EventType.MOUSEOUT, elem]); | |
| } | |
| function assertEvents(var_args) { | |
| var expectedEvents = goog.array.concat.apply(null, arguments); | |
| assertArrayEquals(expectedEvents, events); | |
| events = []; | |
| } | |
| function testTouchScreenPress() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| assertTrue(touchscreen.isPressed()); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1]); | |
| } | |
| } | |
| function testTouchScreen2FingerPress() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, | |
| new goog.math.Coordinate(0, 0), | |
| new goog.math.Coordinate(10, 10)); | |
| touchscreen.press(/* opt_press2 */ true); | |
| assertTrue(touchscreen.isPressed()); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target), | |
| msPointerDownEvents(target)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 2]); | |
| } | |
| } | |
| function testTouchScreen2FingerPinch() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, | |
| new goog.math.Coordinate(0, 0), | |
| new goog.math.Coordinate(0, 50)); | |
| touchscreen.press(/* opt_press2 */ true); | |
| touchscreen.move(target, | |
| new goog.math.Coordinate(0, 10), | |
| new goog.math.Coordinate(0, 40)); | |
| touchscreen.release(); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target), | |
| msPointerDownEvents(target), | |
| msPointerMoveEvents(target), | |
| msPointerMoveEvents(target), | |
| msPointerUpEventsWithClick(target), | |
| msPointerUpEventsWithClick(target)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 2, | |
| goog.events.EventType.TOUCHMOVE, target, 2, | |
| goog.events.EventType.TOUCHEND, target, 2]); | |
| } | |
| } | |
| function testTouchScreen2FingerPinchReleaseOnNoTouchElement() { | |
| if (!bot.userAgent.IE_DOC_10) { | |
| return; | |
| } | |
| touchscreen.move(noTouchTarget, | |
| new goog.math.Coordinate(0, 0), | |
| new goog.math.Coordinate(0, 50)); | |
| touchscreen.press(/* opt_press2 */ true); | |
| touchscreen.move(noTouchTarget, | |
| new goog.math.Coordinate(0, 10), | |
| new goog.math.Coordinate(0, 40)); | |
| touchscreen.release(); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(noTouchTarget), | |
| [goog.events.EventType.MSPOINTEROUT, noTouchTarget, | |
| goog.events.EventType.MOUSEOUT, noTouchTarget, | |
| goog.events.EventType.MSPOINTERCANCEL, noTouchTarget]); | |
| } | |
| } | |
| function testTouchScreen2FingerRotate() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, | |
| new goog.math.Coordinate(0, 0), | |
| new goog.math.Coordinate(0, 50)); | |
| touchscreen.press(/* opt_press2 */ true); | |
| touchscreen.move(target, new goog.math.Coordinate(10, 40)); | |
| touchscreen.move(target, new goog.math.Coordinate(50, 50)); | |
| touchscreen.release(); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target), | |
| msPointerDownEvents(target), | |
| msPointerMoveEvents(target), | |
| msPointerMoveEvents(target), | |
| msPointerMoveEvents(target), | |
| msPointerMoveEvents(target), | |
| msPointerUpEventsWithClick(target), | |
| msPointerUpEventsWithClick(target)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 2, | |
| goog.events.EventType.TOUCHMOVE, target, 2, | |
| goog.events.EventType.TOUCHMOVE, target, 2, | |
| goog.events.EventType.TOUCHEND, target, 2]); | |
| } | |
| } | |
| function verifyTapEvents(elem) { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(elem, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.release(); | |
| assertFalse(touchscreen.isPressed()); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(elem), | |
| msPointerUpEventsWithClick(elem)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, elem, 1, | |
| goog.events.EventType.TOUCHEND, elem, 1, | |
| goog.events.EventType.MOUSEMOVE, elem, | |
| goog.events.EventType.MOUSEDOWN, elem, | |
| goog.events.EventType.MOUSEUP, elem, | |
| goog.events.EventType.CLICK, elem]); | |
| } | |
| } | |
| function testTouchScreenRelease() { | |
| verifyTapEvents(target); | |
| } | |
| function testTouchScreenReleaseOnNoTouchElement() { | |
| if (!bot.userAgent.IE_DOC_10) { | |
| return; | |
| } | |
| // Tap events should fire normally even if -ms-touch-action == auto. | |
| verifyTapEvents(noTouchTarget); | |
| } | |
| function testTouchScreenReleaseAfterMove() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| // After a move, the mouseclick should not happen. | |
| touchscreen.move(target, new goog.math.Coordinate(10, 10)); | |
| touchscreen.release(); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target), | |
| msPointerMoveEvents(target), | |
| msPointerUpEventsWithClick(target)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1, | |
| goog.events.EventType.TOUCHMOVE, target, 1, | |
| goog.events.EventType.TOUCHEND, target, 1]); | |
| } | |
| } | |
| function testMsSetPointerCapture() { | |
| if (!bot.userAgent.IE_DOC_10) { | |
| return; | |
| } | |
| touchscreen.move(captureTarget, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.move(lowerTarget, new goog.math.Coordinate(10, 10)); | |
| touchscreen.release(); | |
| // The captureTarget calls msSetPointerCapture, so subsequent events | |
| // should fire on captureTarget even after the move to lowerTarget. | |
| assertEvents(msPointerDownEvents(captureTarget), | |
| msPointerMoveEvents(captureTarget), | |
| msPointerUpEventsWithoutClick(captureTarget)); | |
| } | |
| function testBubblingMsSetPointerCapture() { | |
| if (!bot.userAgent.IE_DOC_10) { | |
| return; | |
| } | |
| touchscreen.move(innerCaptureTarget, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.move(lowerTarget, new goog.math.Coordinate(10, 10)); | |
| touchscreen.release(); | |
| // The MSPointerDown event on innerCaptureTarget bubbles up to the | |
| // captureTarget element which calls msSetPointerCapture, so subsequent | |
| // events should fire on captureTarget even after the move to lowerTarget. | |
| assertEvents(msPointerDownEvents(innerCaptureTarget), | |
| msPointerMoveEvents(captureTarget), | |
| msPointerUpEventsWithoutClick(captureTarget)); | |
| } | |
| function testClickDoesNotFireOnCapturedPointer() { | |
| if (!bot.userAgent.IE_DOC_10) { | |
| return; | |
| } | |
| touchscreen.move(innerCaptureTarget, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.move(innerCaptureTarget, new goog.math.Coordinate(10, 10)); | |
| touchscreen.release(); | |
| // After the pointer down event, captureTarget should receive the rest of | |
| // the events except for the click event. | |
| assertEvents(msPointerDownEvents(innerCaptureTarget), | |
| msPointerMoveEvents(captureTarget), | |
| [goog.events.EventType.MSPOINTERUP, captureTarget], | |
| [goog.events.EventType.MOUSEUP, captureTarget], | |
| [goog.events.EventType.CLICK, innerCaptureTarget], | |
| [goog.events.EventType.MSPOINTEROUT, captureTarget], | |
| [goog.events.EventType.MOUSEOUT, captureTarget]); | |
| } | |
| function testTouchScreenReleaseAfterMoveOnNoTouchElement_IE() { | |
| if (!bot.userAgent.IE_DOC_10) { | |
| return; | |
| } | |
| touchscreen.move(noTouchTarget, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.move(noTouchTarget, new goog.math.Coordinate(10, 10)); | |
| touchscreen.move(noTouchTarget, new goog.math.Coordinate(20, 20)); | |
| touchscreen.release(); | |
| // Since the element does not support touch actions, the move triggers | |
| // a pointerout and mouseout events followed by a pointer cancel. | |
| assertEvents(msPointerDownEvents(noTouchTarget), | |
| [goog.events.EventType.MSPOINTEROUT, noTouchTarget, | |
| goog.events.EventType.MOUSEOUT, noTouchTarget, | |
| goog.events.EventType.MSPOINTERCANCEL, noTouchTarget]); | |
| } | |
| function testTouchScreenReleaseAfterNewElement() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| // After moving to a new element, the touchmove and touchend | |
| // events should fire on the element where the touch started. | |
| touchscreen.move(lowerTarget, new goog.math.Coordinate(0, 0)); | |
| touchscreen.release(); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target), | |
| msPointerMoveEvents(lowerTarget), | |
| msPointerUpEventsWithoutClick(lowerTarget)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1, | |
| goog.events.EventType.TOUCHMOVE, target, 1, | |
| goog.events.EventType.TOUCHEND, target, 1]); | |
| } | |
| } | |
| function testTouchScreenMoveWithoutPress() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); | |
| assertFalse(touchscreen.isPressed()); | |
| } | |
| function testTouchScreenMoveWithPress() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.move(target, new goog.math.Coordinate(20, 20)); | |
| assertTrue(touchscreen.isPressed()); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target), | |
| msPointerMoveEvents(target)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1, | |
| goog.events.EventType.TOUCHMOVE, target, 1]); | |
| } | |
| } | |
| function testExceptionReleasingWhenNotPressed() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| assertThrows('Releasing when not pressed should throw an exception', | |
| goog.bind(touchscreen.release, touchscreen)); | |
| } | |
| function testExceptionPressedWhenAlreadyPressed() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| assertThrows('Pressing when already pressed should throw an exception', | |
| goog.bind(touchscreen.press, touchscreen)); | |
| } | |
| function testPreventDefaultOnTouchstart() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| goog.events.listen(target, goog.events.EventType.TOUCHSTART, function(e) { | |
| e.preventDefault(); | |
| }); | |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.release(); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target), | |
| msPointerUpEventsWithClick(target)); | |
| } else { | |
| assertEvents([goog.events.EventType.TOUCHSTART, target, 1, | |
| goog.events.EventType.TOUCHEND, target, 1]); | |
| } | |
| } | |
| function testPreventDefaultOnTouchend() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS) { | |
| return; | |
| } | |
| goog.events.listen(target, goog.events.EventType.TOUCHEND, function(e) { | |
| e.preventDefault(); | |
| }); | |
| touchscreen.move(target, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.release(); | |
| if (bot.userAgent.IE_DOC_10) { | |
| assertEvents(msPointerDownEvents(target), | |
| msPointerUpEventsWithClick(target)); | |
| } else { | |
| var events = [goog.events.EventType.TOUCHSTART, target, 1, | |
| goog.events.EventType.TOUCHEND, target, 1]; | |
| if (!bot.userAgent.IOS && !goog.userAgent.product.CHROME) { | |
| events.push(goog.events.EventType.MOUSEMOVE, target, | |
| goog.events.EventType.MOUSEDOWN, target, | |
| goog.events.EventType.MOUSEUP, target, | |
| goog.events.EventType.CLICK, target); | |
| } | |
| assertEvents(events); | |
| } | |
| } | |
| function testTouchEventCoords() { | |
| if (!bot.events.SUPPORTS_TOUCH_EVENTS || bot.userAgent.IE_DOC_10) { | |
| return; | |
| } | |
| window.scrollTo(20, 30); | |
| // Yield to ensure all browsers apply the scrolling change. | |
| // Relying on the implicit tick in a promise resolution is enough. | |
| return goog.Promise.resolve().then(function() { | |
| var coords = bot.dom.getClientRect(coordsTarget); | |
| touchscreen.move(coordsTarget, new goog.math.Coordinate(0, 0)); | |
| touchscreen.press(); | |
| touchscreen.release(); | |
| // The client coords of the touch event should be the top left of the | |
| // target and the page coords should include the scroll offset. | |
| assertEvents([coords.left, coords.top, | |
| coords.left + 20, coords.top + 30]); | |
| }); | |
| } | |
| </script> | |
| </head> | |
| <body> | |
| TouchScreen Test.<br> | |
| <div id="target" | |
| style="background-color:blue; | |
| width:200px; | |
| height:100px; | |
| -ms-touch-action:none"> | |
| touch here | |
| </div> | |
| <div id="lower" | |
| style="background-color:red; | |
| width:50px; | |
| height:50px; | |
| position relative; | |
| top:25px; | |
| -ms-touch-action:none"> | |
| lower | |
| </div> | |
| <div id="captureTarget" | |
| style="background-color:green; | |
| width:200px; | |
| height:200px; | |
| -ms-touch-action:none"> | |
| ie 10 target | |
| <div id="innerCaptureTarget" | |
| style="background-color:cyan; | |
| width:100px; | |
| height:50px; | |
| -ms-touch-action:none"> | |
| inner ie 10 target | |
| </div> | |
| </div> | |
| <div id="notouch" | |
| style="background-color:green; | |
| width:100px; | |
| height:100px; | |
| position relative; | |
| top:50px; | |
| -ms-touch-action:auto"> | |
| no touch | |
| </div> | |
| <div id="coordsTarget" | |
| style="background-color:magenta; | |
| width:8000px; | |
| height:8000px; | |
| -ms-touch-action:none"> | |
| coords target | |
| </div> | |
| </body> | |
| </html> |