/* global QUnit, $, TouchUtil, Util, testLog */ (function () { var viewer; var sleep = time => new Promise(res => setTimeout(res, time)); QUnit.module( 'Events', { beforeEach: function () { $( '
' ).appendTo( "#qunit-fixture" ); testLog.reset(); // eslint-disable-next-line new-cap viewer = OpenSeadragon( { id: 'eventsexample', prefixUrl: '/build/openseadragon/images/', springStiffness: 100 // Faster animation = faster tests } ); }, afterEach: function () { if ( viewer && viewer.close ) { viewer.close(); } viewer = null; } } ); // ---------- QUnit.test( 'MouseTracker: mouse gestures', function (assert) { var done = assert.async(); var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ), simEvent = {}, offset = $canvas.offset(), tracker = viewer.innerTracker, origEnterHandler, origLeaveHandler, origPressHandler, origReleaseHandler, origNonPrimaryPressHandler, origNonPrimaryReleaseHandler, origMoveHandler, origClickHandler, origDblClickHandler, origDragHandler, origDragEndHandler, enterCount, leaveCount, pressCount, releaseCount, rightPressCount, rightReleaseCount, middlePressCount, middleReleaseCount, moveCount, clickCount, dblClickCount, dragCount, dragEndCount, insideElementPressed, insideElementReleased, quickClick, speed, direction; var hookViewerHandlers = function () { origEnterHandler = tracker.enterHandler; tracker.enterHandler = function ( event ) { enterCount++; if (origEnterHandler) { return origEnterHandler( event ); } else { return true; } }; origLeaveHandler = tracker.leaveHandler; tracker.leaveHandler = function ( event ) { leaveCount++; if (origLeaveHandler) { return origLeaveHandler( event ); } else { return true; } }; origPressHandler = tracker.pressHandler; tracker.pressHandler = function ( event ) { pressCount++; if (origPressHandler) { return origPressHandler( event ); } else { return true; } }; origReleaseHandler = tracker.releaseHandler; tracker.releaseHandler = function ( event ) { releaseCount++; insideElementPressed = event.insideElementPressed; insideElementReleased = event.insideElementReleased; if (origReleaseHandler) { return origReleaseHandler( event ); } else { return true; } }; origNonPrimaryPressHandler = tracker.nonPrimaryPressHandler; tracker.nonPrimaryPressHandler = function ( event ) { if (event.button === 0) { pressCount++; } else if (event.button === 1) { middlePressCount++; } else if (event.button === 2) { rightPressCount++; } if (origNonPrimaryPressHandler) { return origNonPrimaryPressHandler( event ); } else { return true; } }; origNonPrimaryReleaseHandler = tracker.nonPrimaryReleaseHandler; tracker.nonPrimaryReleaseHandler = function ( event ) { if (event.button === 0) { releaseCount++; } else if (event.button === 1) { middleReleaseCount++; } else if (event.button === 2) { rightReleaseCount++; } if (origNonPrimaryReleaseHandler) { return origNonPrimaryReleaseHandler( event ); } else { return true; } }; origMoveHandler = tracker.moveHandler; tracker.moveHandler = function ( event ) { moveCount++; if (origMoveHandler) { return origMoveHandler( event ); } else { return true; } }; origClickHandler = tracker.clickHandler; tracker.clickHandler = function ( event ) { clickCount++; quickClick = event.quick; if (origClickHandler) { return origClickHandler( event ); } else { return true; } }; origDblClickHandler = tracker.dblClickHandler; tracker.dblClickHandler = function ( event ) { dblClickCount++; if (origDblClickHandler) { return origDblClickHandler( event ); } else { return true; } }; origDragHandler = tracker.dragHandler; tracker.dragHandler = function ( event ) { dragCount++; if (origDragHandler) { return origDragHandler( event ); } else { return true; } }; origDragEndHandler = tracker.dragEndHandler; tracker.dragEndHandler = function ( event ) { dragEndCount++; speed = event.speed; direction = event.direction; if (origDragEndHandler) { return origDragEndHandler( event ); } else { return true; } }; }; var unhookViewerHandlers = function () { tracker.enterHandler = origEnterHandler; tracker.leaveHandler = origLeaveHandler; tracker.pressHandler = origPressHandler; tracker.releaseHandler = origReleaseHandler; tracker.moveHandler = origMoveHandler; tracker.clickHandler = origClickHandler; tracker.dblClickHandler = origDblClickHandler; tracker.dragHandler = origDragHandler; tracker.dragEndHandler = origDragEndHandler; }; var simulateEnter = function (x, y) { simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mouseenter', simEvent ); }; var simulateLeave = function (x, y) { simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; simEvent.relatedTarget = document.body; $canvas.simulate( 'mouseleave', simEvent ); }; //var simulateLeaveFrame = function (x, y) { // simEvent.clientX = offset.left + x; // simEvent.clientY = offset.top + y; // simEvent.relatedTarget = document.getElementsByTagName("html")[0]; // $canvas.simulate( 'mouseleave', simEvent ); //}; var simulateDown = function (x, y) { simEvent.button = 0; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mousedown', simEvent ); }; var simulateUp = function (x, y) { simEvent.button = 0; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mouseup', simEvent ); }; var simulateNonPrimaryDown = function (x, y, button) { simEvent.button = button; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mousedown', simEvent ); }; var simulateNonPrimaryUp = function (x, y, button) { simEvent.button = button; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mouseup', simEvent ); }; var simulateMove = function (dX, dY, count) { var i; for ( i = 0; i < count; i++ ) { simEvent.clientX += dX; simEvent.clientY += dY; $canvas.simulate( 'mousemove', simEvent ); } }; var resetForAssessment = function () { simEvent = { button: 0, clientX: offset.left, clientY: offset.top }; enterCount = 0; leaveCount = 0; pressCount = 0; releaseCount = 0; rightPressCount = 0; rightReleaseCount = 0; middlePressCount = 0; middleReleaseCount = 0; moveCount = 0; clickCount = 0; dblClickCount = 0; dragCount = 0; dragEndCount = 0; insideElementPressed = false; insideElementReleased = false; quickClick = false; speed = 0; direction = 2 * Math.PI; }; var assessGestureExpectations = function (expected) { var pointersList = tracker.getActivePointersListByType('mouse'); if ('enterCount' in expected) { assert.equal( enterCount, expected.enterCount, expected.description + 'enterHandler event count matches expected (' + expected.enterCount + ')' ); } if ('leaveCount' in expected) { assert.equal( leaveCount, expected.leaveCount, expected.description + 'leaveHandler event count matches expected (' + expected.leaveCount + ')' ); } if ('pressCount' in expected) { assert.equal( pressCount, expected.pressCount, expected.description + 'pressHandler event count matches expected (' + expected.pressCount + ')' ); } if ('releaseCount' in expected) { assert.equal( releaseCount, expected.releaseCount, expected.description + 'releaseHandler event count matches expected (' + expected.releaseCount + ')' ); } if ('rightPressCount' in expected) { assert.equal( rightPressCount, expected.rightPressCount, expected.description + 'nonPrimaryPressHandler event count (secondary/right button) matches expected (' + expected.rightPressCount + ')' ); } if ('rightReleaseCount' in expected) { assert.equal( rightReleaseCount, expected.rightReleaseCount, expected.description + 'nonPrimaryReleaseHandler event count (secondary/right button) matches expected (' + expected.rightReleaseCount + ')' ); } if ('middlePressCount' in expected) { assert.equal( middlePressCount, expected.middlePressCount, expected.description + 'nonPrimaryPressHandler event count (aux/middle button) matches expected (' + expected.middlePressCount + ')' ); } if ('middleReleaseCount' in expected) { assert.equal( middleReleaseCount, expected.middleReleaseCount, expected.description + 'nonPrimaryReleaseHandler event count (aux/middle button) matches expected (' + expected.middleReleaseCount + ')' ); } if ('moveCount' in expected) { assert.equal( moveCount, expected.moveCount, expected.description + 'moveHandler event count matches expected (' + expected.moveCount + ')' ); } if ('clickCount' in expected) { assert.equal( clickCount, expected.clickCount, expected.description + 'clickHandler event count matches expected (' + expected.clickCount + ')' ); } if ('dblClickCount' in expected) { assert.equal( dblClickCount, expected.dblClickCount, expected.description + 'dblClickHandler event count matches expected (' + expected.dblClickCount + ')' ); } if ('dragCount' in expected) { assert.equal( dragCount, expected.dragCount, expected.description + 'dragHandler event count matches expected (' + expected.dragCount + ')' ); } if ('dragEndCount' in expected) { assert.equal( dragEndCount, expected.dragEndCount, expected.description + 'dragEndHandler event count matches expected (' + expected.dragEndCount + ')' ); } if ('insideElementPressed' in expected) { assert.equal( insideElementPressed, expected.insideElementPressed, expected.description + 'releaseHandler event.insideElementPressed matches expected (' + expected.insideElementPressed + ')' ); } if ('insideElementReleased' in expected) { assert.equal( insideElementReleased, expected.insideElementReleased, expected.description + 'releaseHandler event.insideElementReleased matches expected (' + expected.insideElementReleased + ')' ); } if ('contacts' in expected) { assert.equal( pointersList.contacts, expected.contacts, expected.description + 'Remaining pointer contact count matches expected (' + expected.contacts + ')' ); } if ('trackedPointers' in expected) { assert.equal( pointersList.getLength(), expected.trackedPointers, expected.description + 'Remaining tracked pointer count matches expected (' + expected.trackedPointers + ')' ); } if ('quickClick' in expected) { assert.equal( quickClick, expected.quickClick, expected.description + 'clickHandler event.quick matches expected (' + expected.quickClick + ')' ); } if ('speed' in expected) { Util.assessNumericValue(expected.speed, speed, 1.0, expected.description + 'Drag speed '); } if ('direction' in expected) { Util.assessNumericValue(expected.direction, direction, 0.2, expected.description + 'Drag direction '); } }; var onOpen = function ( event ) { viewer.removeHandler( 'open', onOpen ); hookViewerHandlers(); // enter-move-release (release in tracked element, press in unknown element) // (Note we also test to see if the pointer is still being tracked by not simulating a leave event until after assessment) resetForAssessment(); simulateEnter(0, 0); simulateMove(1, 1, 10); simulateMove(-1, -1, 10); simulateUp(0, 0); assessGestureExpectations({ description: 'enter-move-release (release in tracked element, press in unknown element): ', enterCount: 1, leaveCount: 0, pressCount: 0, releaseCount: 1, rightPressCount: 0, rightReleaseCount: 0, middlePressCount: 0, middleReleaseCount: 0, moveCount: 20, clickCount: 0, dblClickCount: 0, dragCount: 0, dragEndCount: 0, insideElementPressed: false, insideElementReleased: true, contacts: 0, trackedPointers: 1 //quickClick: false }); simulateLeave(-1, -1); // flush tracked pointer // enter-move-leave (fly-over) resetForAssessment(); simulateEnter(0, 0); simulateMove(1, 1, 10); simulateMove(-1, -1, 10); simulateLeave(-1, -1); assessGestureExpectations({ description: 'enter-move-leave (fly-over): ', enterCount: 1, leaveCount: 1, pressCount: 0, releaseCount: 0, rightPressCount: 0, rightReleaseCount: 0, middlePressCount: 0, middleReleaseCount: 0, moveCount: 20, clickCount: 0, dblClickCount: 0, dragCount: 0, dragEndCount: 0, //insideElementPressed: false, //insideElementReleased: false, contacts: 0, trackedPointers: 0 //quickClick: false }); // enter-press-release-press-release-leave (primary/left double click) resetForAssessment(); simulateEnter(0, 0); simulateDown(0, 0); simulateUp(0, 0); simulateDown(0, 0); simulateUp(0, 0); simulateLeave(-1, -1); assessGestureExpectations({ description: 'enter-press-release-press-release-leave (primary/left double click): ', enterCount: 1, leaveCount: 1, pressCount: 2, releaseCount: 2, rightPressCount: 0, rightReleaseCount: 0, middlePressCount: 0, middleReleaseCount: 0, moveCount: 0, clickCount: 2, dblClickCount: 1, dragCount: 0, dragEndCount: 0, // drag-end event no longer fired if pointer didn't move (#2064) insideElementPressed: true, insideElementReleased: true, contacts: 0, trackedPointers: 0 //quickClick: true }); // enter-press-release-leave (primary/left click) resetForAssessment(); simulateEnter(0, 0); simulateDown(0, 0); simulateUp(0, 0); simulateLeave(-1, -1); assessGestureExpectations({ description: 'enter-press-release-leave (primary/left click): ', enterCount: 1, leaveCount: 1, pressCount: 1, releaseCount: 1, rightPressCount: 0, rightReleaseCount: 0, middlePressCount: 0, middleReleaseCount: 0, moveCount: 0, clickCount: 1, dblClickCount: 0, dragCount: 0, dragEndCount: 0, // drag-end event no longer fired if pointer didn't move (#2064) insideElementPressed: true, insideElementReleased: true, contacts: 0, trackedPointers: 0, quickClick: true }); // enter-nonprimarypress-nonprimaryrelease-leave (secondary/right click) resetForAssessment(); simulateEnter(0, 0); simulateNonPrimaryDown(0, 0, 2); simulateNonPrimaryUp(0, 0, 2); simulateLeave(-1, -1); assessGestureExpectations({ description: 'enter-nonprimarypress-nonprimaryrelease-leave (secondary/right click): ', enterCount: 1, leaveCount: 1, pressCount: 0, releaseCount: 0, rightPressCount: 1, rightReleaseCount: 1, middlePressCount: 0, middleReleaseCount: 0, moveCount: 0, clickCount: 0, dblClickCount: 0, dragCount: 0, dragEndCount: 0, //insideElementPressed: true, //insideElementReleased: true, contacts: 0, trackedPointers: 0, //quickClick: true }); // enter-nonprimarypress-nonprimaryrelease-leave (aux/middle click) resetForAssessment(); simulateEnter(0, 0); simulateNonPrimaryDown(0, 0, 1); simulateNonPrimaryUp(0, 0, 1); simulateLeave(-1, -1); assessGestureExpectations({ description: 'enter-nonprimarypress-nonprimaryrelease-leave (aux/middle click): ', enterCount: 1, leaveCount: 1, pressCount: 0, releaseCount: 0, rightPressCount: 0, rightReleaseCount: 0, middlePressCount: 1, middleReleaseCount: 1, moveCount: 0, clickCount: 0, dblClickCount: 0, dragCount: 0, dragEndCount: 0, //insideElementPressed: true, //insideElementReleased: true, contacts: 0, trackedPointers: 0, //quickClick: true }); // enter-nonprimarypress-move-nonprimaryrelease-move-leave (secondary/right button drag, release in tracked element) resetForAssessment(); simulateEnter(0, 0); simulateNonPrimaryDown(0, 0, 2); simulateMove(1, 1, 100); simulateNonPrimaryUp(10, 10, 2); simulateMove(-1, -1, 100); simulateLeave(-1, -1); assessGestureExpectations({ description: 'enter-nonprimarypress-move-nonprimaryrelease-move-leave (secondary/right button drag, release in tracked element): ', enterCount: 1, leaveCount: 1, pressCount: 0, releaseCount: 0, rightPressCount: 1, rightReleaseCount: 1, middlePressCount: 0, middleReleaseCount: 0, moveCount: 200, clickCount: 0, dblClickCount: 0, dragCount: 0, dragEndCount: 0, //insideElementPressed: true, //insideElementReleased: true, contacts: 0, trackedPointers: 0, //quickClick: false }); // enter-press-move-release-move-leave (drag, release in tracked element) resetForAssessment(); simulateEnter(0, 0); simulateDown(0, 0); simulateMove(1, 1, 100); simulateUp(10, 10); simulateMove(-1, -1, 100); simulateLeave(-1, -1); assessGestureExpectations({ description: 'enter-press-move-release-move-leave (drag, release in tracked element): ', enterCount: 1, leaveCount: 1, pressCount: 1, releaseCount: 1, rightPressCount: 0, rightReleaseCount: 0, middlePressCount: 0, middleReleaseCount: 0, moveCount: 200, clickCount: 1, dblClickCount: 0, dragCount: 100, dragEndCount: 1, insideElementPressed: true, insideElementReleased: true, contacts: 0, trackedPointers: 0, quickClick: false }); // enter-press-move-leave-move-release (drag, release outside tracked element) resetForAssessment(); simulateEnter(0, 0); simulateDown(0, 0); simulateMove(1, 1, 5); simulateMove(-1, -1, 5); simulateLeave(-1, -1); simulateMove(-1, -1, 5); simulateUp(-5, -5); assessGestureExpectations({ description: 'enter-press-move-leave-move-release (drag, release outside tracked element): ', enterCount: 1, leaveCount: 1, pressCount: 1, releaseCount: 1, rightPressCount: 0, rightReleaseCount: 0, middlePressCount: 0, middleReleaseCount: 0, moveCount: 15, clickCount: 0, dblClickCount: 0, dragCount: 15, dragEndCount: 1, insideElementPressed: true, insideElementReleased: false, contacts: 0, trackedPointers: 0, quickClick: false }); //// enter-press-move-leave-move-release-outside (drag, release outside iframe) //resetForAssessment(); //simulateEnter(0, 0); //simulateDown(0, 0); //simulateMove(1, 1, 5); //simulateMove(-1, -1, 5); //simulateLeaveFrame(-1, -1); //// you don't actually receive the mouseup if you mouseup outside of the document //assessGestureExpectations({ // description: 'enter-press-move-leave-move-release-outside (drag, release outside iframe): ', // enterCount: 1, // leaveCount: 1, // pressCount: 1, // releaseCount: 1, // rightPressCount: 0, // rightReleaseCount: 0, // middlePressCount: 0, // middleReleaseCount: 0, // moveCount: 10, // clickCount: 0, // dblClickCount: 0, // dragCount: 10, // dragEndCount: 1, // insideElementPressed: true, // insideElementReleased: false, // contacts: 0, // trackedPointers: 0, // quickClick: false //}); unhookViewerHandlers(); viewer.close(); done(); }; viewer.addHandler( 'open', onOpen ); viewer.open( '/test/data/testpattern.dzi' ); } ); // ---------- if ('TouchEvent' in window) { QUnit.test( 'MouseTracker: touch events', function (assert) { var done = assert.async(); var tracker = viewer.innerTracker, touches; var reset = function () { touches = []; TouchUtil.reset(); }; var assessTouchExpectations = function ( expected ) { var pointersList = tracker.getActivePointersListByType( 'touch' ); if ('captureCount' in expected) { assert.equal( pointersList.captureCount, expected.captureCount, expected.description + 'Pointer capture count matches expected (' + expected.captureCount + ')' ); } if ('contacts' in expected) { assert.equal( pointersList.contacts, expected.contacts, expected.description + 'Pointer contact count matches expected (' + expected.contacts + ')' ); } if ('trackedPointers' in expected) { assert.equal( pointersList.getLength(), expected.trackedPointers, expected.description + 'Tracked pointer count matches expected (' + expected.trackedPointers + ')' ); } }; var onOpen = function ( event ) { viewer.removeHandler( 'open', onOpen ); TouchUtil.initTracker( tracker ); // start-end-end (multi-touch start event) reset(); touches = TouchUtil.start( [0, 0], [20, 20] ); assessTouchExpectations({ description: 'start-end-end (multi-touch start event) [capture]: ', captureCount: 2, contacts: 2, trackedPointers: 2 }); TouchUtil.end( touches[1] ); TouchUtil.end( touches[0] ); assessTouchExpectations({ description: 'start-end-end (multi-touch start event) [release]: ', captureCount: 0, contacts: 0, trackedPointers: 0 }); // start-start-end (multi-touch end event) reset(); touches.push( TouchUtil.start([0, 0]) ); touches.push( TouchUtil.start([20, 20]) ); assessTouchExpectations({ description: 'start-start-end (multi-touch end event) [capture]: ', captureCount: 2, contacts: 2, trackedPointers: 2 }); TouchUtil.end( touches ); assessTouchExpectations({ description: 'start-start-end (multi-touch end event) [release]: ', captureCount: 0, contacts: 0, trackedPointers: 0 }); TouchUtil.resetTracker( tracker ); viewer.close(); done(); }; viewer.addHandler( 'open', onOpen ); viewer.open( '/test/data/testpattern.dzi' ); } ); } // ---------- QUnit.test('Viewer: preventDefaultAction', function(assert) { var done = assert.async(); var $canvas = $(viewer.element).find('.openseadragon-canvas') .not('.navigator .openseadragon-canvas'); var epsilon = 0.0000001; function simulateClickAndDrag() { $canvas.simulate('focus'); // Drag to pan Util.simulateViewerClickWithDrag( { viewer: viewer, widthFactor: 0.25, heightFactor: 0.25, dragCount: 10, dragDx: 1, dragDy: 1 } ); // Click to zoom Util.simulateViewerClickWithDrag( { viewer: viewer, widthFactor: 0.25, heightFactor: 0.25, dragCount: 0, dragDx: 0, dragDy: 0 } ); $canvas.simulate('blur'); } var onOpen = function() { viewer.removeHandler('open', onOpen); // Hook viewer events to set preventDefaultAction var onCanvasClick = function (event) { event.preventDefaultAction = true; }; var onCanvasDrag = function (event) { event.preventDefaultAction = true; }; viewer.addHandler("canvas-click", onCanvasClick); viewer.addHandler("canvas-drag", onCanvasDrag); var originalZoom = viewer.viewport.getZoom(); var originalBounds = viewer.viewport.getBounds(); simulateClickAndDrag(); var zoom = viewer.viewport.getZoom(); var bounds = viewer.viewport.getBounds(); Util.assessNumericValue(assert, zoom, originalZoom, epsilon, "Zoom should be prevented"); Util.assertRectangleEquals(assert, bounds, originalBounds, epsilon, 'Pan should be prevented'); viewer.removeHandler("canvas-click", onCanvasClick); viewer.removeHandler("canvas-drag", onCanvasDrag); simulateClickAndDrag(); zoom = viewer.viewport.getZoom(); bounds = viewer.viewport.getBounds(); Util.assessNumericValue(assert, zoom, 0.002, epsilon, "Zoom should not be prevented"); Util.assertRectangleEquals( assert, new OpenSeadragon.Rect(-384.5, -0.25, 500, 0.5), bounds, epsilon, 'Pan should not be prevented'); viewer.close(); done(); }; viewer.addHandler('open', onOpen); viewer.open('/test/data/testpattern.dzi'); }); // ---------- QUnit.test('Viewer: preventDefaultAction in dblClickHandler', function(assert) { var done = assert.async(); var epsilon = 0.0000001; var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ), simEvent = {}, offset = $canvas.offset(); var simulateEnter = function (x, y) { simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mouseenter', simEvent ); }; var simulateLeave = function (x, y) { simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; simEvent.relatedTarget = document.body; $canvas.simulate( 'mouseleave', simEvent ); }; var simulateDown = function (x, y) { simEvent.button = 0; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mousedown', simEvent ); }; var simulateUp = function (x, y) { simEvent.button = 0; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mouseup', simEvent ); }; function simulateDblTap() { simulateEnter(2, 2); simulateDown(2, 2); simulateUp(2, 2); simulateDown(2, 2); simulateUp(2, 2); simulateLeave(-1, -1); } var onOpen = function() { viewer.removeHandler('open', onOpen); var origClickSetting = viewer.gestureSettingsMouse.clickToZoom; var origDblClickSetting = viewer.gestureSettingsMouse.dblClickToZoom; viewer.gestureSettingsMouse.clickToZoom = false; viewer.gestureSettingsMouse.dblClickToZoom = true; var originalZoom = viewer.viewport.getZoom(); var onCanvasDblClick = function (event) { event.preventDefaultAction = true; }; viewer.addHandler('canvas-double-click', onCanvasDblClick); simulateDblTap(); var zoom = viewer.viewport.getZoom(); Util.assessNumericValue(assert, originalZoom, zoom, epsilon, "Zoom on double tap should be prevented"); // Reset event handler to original viewer.removeHandler("canvas-double-click", onCanvasDblClick); simulateDblTap(); originalZoom *= viewer.zoomPerClick; zoom = viewer.viewport.getZoom(); Util.assessNumericValue(assert, originalZoom, zoom, epsilon, "Zoom on double tap should not be prevented"); viewer.gestureSettingsMouse.clickToZoom = origClickSetting; viewer.gestureSettingsMouse.dblClickToZoom = origDblClickSetting; viewer.close(); done(); }; viewer.addHandler('open', onOpen); viewer.open('/test/data/testpattern.dzi'); }); // ---------- QUnit.test( 'EventSource/MouseTracker/Viewer: event.originalEvent event.userData canvas-drag canvas-drag-end canvas-release canvas-click', function (assert) { var done = assert.async(); var $canvas = $( viewer.element ).find( '.openseadragon-canvas' ).not( '.navigator .openseadragon-canvas' ), mouseTracker = null, userData = { item1: 'Test user data', item2: Math.random() }, originalUserData = { item1: userData.item1, item2: userData.item2 }, dragCount = 10, dragsHandledEventSource = 0, dragEndsHandledEventSource = 0, releasesHandledEventSource = 0, clicksHandledEventSource = 0, eventsHandledMouseTracker = 0, eventSourcePassedMouseTracker = 0, originalEventsPassedMouseTracker = 0, eventsHandledViewer = 0, originalEventsPassedViewer = 0, dragEndsExpected = 1, releasesExpected = 1; var checkOriginalEventReceivedViewer = function ( event ) { eventsHandledViewer++; //TODO Provide a better check for the original event...simulate doesn't currently extend the object // with arbitrary user data. if ( event && event.originalEvent ) { originalEventsPassedViewer++; } }; var onEventSourceDrag = function ( event ) { checkOriginalEventReceivedViewer( event ); dragsHandledEventSource++; }; var onEventSourceDragEnd = function ( event ) { checkOriginalEventReceivedViewer( event ); dragEndsHandledEventSource++; }; var onEventSourceRelease = function ( event ) { checkOriginalEventReceivedViewer( event ); releasesHandledEventSource++; }; var onEventSourceClick = function ( event ) { checkOriginalEventReceivedViewer( event ); clicksHandledEventSource++; }; var checkOriginalEventReceived = function ( event ) { eventsHandledMouseTracker++; if ( event && event.eventSource === mouseTracker ) { eventSourcePassedMouseTracker++; } //TODO Provide a better check for the original event...simulate doesn't currently extend the object // with arbitrary user data. if ( event && event.originalEvent ) { originalEventsPassedMouseTracker++; } }; var onMouseTrackerFocus = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerBlur = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerEnter = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerPress = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerMove = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerDrag = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerDragEnd = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerRelease = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerClick = function ( event ) { checkOriginalEventReceived( event ); }; var onMouseTrackerLeave = function ( event ) { checkOriginalEventReceived( event ); mouseTracker.destroy(); viewer.removeHandler( 'canvas-drag', onEventSourceDrag ); viewer.removeHandler( 'canvas-release', onEventSourceRelease ); viewer.removeHandler( 'canvas-click', onEventSourceClick ); assert.equal( dragsHandledEventSource, dragCount, "'canvas-drag' event count matches 'mousemove' event count (" + dragCount + ")" ); assert.equal( dragEndsHandledEventSource, dragEndsExpected, "'canvas-drag-end' event count matches expected (" + dragEndsExpected + ")" ); assert.equal( releasesHandledEventSource, releasesExpected, "'canvas-release' event count matches expected (" + releasesExpected + ")" ); assert.equal( clicksHandledEventSource, releasesExpected, "'canvas-click' event count matches expected (" + releasesExpected + ")" ); assert.equal( originalEventsPassedViewer, eventsHandledViewer, "Original event received count matches expected (" + eventsHandledViewer + ")" ); assert.equal( eventSourcePassedMouseTracker, eventsHandledMouseTracker, "Event source received count matches expected (" + eventsHandledMouseTracker + ")" ); assert.equal( originalEventsPassedMouseTracker, eventsHandledMouseTracker, "Original event received count matches expected (" + eventsHandledMouseTracker + ")" ); assert.deepEqual( event.userData, originalUserData, 'MouseTracker userData was untouched' ); viewer.close(); done(); }; var onOpen = function ( ) { viewer.removeHandler( 'open', onOpen ); viewer.addHandler( 'canvas-drag', onEventSourceDrag ); viewer.addHandler( 'canvas-drag-end', onEventSourceDragEnd ); viewer.addHandler( 'canvas-release', onEventSourceRelease ); viewer.addHandler( 'canvas-click', onEventSourceClick ); mouseTracker = new OpenSeadragon.MouseTracker( { element: $canvas[0], userData: userData, clickTimeThreshold: OpenSeadragon.DEFAULT_SETTINGS.clickTimeThreshold, clickDistThreshold: OpenSeadragon.DEFAULT_SETTINGS.clickDistThreshold, dblClickTimeThreshold: OpenSeadragon.DEFAULT_SETTINGS.dblClickTimeThreshold, dblClickDistThreshold: OpenSeadragon.DEFAULT_SETTINGS.dblClickDistThreshold, focusHandler: onMouseTrackerFocus, blurHandler: onMouseTrackerBlur, enterHandler: onMouseTrackerEnter, pressHandler: onMouseTrackerPress, moveHandler: onMouseTrackerMove, dragHandler: onMouseTrackerDrag, dragEndHandler: onMouseTrackerDragEnd, releaseHandler: onMouseTrackerRelease, clickHandler: onMouseTrackerClick, leaveHandler: onMouseTrackerLeave } ); var event = { clientX: 1, clientY: 1 }; $canvas.simulate( 'focus', event ); Util.simulateViewerClickWithDrag( { viewer: viewer, widthFactor: 0.25, heightFactor: 0.25, dragCount: dragCount, dragDx: 1, dragDy: 1 } ); $canvas.simulate( 'blur', event ); }; viewer.addHandler( 'open', onOpen ); viewer.open( '/test/data/testpattern.dzi' ); } ); // ---------- QUnit.test( 'EventSource: addHandler without userData', function (assert) { var done = assert.async(); var openHandler = function ( event ) { viewer.removeHandler( 'open', openHandler ); assert.ok( event, 'Event handler received event data' ); if ( event ) { assert.strictEqual( event.eventSource, viewer, 'eventSource sent, eventSource is viewer' ); assert.strictEqual( event.userData, null, 'User data defaulted to null' ); } viewer.close(); done(); }; viewer.addHandler( 'open', openHandler ); viewer.open( '/test/data/testpattern.dzi' ); } ); // ---------- QUnit.test( 'EventSource: addHandler with userData', function (assert) { var done = assert.async(); var userData = { item1: 'Test user data', item2: Math.random() }, originalUserData = { item1: userData.item1, item2: userData.item2 }; var openHandler = function ( event ) { viewer.removeHandler( 'open', openHandler ); assert.ok( event, 'Event handler received event data' ); assert.ok( event && event.userData, 'Event handler received user data' ); if ( event && event.userData ) { assert.deepEqual( event.userData, originalUserData, 'User data was untouched' ); } viewer.close(); done(); }; viewer.addHandler( 'open', openHandler, userData ); viewer.open( '/test/data/testpattern.dzi' ); } ); // ---------- QUnit.test('EventSource: addOnceHandler', function(assert) { var eventSource = new OpenSeadragon.EventSource(); var userData = 'data'; var eventData = { foo: 1 }; var handlerCalledCount = 0; eventSource.addOnceHandler('test-event', function(event) { handlerCalledCount++; assert.strictEqual(event.foo, eventData.foo, 'Event data should be transmitted to the event.'); assert.strictEqual(event.userData, userData, 'User data should be transmitted to the event.'); }, userData); assert.strictEqual(0, handlerCalledCount, 'Handler should not have been called yet.'); eventSource.raiseEvent('test-event', eventData); assert.strictEqual(1, handlerCalledCount, 'Handler should have been called once.'); eventSource.raiseEvent('test-event', eventData); assert.strictEqual(1, handlerCalledCount, 'Handler should still have been called once.'); }); // ---------- QUnit.test('EventSource: addOnceHandler 2 times', function(assert) { var eventSource = new OpenSeadragon.EventSource(); var userData = 'data'; var eventData = { foo: 1 }; var handlerCalledCount = 0; eventSource.addOnceHandler('test-event', function(event) { handlerCalledCount++; assert.strictEqual(event.foo, eventData.foo, 'Event data should be transmitted to the event.'); assert.strictEqual(event.userData, userData, 'User data should be transmitted to the event.'); }, userData, 2); assert.strictEqual(0, handlerCalledCount, 'Handler should not have been called yet.'); eventSource.raiseEvent('test-event', eventData); assert.strictEqual(1, handlerCalledCount, 'Handler should have been called once.'); eventSource.raiseEvent('test-event', eventData); assert.strictEqual(2, handlerCalledCount, 'Handler should have been called twice.'); eventSource.raiseEvent('test-event', eventData); assert.strictEqual(2, handlerCalledCount, 'Handler should still have been called twice.'); }); // ---------- QUnit.test( 'Viewer: event count test with \'tile-drawing\'', function (assert) { var done = assert.async(); assert.ok(viewer.numberOfHandlers('tile-drawing') === 0, "'tile-drawing' event is empty by default."); var tileDrawing = function ( event ) { viewer.removeHandler( 'tile-drawing', tileDrawing ); assert.ok(viewer.numberOfHandlers('tile-drawing') === 0, "'tile-drawing' deleted: count is 0."); viewer.close(); done(); }; var tileDrawingDummy = function ( event ) {}; viewer.addHandler( 'tile-drawing', tileDrawing ); assert.ok(viewer.numberOfHandlers('tile-drawing') === 1, "'tile-drawing' event set to 1."); viewer.addHandler( 'tile-drawing', tileDrawingDummy ); assert.ok(viewer.numberOfHandlers('tile-drawing') === 2, "'tile-drawing' event set to 2."); viewer.removeHandler( 'tile-drawing', tileDrawingDummy ); assert.ok(viewer.numberOfHandlers('tile-drawing') === 1, "'tile-drawing' deleted once: count is 1."); viewer.open( '/test/data/testpattern.dzi' ); } ); QUnit.test( 'Viewer: tile-drawing event', function (assert) { var done = assert.async(); var tileDrawing = function ( event ) { viewer.removeHandler( 'tile-drawing', tileDrawing ); assert.ok( event, 'Event handler should be invoked' ); if ( event ) { // Make sure we have the expected elements set assert.ok(event.context, "Context should be set"); assert.ok(event.tile, "Tile should be set"); assert.ok(event.rendered, "Rendered should be set"); } viewer.close(); done(); }; viewer.addHandler( 'tile-drawing', tileDrawing ); viewer.open( '/test/data/testpattern.dzi' ); } ); // tile-loaded event tests QUnit.test( 'Viewer: tile-loaded event without callback.', function (assert) { var done = assert.async(); function tileLoaded ( event ) { viewer.removeHandler( 'tile-loaded', tileLoaded); var tile = event.tile; assert.ok( tile.loading, "The tile should be marked as loading."); assert.notOk( tile.loaded, "The tile should not be marked as loaded."); //make sure we require tile loaded status once the data is ready event.promise.then(function() { assert.notOk( tile.loading, "The tile should not be marked as loading."); assert.ok( tile.loaded, "The tile should be marked as loaded."); done(); }); } viewer.addHandler( 'tile-loaded', tileLoaded); viewer.open( '/test/data/testpattern.dzi' ); } ); QUnit.test( 'Viewer: tile-loaded event with 1 callback.', function (assert) { var done = assert.async(); function tileLoaded ( event ) { viewer.removeHandler( 'tile-loaded', tileLoaded); var tile = event.tile; assert.ok( tile.loading, "The tile should be marked as loading."); assert.notOk( tile.loaded, "The tile should not be marked as loaded."); event.promise.then( _ => { assert.notOk( tile.loading, "The tile should not be marked as loading."); assert.ok( tile.loaded, "The tile should be marked as loaded."); done(); }); } viewer.addHandler( 'tile-loaded', tileLoaded); viewer.open( '/test/data/testpattern.dzi' ); } ); QUnit.test( 'Viewer: asynchronous tile processing.', function (assert) { var done = assert.async(), handledOnce = false; const tileLoaded1 = async (event) => { assert.ok( handledOnce, "tileLoaded1 with priority 5 should be called second."); const tile = event.tile; handledOnce = true; assert.ok( tile.loading, "The tile should be marked as loading."); assert.notOk( tile.loaded, "The tile should not be marked as loaded."); event.promise.then(() => { assert.notOk( tile.loading, "The tile should not be marked as loading."); assert.ok( tile.loaded, "The tile should be marked as loaded."); done(); done = null; }); await sleep(10); }; const tileLoaded2 = async (event) => { assert.notOk( handledOnce, "TileLoaded2 with priority 10 should be called first."); const tile = event.tile; //remove handlers immediatelly, processing is async -> removing in the second function could //get after a different tile gets processed viewer.removeHandler( 'tile-loaded', tileLoaded1); viewer.removeHandler( 'tile-loaded', tileLoaded2); handledOnce = true; assert.ok( tile.loading, "The tile should be marked as loading."); assert.notOk( tile.loaded, "The tile should not be marked as loaded."); event.promise.then(() => { assert.notOk( tile.loading, "The tile should not be marked as loading."); assert.ok( tile.loaded, "The tile should be marked as loaded."); }); await sleep(30); }; //first will get called tileLoaded2 although registered later viewer.addHandler( 'tile-loaded', tileLoaded1, null, 5); viewer.addHandler( 'tile-loaded', tileLoaded2, null, 10); viewer.open( '/test/data/testpattern.dzi' ); } ); QUnit.test( 'Viewer: tile-unloaded event.', function(assert) { var tiledImage; var tiles = []; var done = assert.async(); function tileLoaded( event ) { tiledImage = event.tiledImage; tiles.push(event.tile); if (tiles.length === 1) { setTimeout(function() { tiledImage.reset(); }, 0); } } function tileUnloaded( event ) { viewer.removeHandler( 'tile-loaded', tileLoaded); viewer.removeHandler( 'tile-unloaded', tileUnloaded ); assert.equal( tiles.find(t => t === event.tile), event.tile, "The unloaded tile should be one of the loaded tiles." ); assert.equal( tiledImage, event.tiledImage, "The tiledImage of the unloaded tile should be the same than the one of the loaded one." ); done(); } viewer.addHandler( 'tile-loaded', tileLoaded ); viewer.addHandler( 'tile-unloaded', tileUnloaded ); viewer.open( '/test/data/testpattern.dzi' ); } ); } )();