From 69e9326d4f9fc7478fe1543f0f085c2cecbff5b1 Mon Sep 17 00:00:00 2001 From: Adam Carruthers Date: Thu, 4 Dec 2014 17:06:33 -0500 Subject: [PATCH 01/52] fix #500 - requests keyboard focus when canvas is clicked The canvas click listener will now check if keyboard-command-area has focus, and if it does not, it will request it. --- src/viewer.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/viewer.js b/src/viewer.js index 39ed6294..b0ac0e47 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2265,6 +2265,13 @@ function onBlur(){ function onCanvasClick( event ) { var gestureSettings; + var haveKeyboardFocus = document.activeElement == this.keyboardCommandArea; + + // If we don't have keyboard focus, request it. + if ( !haveKeyboardFocus ) { + this.keyboardCommandArea.focus(); + } + if ( !event.preventDefaultAction && this.viewport && event.quick ) { gestureSettings = this.gestureSettingsByDeviceType( event.pointerType ); if ( gestureSettings.clickToZoom ) { From 6e49f802487e0f45aecc25b9d45ecd9e296da47a Mon Sep 17 00:00:00 2001 From: Adam Carruthers Date: Mon, 22 Dec 2014 20:29:44 -0700 Subject: [PATCH 02/52] Prevent mobile keyboard from opening Adds readonly property to .keyboard-command-area to prevent input, but allow keys to be captured. --- src/viewer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/viewer.js b/src/viewer.js index b0ac0e47..1ff4e1c9 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -300,6 +300,8 @@ $.Viewer = function( options ) { style.left = "0px"; style.resize = "none"; }( this.keyboardCommandArea.style )); + // Set read-only - hides keyboard on mobile devices, still allows input. + this.keyboardCommandArea.readOnly = true; this.container.insertBefore( this.canvas, this.container.firstChild ); this.container.insertBefore( this.keyboardCommandArea, this.container.firstChild ); From 8d4c776cd0003382214dc1b189db74c7cf6eb1af Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 30 Dec 2014 12:57:17 -0800 Subject: [PATCH 03/52] MouseTracker fixes for #502, #518, #527, #539 --- src/mousetracker.js | 136 +++++++++++++++++--------------------------- test/events.js | 64 ++++++++++----------- 2 files changed, 85 insertions(+), 115 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 0c865c74..3485c84d 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -193,8 +193,6 @@ mousemove: function ( event ) { onMouseMove( _this, event ); }, mousemovecaptured: function ( event ) { onMouseMoveCaptured( _this, event ); }, - mouseoutdocument: function ( event ) { onMouseOutDocument( _this, event ); }, - touchenter: function ( event ) { onTouchEnter( _this, event ); }, touchleave: function ( event ) { onTouchLeave( _this, event ); }, touchstart: function ( event ) { onTouchStart( _this, event ); }, @@ -210,9 +208,6 @@ pointerout: function ( event ) { onPointerOut( _this, event ); }, MSPointerOut: function ( event ) { onPointerOut( _this, event ); }, - pointeroutdocument: function ( event ) { onPointerOutDocument( _this, event ); }, - MSPointerOutdocument: function ( event ) { onPointerOutDocument( _this, event ); }, - pointerdown: function ( event ) { onPointerDown( _this, event ); }, MSPointerDown: function ( event ) { onPointerDown( _this, event ); }, pointerup: function ( event ) { onPointerUp( _this, event ); }, @@ -797,6 +792,8 @@ // Pointer event model and feature detection /////////////////////////////////////////////////////////////////////////////// + $.MouseTracker.captureElement = document; + /** * Detect available mouse wheel event name. */ @@ -1035,6 +1032,50 @@ // Utility functions /////////////////////////////////////////////////////////////////////////////// + /** + * Removes all tracked pointers. + * @private + * @inner + */ + function clearTrackedPointers( tracker ) { + var delegate = THIS[ tracker.hash ], + i, + pointerListCount = delegate.activePointersLists.length; + + if ( delegate.pointerCaptureCount > 0 ) { + $.removeEvent( + $.MouseTracker.captureElement, + 'mousemove', + delegate.mousemovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'mouseup', + delegate.mouseupcaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + delegate.pointermovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + delegate.pointerupcaptured, + true + ); + + delegate.pointerCaptureCount = 0; + } + + for ( i = 0; i < pointerListCount; i++ ) { + delegate.activePointersLists.pop(); + } + } + /** * Starts tracking pointer events on the tracked element. * @private @@ -1056,14 +1097,7 @@ ); } - // handle pointer/mouse out of document body - if ( window.PointerEvent ) { - $.addEvent(document.body, "pointerout", delegate.pointeroutdocument); - } else if ( window.MSPointerEvent ) { - $.addEvent(document.body, "pointerout", delegate.MSPointerOutdocument); - } else { - $.addEvent(document.body, "mouseout", delegate.mouseoutdocument); - } + clearTrackedPointers( tracker ); delegate.tracking = true; } @@ -1090,14 +1124,7 @@ ); } - // handle pointer/mouse out of document body - if ( window.PointerEvent ) { - $.removeEvent(document.body, "pointerout", delegate.pointeroutdocument); - } else if ( window.MSPointerEvent ) { - $.removeEvent(document.body, "MSPointerOut", delegate.MSPointerOutdocument); - } else { - $.removeEvent(document.body, "mouseout", delegate.mouseoutdocument); - } + clearTrackedPointers( tracker ); delegate.tracking = false; } @@ -1112,19 +1139,18 @@ var delegate = THIS[ tracker.hash ]; delegate.pointerCaptureCount++; - //$.console.log('pointerCaptureCount++ ', delegate.pointerCaptureCount); if ( delegate.pointerCaptureCount === 1 ) { // We emulate mouse capture by hanging listeners on the window object. // (Note we listen on the capture phase so the captured handlers will get called first) $.addEvent( - window, + $.MouseTracker.captureElement, isLegacyMouse ? 'mouseup' : ($.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp'), isLegacyMouse ? delegate.mouseupcaptured : delegate.pointerupcaptured, true ); $.addEvent( - window, + $.MouseTracker.captureElement, isLegacyMouse ? 'mousemove' : ($.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove'), isLegacyMouse ? delegate.mousemovecaptured : delegate.pointermovecaptured, true @@ -1142,19 +1168,18 @@ var delegate = THIS[ tracker.hash ]; delegate.pointerCaptureCount--; - //$.console.log('pointerCaptureCount-- ', delegate.pointerCaptureCount); if ( delegate.pointerCaptureCount === 0 ) { // We emulate mouse capture by hanging listeners on the window object. // (Note we listen on the capture phase so the captured handlers will get called first) $.removeEvent( - window, + $.MouseTracker.captureElement, isLegacyMouse ? 'mousemove' : ($.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove'), isLegacyMouse ? delegate.mousemovecaptured : delegate.pointermovecaptured, true ); $.removeEvent( - window, + $.MouseTracker.captureElement, isLegacyMouse ? 'mouseup' : ($.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp'), isLegacyMouse ? delegate.mouseupcaptured : delegate.pointerupcaptured, true @@ -1481,35 +1506,6 @@ updatePointersExit( tracker, event, [ gPoint ] ); } - /** - * This handler is used to handle the case where the mouse is dragged out of the window, it should cause the drag to be properly released. - * - * @private - * @inner - */ - function onMouseOutDocument( tracker, event ) { - event = $.getEvent( event ); - - var html = document.getElementsByTagName("html")[0]; - var target = event.target || event.srcElement; - if ((event.relatedTarget!==html && event.relatedTarget!==null) || event.currentTarget !== document.body) { - return; // not a mouseout of the iframe - } - - var gPoint = { - id: $.MouseTracker.mousePointerId, - type: 'mouse', - isPrimary: true, - currentPos: getMouseAbsolute( event ), - currentTime: $.now() - }; - - event.buttons = undefined; - - if ( updatePointersUp( tracker, event, [ gPoint ], 0 ) ) { - releasePointer( tracker, true ); - } - } /** * @private @@ -1700,6 +1696,7 @@ if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact // Touch event model start, end, and move events are always captured so we don't need to capture explicitly + $.stopEvent( event ); } $.cancelEvent( event ); @@ -1853,33 +1850,6 @@ updatePointersExit( tracker, event, [ gPoint ] ); } - /** - * This handler is used to handle the case where the pointer is dragged out of the window, it should cause the drag to be properly released. - * - * @private - * @inner - */ - function onPointerOutDocument( tracker, event ) { - event = $.getEvent( event ); - - var html = document.getElementsByTagName("html")[0]; - if ((event.relatedTarget!==html && event.relatedTarget!==null) || event.currentTarget !== document.body) { - return; // not a mouseout of the iframe - } - - var gPoint = { - id: event.pointerId, - type: getPointerType( event ), - isPrimary: event.isPrimary, - currentPos: getMouseAbsolute( event ), - currentTime: $.now() - }; - - if ( updatePointersUp( tracker, event, [ gPoint ], 0 ) ) { - releasePointer( tracker, false ); - } - } - /** * @private * @inner diff --git a/test/events.js b/test/events.js index ba1a36e2..07c14ea6 100644 --- a/test/events.js +++ b/test/events.js @@ -165,13 +165,13 @@ var simulateLeave = function (x, y) { simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; - simEvent.relatedTarget = document.body; - $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); - }; - var simulateLeaveFrame = function (x, y) { - simEvent.clientX = offset.left + x; - simEvent.clientY = offset.top + y; - simEvent.relatedTarget = document.getElementsByTagName("html")[0]; + // simEvent.relatedTarget = document.body; + // $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); + //}; + //var simulateLeaveFrame = function (x, y) { + // simEvent.clientX = offset.left + x; + // simEvent.clientY = offset.top + y; + // simEvent.relatedTarget = document.getElementsByTagName("html")[0]; $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); }; @@ -454,31 +454,31 @@ }); - // enter-press-move-exit-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-exit-move-release-outside (drag, release outside iframe): ', - enterCount: 1, - exitCount: 1, - pressCount: 1, - releaseCount: 1, - moveCount: 10, - clickCount: 0, - dblClickCount: 0, - dragCount: 10, - dragEndCount: 1, - insideElementPressed: true, - insideElementReleased: false, - contacts: 0, - trackedPointers: 0, - quickClick: false - }); + //// enter-press-move-exit-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-exit-move-release-outside (drag, release outside iframe): ', + // enterCount: 1, + // exitCount: 1, + // pressCount: 1, + // releaseCount: 1, + // moveCount: 10, + // clickCount: 0, + // dblClickCount: 0, + // dragCount: 10, + // dragEndCount: 1, + // insideElementPressed: true, + // insideElementReleased: false, + // contacts: 0, + // trackedPointers: 0, + // quickClick: false + //}); unhookViewerHandlers(); viewer.close(); From 3e76bfdd9eae24a212d4dc34a66871faa7290722 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Wed, 31 Dec 2014 11:08:06 -0800 Subject: [PATCH 04/52] Changelog for #518 --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index e77bb84d..4ae3667e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -18,8 +18,8 @@ OPENSEADRAGON CHANGELOG * Viewport.setRotation now allows all rotation angles (#466) * Pinch rotate is now available (defaults to off) (#468) * Added option for home button to fill viewer (#474) -* Now handling iframe/frame mouseouts properly (#481) * Better handling of mid-update image loaded callbacks (#409) +* Tracked pointers are now cleaned up when Viewer.setMouseNavEnabled(false) is called (#518) 1.1.1: From b39d31a8452a26dc1bb57a501d4e6dead5251653 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 31 Dec 2014 14:30:10 -0800 Subject: [PATCH 05/52] MouseTracker - Added explicit pointer capture for touch event model events --- src/mousetracker.js | 210 +++++++++++++++++++++++++++++++------------- 1 file changed, 151 insertions(+), 59 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 3485c84d..8e89e43a 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -170,8 +170,6 @@ * @private * @property {Boolean} tracking * Are we currently tracking pointer events for this element. - * @property {Boolean} capturing - * Are we curruently capturing mouse events (legacy mouse events only). */ THIS[ this.hash ] = { click: function ( event ) { onClick( _this, event ); }, @@ -197,7 +195,9 @@ touchleave: function ( event ) { onTouchLeave( _this, event ); }, touchstart: function ( event ) { onTouchStart( _this, event ); }, touchend: function ( event ) { onTouchEnd( _this, event ); }, + touchendcaptured: function ( event ) { onTouchEndCaptured( _this, event ); }, touchmove: function ( event ) { onTouchMove( _this, event ); }, + touchmovecaptured: function ( event ) { onTouchMoveCaptured( _this, event ); }, touchcancel: function ( event ) { onTouchCancel( _this, event ); }, gesturestart: function ( event ) { onGestureStart( _this, event ); }, @@ -227,12 +227,6 @@ // of the element (for hover-capable devices) and/or have contact or a button press initiated in the element. activePointersLists: [], - // Legacy mouse capture tracking - capturing: false, - - // Pointer event model capture tracking - pointerCaptureCount: 0, - // Tracking for double-click gesture lastClickPos: null, dblClickTimeOut: null, @@ -944,6 +938,12 @@ * @memberof OpenSeadragon.MouseTracker.GesturePointList# */ this.clicks = 0; + /** + * Current number of captured pointers for the device. + * @member {Number} captureCount + * @memberof OpenSeadragon.MouseTracker.GesturePointList# + */ + this.captureCount = 0; }; $.MouseTracker.GesturePointList.prototype = /** @lends OpenSeadragon.MouseTracker.GesturePointList.prototype */{ /** @@ -1042,33 +1042,47 @@ i, pointerListCount = delegate.activePointersLists.length; - if ( delegate.pointerCaptureCount > 0 ) { - $.removeEvent( - $.MouseTracker.captureElement, - 'mousemove', - delegate.mousemovecaptured, - true - ); - $.removeEvent( - $.MouseTracker.captureElement, - 'mouseup', - delegate.mouseupcaptured, - true - ); - $.removeEvent( - $.MouseTracker.captureElement, - $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', - delegate.pointermovecaptured, - true - ); - $.removeEvent( - $.MouseTracker.captureElement, - $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', - delegate.pointerupcaptured, - true - ); + for ( i = 0; i < pointerListCount; i++ ) { + if ( delegate.activePointersLists[ i ].captureCount > 0 ) { + $.removeEvent( + $.MouseTracker.captureElement, + 'mousemove', + delegate.mousemovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'mouseup', + delegate.mouseupcaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + delegate.pointermovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + delegate.pointerupcaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'touchmove', + delegate.touchmovecaptured, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + 'touchend', + delegate.touchendcaptured, + true + ); - delegate.pointerCaptureCount = 0; + delegate.activePointersLists[ i ].captureCount = 0; + } } for ( i = 0; i < pointerListCount; i++ ) { @@ -1130,29 +1144,62 @@ } } + /** + * @private + * @inner + */ + function getCaptureEventParams( tracker, pointerType ) { + var delegate = THIS[ tracker.hash ]; + + if ( pointerType === 'mouse' ) { + return { + upName: 'mouseup', + upHandler: delegate.mouseupcaptured, + moveName: 'mousemove', + moveHandler: delegate.mousemovecaptured + }; + } else if ( pointerType === 'touch' ) { + return { + upName: 'touchend', + upHandler: delegate.touchendcaptured, + moveName: 'touchmove', + moveHandler: delegate.touchmovecaptured + }; + } else { + return { + upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + upHandler: delegate.pointerupcaptured, + moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + moveHandler: delegate.pointermovecaptured + }; + } + } + /** * Begin capturing pointer events to the tracked element. * @private * @inner */ - function capturePointer( tracker, isLegacyMouse ) { - var delegate = THIS[ tracker.hash ]; + function capturePointer( tracker, pointerType ) { + var delegate = THIS[ tracker.hash ], + pointsList = tracker.getActivePointersListByType( pointerType ), + eventParams = getCaptureEventParams( tracker, pointerType ); - delegate.pointerCaptureCount++; + pointsList.captureCount++; - if ( delegate.pointerCaptureCount === 1 ) { + if ( pointsList.captureCount === 1 ) { // We emulate mouse capture by hanging listeners on the window object. // (Note we listen on the capture phase so the captured handlers will get called first) $.addEvent( $.MouseTracker.captureElement, - isLegacyMouse ? 'mouseup' : ($.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp'), - isLegacyMouse ? delegate.mouseupcaptured : delegate.pointerupcaptured, + eventParams.upName, + eventParams.upHandler, true ); $.addEvent( $.MouseTracker.captureElement, - isLegacyMouse ? 'mousemove' : ($.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove'), - isLegacyMouse ? delegate.mousemovecaptured : delegate.pointermovecaptured, + eventParams.moveName, + eventParams.moveHandler, true ); } @@ -1164,24 +1211,26 @@ * @private * @inner */ - function releasePointer( tracker, isLegacyMouse ) { - var delegate = THIS[ tracker.hash ]; + function releasePointer( tracker, pointerType ) { + var delegate = THIS[ tracker.hash ], + pointsList = tracker.getActivePointersListByType( pointerType ), + eventParams = getCaptureEventParams( tracker, pointerType ); - delegate.pointerCaptureCount--; + pointsList.captureCount--; - if ( delegate.pointerCaptureCount === 0 ) { + if ( pointsList.captureCount === 0 ) { // We emulate mouse capture by hanging listeners on the window object. // (Note we listen on the capture phase so the captured handlers will get called first) $.removeEvent( $.MouseTracker.captureElement, - isLegacyMouse ? 'mousemove' : ($.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove'), - isLegacyMouse ? delegate.mousemovecaptured : delegate.pointermovecaptured, + eventParams.moveName, + eventParams.moveHandler, true ); $.removeEvent( $.MouseTracker.captureElement, - isLegacyMouse ? 'mouseup' : ($.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp'), - isLegacyMouse ? delegate.mouseupcaptured : delegate.pointerupcaptured, + eventParams.upName, + eventParams.upHandler, true ); } @@ -1526,7 +1575,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { $.stopEvent( event ); - capturePointer( tracker, true ); + capturePointer( tracker, 'mouse' ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) { @@ -1574,7 +1623,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - releasePointer( tracker, true ); + releasePointer( tracker, 'mouse' ); } } @@ -1695,8 +1744,8 @@ } if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact - // Touch event model start, end, and move events are always captured so we don't need to capture explicitly $.stopEvent( event ); + capturePointer( tracker, 'touch' ); } $.cancelEvent( event ); @@ -1708,6 +1757,28 @@ * @inner */ function onTouchEnd( tracker, event ) { + handleTouchEnd( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate pointer capture. + * onTouchEnd is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onTouchEndCaptured( tracker, event ) { + handleTouchEnd( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleTouchEnd( tracker, event ) { var time, i, touchCount = event.changedTouches.length, @@ -1725,9 +1796,9 @@ } ); } - // Touch event model start, end, and move events are always captured so we don't need to release capture. - // We'll ignore the should-release-capture return value here - updatePointersUp( tracker, event, gPoints, 0 ); // 0 means primary button press/release or touch contact + if ( updatePointersUp( tracker, event, gPoints, 0 ) ) { + releasePointer( tracker, 'touch' ); + } // simulate touchleave if not natively available if ( !$.MouseTracker.haveTouchEnter && touchCount > 0 ) { @@ -1743,6 +1814,28 @@ * @inner */ function onTouchMove( tracker, event ) { + handleTouchMove( tracker, event ); + } + + + /** + * This handler is attached to the window object (on the capture phase) to emulate pointer capture. + * onTouchMove is still attached to the tracked element, so stop propagation to avoid processing twice. + * + * @private + * @inner + */ + function onTouchMoveCaptured( tracker, event ) { + handleTouchMove( tracker, event ); + $.stopEvent( event ); + } + + + /** + * @private + * @inner + */ + function handleTouchMove( tracker, event ) { var i, touchCount = event.changedTouches.length, gPoints = []; @@ -1866,8 +1959,8 @@ }; if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { - capturePointer( tracker, false ); $.stopEvent( event ); + capturePointer( tracker, 'pointer' ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { @@ -1917,8 +2010,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - releasePointer( tracker, false ); - //$.stopEvent( event ); + releasePointer( tracker, 'pointer' ); } } From 49e1a8b8e26488d476a06c0546061f8e7b680159 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 31 Dec 2014 14:39:37 -0800 Subject: [PATCH 06/52] changelog update --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 4ae3667e..29e4d3a9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -20,6 +20,7 @@ OPENSEADRAGON CHANGELOG * Added option for home button to fill viewer (#474) * Better handling of mid-update image loaded callbacks (#409) * Tracked pointers are now cleaned up when Viewer.setMouseNavEnabled(false) is called (#518) +* Added explicit pointer capture for touch event model touchstart events 1.1.1: From 05ba23ea55ada1fde5aa5a9276b329d1357663dc Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 31 Dec 2014 14:41:27 -0800 Subject: [PATCH 07/52] changelog update - added PR # --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 29e4d3a9..5485d015 100644 --- a/changelog.txt +++ b/changelog.txt @@ -20,7 +20,7 @@ OPENSEADRAGON CHANGELOG * Added option for home button to fill viewer (#474) * Better handling of mid-update image loaded callbacks (#409) * Tracked pointers are now cleaned up when Viewer.setMouseNavEnabled(false) is called (#518) -* Added explicit pointer capture for touch event model touchstart events +* Added explicit pointer capture for touch event model touchstart events (#552) 1.1.1: From d694c7ea6ca81c24a74a6bbd88dbddfc71501c70 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 5 Jan 2015 13:17:05 -0800 Subject: [PATCH 08/52] Version bump --- changelog.txt | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5485d015..4e71760e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,7 @@ OPENSEADRAGON CHANGELOG ======================= -1.2.0: (in progress) +1.2.0: * New combined IIIF TileSource for 1.0 through 2.0 (#441) * BREAKING CHANGE: Removed IIIF1_1TileSource (now that IIIFTileSource supports all versions) diff --git a/package.json b/package.json index 486d8743..6aa039fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "OpenSeadragon", - "version": "1.1.1", + "version": "1.2.0", "description": "Provides a smooth, zoomable user interface for HTML/Javascript.", "devDependencies": { "grunt": "^0.4.5", From 8ff70dd54fee5b4ebe212311f599a7fecfd14514 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 5 Jan 2015 13:21:19 -0800 Subject: [PATCH 09/52] Started 1.2.1 --- changelog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.txt b/changelog.txt index 4e71760e..779df7b5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,8 @@ OPENSEADRAGON CHANGELOG ======================= +1.2.1: (in progress) + 1.2.0: * New combined IIIF TileSource for 1.0 through 2.0 (#441) From 9e07c96d29407f38108e9ee424bfc9eb37d5bec0 Mon Sep 17 00:00:00 2001 From: Younes El Alami Date: Fri, 9 Jan 2015 02:21:16 +0000 Subject: [PATCH 10/52] Added preserveOverlays option to Viewer --- src/openseadragon.js | 7 +++++++ src/viewer.js | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/openseadragon.js b/src/openseadragon.js index f8b744de..e1a37e2f 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -519,6 +519,12 @@ * position. If preserveViewport is set to true, then the viewport position * is preserved when navigating between images in the sequence. * + * @property {Boolean} [preserveOverlays=false] + * If the viewer has been configured with a sequence of tile sources, then + * normally navigating to through each image resets the overlays. + * If preserveOverlays is set to true, then the overlays + * are preserved when navigating between images in the sequence. + * * @property {Boolean} [showReferenceStrip=false] * If the viewer has been configured with a sequence of tile sources, then * display a scrolling strip of image thumbnails for navigating through the images. @@ -945,6 +951,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ showSequenceControl: true, //SEQUENCE sequenceControlAnchor: null, //SEQUENCE preserveViewport: false, //SEQUENCE + preserveOverlays: false, //SEQUENCE navPrevNextWrap: false, //SEQUENCE showNavigationControl: true, //ZOOM/HOME/FULL/ROTATION navigationControlAnchor: null, //ZOOM/HOME/FULL/ROTATION diff --git a/src/viewer.js b/src/viewer.js index 39ed6294..32a18722 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -539,9 +539,13 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, this.navigator.close(); } - this.clearOverlays(); + if( ! this.preserveOverlays) + { + this.clearOverlays(); + this.overlaysContainer.innerHTML = ""; + } + this.drawersContainer.innerHTML = ""; - this.overlaysContainer.innerHTML = ""; if ( this.drawer ) { this.drawer.destroy(); @@ -1968,7 +1972,12 @@ function openTileSource( viewer, source ) { _this.viewport.resetContentSize( _this.source.dimensions ); } - _this.source.overlays = _this.source.overlays || []; + if( _this.preserveOverlays ){ + _this.source.overlays = _this.currentOverlays; + } + else{ + _this.source.overlays = _this.source.overlays || []; + } _this.drawer = new $.Drawer({ viewer: _this, From 1d16b01a2863ef1268f093b09c082b4f8ab91687 Mon Sep 17 00:00:00 2001 From: Younes El Alami Date: Sat, 10 Jan 2015 12:11:45 +0000 Subject: [PATCH 11/52] Changed _this.source.overlays to _this.overlays, https://github.com/openseadragon/openseadragon/pull/561/files#r22730318 --- src/viewer.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/viewer.js b/src/viewer.js index 32a18722..a359a9d9 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -1973,12 +1973,11 @@ function openTileSource( viewer, source ) { } if( _this.preserveOverlays ){ - _this.source.overlays = _this.currentOverlays; - } - else{ - _this.source.overlays = _this.source.overlays || []; + _this.overlays = _this.currentOverlays; } + _this.source.overlays = _this.source.overlays || []; + _this.drawer = new $.Drawer({ viewer: _this, source: _this.source, From 30b5ec04c62c27d3d528661007ce622653555de1 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Sat, 10 Jan 2015 14:49:02 -0800 Subject: [PATCH 12/52] MouseTracker Improvements * Exposed secondary pointer button (middle, right, etc.) events from MouseTracker and through viewer (#479) * MouseTracker - Improved IE 8 compatibility --- changelog.txt | 3 + src/mousetracker.js | 432 +++++++++++++++++++++++++++++++++----------- src/viewer.js | 62 ++++++- 3 files changed, 392 insertions(+), 105 deletions(-) diff --git a/changelog.txt b/changelog.txt index 779df7b5..dfb1a5a9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,9 @@ OPENSEADRAGON CHANGELOG 1.2.1: (in progress) +* Exposed secondary pointer button (middle, right, etc.) events from MouseTracker and through viewer (#479) +* MouseTracker - Improved IE 8 compatibility + 1.2.0: * New combined IIIF TileSource for 1.0 through 2.0 (#441) diff --git a/src/mousetracker.js b/src/mousetracker.js index 8e89e43a..ff4f15fa 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -72,8 +72,12 @@ * An optional handler for pointer exit. * @param {OpenSeadragon.EventHandler} [options.pressHandler=null] * An optional handler for pointer press. + * @param {OpenSeadragon.EventHandler} [options.auxPressHandler=null] + * An optional handler for pointer non-primary button press. * @param {OpenSeadragon.EventHandler} [options.releaseHandler=null] * An optional handler for pointer release. + * @param {OpenSeadragon.EventHandler} [options.auxReleaseHandler=null] + * An optional handler for pointer non-primary button release. * @param {OpenSeadragon.EventHandler} [options.moveHandler=null] * An optional handler for pointer move. * @param {OpenSeadragon.EventHandler} [options.scrollHandler=null] @@ -144,24 +148,26 @@ * @memberof OpenSeadragon.MouseTracker# */ this.dblClickDistThreshold = options.dblClickDistThreshold || $.DEFAULT_SETTINGS.dblClickDistThreshold; - this.userData = options.userData || null; - this.stopDelay = options.stopDelay || 50; + this.userData = options.userData || null; + this.stopDelay = options.stopDelay || 50; - this.enterHandler = options.enterHandler || null; - this.exitHandler = options.exitHandler || null; - this.pressHandler = options.pressHandler || null; - this.releaseHandler = options.releaseHandler || null; - this.moveHandler = options.moveHandler || null; - this.scrollHandler = options.scrollHandler || null; - this.clickHandler = options.clickHandler || null; - this.dblClickHandler = options.dblClickHandler || null; - this.dragHandler = options.dragHandler || null; - this.dragEndHandler = options.dragEndHandler || null; - this.pinchHandler = options.pinchHandler || null; - this.stopHandler = options.stopHandler || null; - this.keyHandler = options.keyHandler || null; - this.focusHandler = options.focusHandler || null; - this.blurHandler = options.blurHandler || null; + this.enterHandler = options.enterHandler || null; + this.exitHandler = options.exitHandler || null; + this.pressHandler = options.pressHandler || null; + this.auxPressHandler = options.auxPressHandler || null; + this.releaseHandler = options.releaseHandler || null; + this.auxReleaseHandler = options.auxReleaseHandler || null; + this.moveHandler = options.moveHandler || null; + this.scrollHandler = options.scrollHandler || null; + this.clickHandler = options.clickHandler || null; + this.dblClickHandler = options.dblClickHandler || null; + this.dragHandler = options.dragHandler || null; + this.dragEndHandler = options.dragEndHandler || null; + this.pinchHandler = options.pinchHandler || null; + this.stopHandler = options.stopHandler || null; + this.keyHandler = options.keyHandler || null; + this.focusHandler = options.focusHandler || null; + this.blurHandler = options.blurHandler || null; //Store private properties in a scope sealed hash map var _this = this; @@ -183,6 +189,8 @@ DOMMouseScroll: function ( event ) { onMouseWheel( _this, event ); }, MozMousePixelScroll: function ( event ) { onMouseWheel( _this, event ); }, + mouseenter: function ( event ) { onMouseEnter( _this, event ); }, // Used on IE8 only + mouseleave: function ( event ) { onMouseLeave( _this, event ); }, // Used on IE8 only mouseover: function ( event ) { onMouseOver( _this, event ); }, mouseout: function ( event ) { onMouseOut( _this, event ); }, mousedown: function ( event ) { onMouseDown( _this, event ); }, @@ -390,6 +398,34 @@ */ pressHandler: function () { }, + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.button + * Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + auxPressHandler: function () { }, + /** * Implement or assign implementation to these handlers during or after * calling the constructor. @@ -420,6 +456,34 @@ */ releaseHandler: function () { }, + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {String} event.pointerType + * "mouse", "touch", "pen", etc. + * @param {OpenSeadragon.Point} event.position + * The position of the event relative to the tracked element. + * @param {Number} event.button + * Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @param {Number} event.buttons + * Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Boolean} event.isTouchEvent + * True if the original event is a touch event, otherwise false. Deprecated. Use pointerType and/or originalEvent instead. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + auxReleaseHandler: function () { }, + /** * Implement or assign implementation to these handlers during or after * calling the constructor. @@ -838,8 +902,14 @@ $.MouseTracker.haveMouseEnter = false; } else { // Legacy W3C mouse events - $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" ); - $.MouseTracker.haveMouseEnter = false; + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" ); + $.MouseTracker.haveMouseEnter = true; + } else { + $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" ); + $.MouseTracker.haveMouseEnter = false; + } + $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" ); if ( 'ontouchstart' in window ) { // iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505) $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); @@ -1181,27 +1251,31 @@ * @inner */ function capturePointer( tracker, pointerType ) { - var delegate = THIS[ tracker.hash ], - pointsList = tracker.getActivePointersListByType( pointerType ), - eventParams = getCaptureEventParams( tracker, pointerType ); + var pointsList = tracker.getActivePointersListByType( pointerType ), + eventParams; pointsList.captureCount++; if ( pointsList.captureCount === 1 ) { - // We emulate mouse capture by hanging listeners on the window object. - // (Note we listen on the capture phase so the captured handlers will get called first) - $.addEvent( - $.MouseTracker.captureElement, - eventParams.upName, - eventParams.upHandler, - true - ); - $.addEvent( - $.MouseTracker.captureElement, - eventParams.moveName, - eventParams.moveHandler, - true - ); + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + tracker.element.setCapture( true ); + } else { + eventParams = getCaptureEventParams( tracker, pointerType ); + // We emulate mouse capture by hanging listeners on the document object. + // (Note we listen on the capture phase so the captured handlers will get called first) + $.addEvent( + $.MouseTracker.captureElement, + eventParams.upName, + eventParams.upHandler, + true + ); + $.addEvent( + $.MouseTracker.captureElement, + eventParams.moveName, + eventParams.moveHandler, + true + ); + } } } @@ -1212,27 +1286,31 @@ * @inner */ function releasePointer( tracker, pointerType ) { - var delegate = THIS[ tracker.hash ], - pointsList = tracker.getActivePointersListByType( pointerType ), - eventParams = getCaptureEventParams( tracker, pointerType ); + var pointsList = tracker.getActivePointersListByType( pointerType ), + eventParams; pointsList.captureCount--; if ( pointsList.captureCount === 0 ) { - // We emulate mouse capture by hanging listeners on the window object. - // (Note we listen on the capture phase so the captured handlers will get called first) - $.removeEvent( - $.MouseTracker.captureElement, - eventParams.moveName, - eventParams.moveHandler, - true - ); - $.removeEvent( - $.MouseTracker.captureElement, - eventParams.upName, - eventParams.upHandler, - true - ); + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + tracker.element.releaseCapture(); + } else { + eventParams = getCaptureEventParams( tracker, pointerType ); + // We emulate mouse capture by hanging listeners on the document object. + // (Note we listen on the capture phase so the captured handlers will get called first) + $.removeEvent( + $.MouseTracker.captureElement, + eventParams.moveName, + eventParams.moveHandler, + true + ); + $.removeEvent( + $.MouseTracker.captureElement, + eventParams.upName, + eventParams.upHandler, + true + ); + } } } @@ -1506,20 +1584,40 @@ } + /** + * Only used on IE 8 + * + * @private + * @inner + */ + function onMouseEnter( tracker, event ) { + event = $.getEvent( event ); + + handleMouseEnter( tracker, event ); + } + + /** * @private * @inner */ function onMouseOver( tracker, event ) { - var gPoint; - event = $.getEvent( event ); if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { return; } - gPoint = { + handleMouseEnter( tracker, event ); + } + + + /** + * @private + * @inner + */ + function handleMouseEnter( tracker, event ) { + var gPoint = { id: $.MouseTracker.mousePointerId, type: 'mouse', isPrimary: true, @@ -1531,20 +1629,40 @@ } + /** + * Only used on IE 8 + * + * @private + * @inner + */ + function onMouseLeave( tracker, event ) { + event = $.getEvent( event ); + + handleMouseExit( tracker, event ); + } + + /** * @private * @inner */ function onMouseOut( tracker, event ) { - var gPoint; - event = $.getEvent( event ); if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { return; } - gPoint = { + handleMouseExit( tracker, event ); + } + + + /** + * @private + * @inner + */ + function handleMouseExit( tracker, event ) { + var gPoint = { id: $.MouseTracker.mousePointerId, type: 'mouse', isPrimary: true, @@ -1556,6 +1674,31 @@ } + /** + * Returns a W3C DOM level 3 standard button value given an event.button property: + * -1 == none, 0 == primary/left, 1 == middle, 2 == secondary/right, 3 == X1/back, 4 == X2/forward, 5 == eraser (pen) + * @private + * @inner + */ + function getStandardizedButton( button ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + // On IE 8, 0 == none, 1 == left, 2 == right, 3 == left and right, 4 == middle, 5 == left and middle, 6 == right and middle, 7 == all three + // TODO: Support chorded (multiple) button presses on IE 8? + if ( button === 1 ) { + return 0; + } else if ( button === 2 ) { + return 2; + } else if ( button === 4 ) { + return 1; + } else { + return -1; + } + } else { + return button; + } + } + + /** * @private * @inner @@ -1573,7 +1716,7 @@ currentTime: $.now() }; - if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { + if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { $.stopEvent( event ); capturePointer( tracker, 'mouse' ); } @@ -1622,11 +1765,12 @@ currentTime: $.now() }; - if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { + if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { releasePointer( tracker, 'mouse' ); } } + /** * @private * @inner @@ -2286,7 +2430,7 @@ * @param {Array.} gPoints * Gesture points associated with the event. * @param {Number} buttonChanged - * The button involved in the event: -1: none, 0: primary, 1: aux, 2: secondary, 3: X1, 4: X2, 5: pen eraser. + * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. * @@ -2304,30 +2448,71 @@ if ( typeof event.buttons !== 'undefined' ) { pointsList.buttons = event.buttons; } else { - if ( buttonChanged === 0 ) { - // Primary - pointsList.buttons |= 1; - } else if ( buttonChanged === 1 ) { - // Aux - pointsList.buttons |= 4; - } else if ( buttonChanged === 2 ) { - // Secondary - pointsList.buttons |= 2; - } else if ( buttonChanged === 3 ) { - // X1 (Back) - pointsList.buttons |= 8; - } else if ( buttonChanged === 4 ) { - // X2 (Forward) - pointsList.buttons |= 16; - } else if ( buttonChanged === 5 ) { - // Pen Eraser - pointsList.buttons |= 32; + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons += 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons += 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons += 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons += 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons += 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons += 32; + } + } else { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons |= 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons |= 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons |= 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons |= 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons |= 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons |= 32; + } } } // Only capture and track primary button, pen, and touch contacts - //if ( buttonChanged !== 0 ) { - if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the commented line above + if ( buttonChanged !== 0 ) { + // Aux Press + if ( tracker.auxPressHandler ) { + propagate = tracker.auxPressHandler( + { + eventSource: tracker, + pointerType: gPoints[ 0 ].type, + position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ), + button: buttonChanged, + buttons: pointsList.buttons, + isTouchEvent: gPoints[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + return false; } @@ -2407,7 +2592,7 @@ * @param {Array.} gPoints * Gesture points associated with the event. * @param {Number} buttonChanged - * The button involved in the event: -1: none, 0: primary, 1: aux, 2: secondary, 3: X1, 4: X2, 5: pen eraser. + * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. * Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events. * @@ -2431,30 +2616,71 @@ if ( typeof event.buttons !== 'undefined' ) { pointsList.buttons = event.buttons; } else { - if ( buttonChanged === 0 ) { - // Primary - pointsList.buttons ^= ~1; - } else if ( buttonChanged === 1 ) { - // Aux - pointsList.buttons ^= ~4; - } else if ( buttonChanged === 2 ) { - // Secondary - pointsList.buttons ^= ~2; - } else if ( buttonChanged === 3 ) { - // X1 (Back) - pointsList.buttons ^= ~8; - } else if ( buttonChanged === 4 ) { - // X2 (Forward) - pointsList.buttons ^= ~16; - } else if ( buttonChanged === 5 ) { - // Pen Eraser - pointsList.buttons ^= ~32; + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons -= 1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons -= 4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons -= 2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons -= 8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons -= 16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons -= 32; + } + } else { + if ( buttonChanged === 0 ) { + // Primary + pointsList.buttons ^= ~1; + } else if ( buttonChanged === 1 ) { + // Aux + pointsList.buttons ^= ~4; + } else if ( buttonChanged === 2 ) { + // Secondary + pointsList.buttons ^= ~2; + } else if ( buttonChanged === 3 ) { + // X1 (Back) + pointsList.buttons ^= ~8; + } else if ( buttonChanged === 4 ) { + // X2 (Forward) + pointsList.buttons ^= ~16; + } else if ( buttonChanged === 5 ) { + // Pen Eraser + pointsList.buttons ^= ~32; + } } } // Only capture and track primary button, pen, and touch contacts - //if ( buttonChanged !== 0 ) { - if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the commented line above + if ( buttonChanged !== 0 ) { + // Aux Release + if ( tracker.auxReleaseHandler ) { + propagate = tracker.auxReleaseHandler( + { + eventSource: tracker, + pointerType: gPoints[ 0 ].type, + position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ), + button: buttonChanged, + buttons: pointsList.buttons, + isTouchEvent: gPoints[ 0 ].type === 'touch', + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( propagate === false ) { + $.cancelEvent( event ); + } + } + return false; } diff --git a/src/viewer.js b/src/viewer.js index 39ed6294..5c8b45a8 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -390,6 +390,8 @@ $.Viewer = function( options ) { dragHandler: $.delegate( this, onCanvasDrag ), dragEndHandler: $.delegate( this, onCanvasDragEnd ), releaseHandler: $.delegate( this, onCanvasRelease ), + auxPressHandler: $.delegate( this, onCanvasAuxPress ), + auxReleaseHandler: $.delegate( this, onCanvasAuxRelease ), scrollHandler: $.delegate( this, onCanvasScroll ), pinchHandler: $.delegate( this, onCanvasPinch ) }).setTracking( this.mouseNavEnabled ? true : false ); // default state @@ -2422,7 +2424,7 @@ function onCanvasDragEnd( event ) { function onCanvasRelease( event ) { /** - * Raised when the mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element. + * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element. * * @event canvas-release * @memberof OpenSeadragon.Viewer @@ -2444,6 +2446,62 @@ function onCanvasRelease( event ) { }); } +function onCanvasAuxPress( event ) { + /** + * Raised when any non-primary pointer button is pressed on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-aux-press + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {Number} button - Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @property {Number} buttons - Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-aux-press', { + tracker: event.eventSource, + position: event.position, + pointerType: event.pointerType, + button: event.button, + buttons: event.buttons, + originalEvent: event.originalEvent + }); +} + +function onCanvasAuxRelease( event ) { + /** + * Raised when any non-primary pointer button is released on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-aux-release + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {Number} button - Button which caused the event. + * -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser. + * @property {Number} buttons - Current buttons pressed. + * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-aux-release', { + tracker: event.eventSource, + position: event.position, + pointerType: event.pointerType, + button: event.button, + buttons: event.buttons, + originalEvent: event.originalEvent + }); +} + function onCanvasPinch( event ) { var gestureSettings, centerPt, @@ -2593,7 +2651,7 @@ function onContainerRelease( event ) { } } /** - * Raised when the mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#container} element. + * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#container} element. * * @event container-release * @memberof OpenSeadragon.Viewer From ad838e7fd459a6d082d2cecb660648347e7b7a14 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Sat, 10 Jan 2015 14:51:56 -0800 Subject: [PATCH 13/52] changelog update --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index dfb1a5a9..2430d5f1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ OPENSEADRAGON CHANGELOG 1.2.1: (in progress) * Exposed secondary pointer button (middle, right, etc.) events from MouseTracker and through viewer (#479) -* MouseTracker - Improved IE 8 compatibility +* MouseTracker - Improved IE 8 compatibility (#562) 1.2.0: From becd11b6ceca46f1c048f3c7637150c01c7c8674 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Sun, 11 Jan 2015 10:06:07 -0800 Subject: [PATCH 14/52] Added unit tests --- test/events.js | 197 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 192 insertions(+), 5 deletions(-) diff --git a/test/events.js b/test/events.js index 07c14ea6..e9f5074f 100644 --- a/test/events.js +++ b/test/events.js @@ -35,6 +35,8 @@ origExitHandler, origPressHandler, origReleaseHandler, + origAuxPressHandler, + origAuxReleaseHandler, origMoveHandler, origClickHandler, origDblClickHandler, @@ -44,6 +46,10 @@ exitCount, pressCount, releaseCount, + rightPressCount, + rightReleaseCount, + auxPressCount, + auxReleaseCount, moveCount, clickCount, dblClickCount, @@ -94,6 +100,36 @@ return true; } }; + origAuxPressHandler = tracker.auxPressHandler; + tracker.auxPressHandler = function ( event ) { + if (event.button === 0) { + pressCount++; + } else if (event.button === 1) { + auxPressCount++; + } else if (event.button === 2) { + rightPressCount++; + } + if (origAuxPressHandler) { + return origAuxPressHandler( event ); + } else { + return true; + } + }; + origAuxReleaseHandler = tracker.auxReleaseHandler; + tracker.auxReleaseHandler = function ( event ) { + if (event.button === 0) { + releaseCount++; + } else if (event.button === 1) { + auxReleaseCount++; + } else if (event.button === 2) { + rightReleaseCount++; + } + if (origAuxReleaseHandler) { + return origAuxReleaseHandler( event ); + } else { + return true; + } + }; origMoveHandler = tracker.moveHandler; tracker.moveHandler = function ( event ) { moveCount++; @@ -176,12 +212,28 @@ }; 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 simulateAuxDown = function (x, y, button) { + simEvent.button = button; + simEvent.clientX = offset.left + x; + simEvent.clientY = offset.top + y; + $canvas.simulate( 'mousedown', simEvent ); + }; + + var simulateAuxUp = function (x, y, button) { + simEvent.button = button; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mouseup', simEvent ); @@ -198,6 +250,7 @@ var resetForAssessment = function () { simEvent = { + button: 0, clientX: offset.left, clientY: offset.top }; @@ -205,6 +258,10 @@ exitCount = 0; pressCount = 0; releaseCount = 0; + rightPressCount = 0; + rightReleaseCount = 0; + auxPressCount = 0; + auxReleaseCount = 0; moveCount = 0; clickCount = 0; dblClickCount = 0; @@ -231,6 +288,18 @@ if ('releaseCount' in expected) { equal( releaseCount, expected.releaseCount, expected.description + 'releaseHandler event count matches expected (' + expected.releaseCount + ')' ); } + if ('rightPressCount' in expected) { + equal( rightPressCount, expected.rightPressCount, expected.description + 'auxPressHandler event count (secondary/right button) matches expected (' + expected.rightPressCount + ')' ); + } + if ('rightReleaseCount' in expected) { + equal( rightReleaseCount, expected.rightReleaseCount, expected.description + 'auxReleaseHandler event count (secondary/right button) matches expected (' + expected.rightReleaseCount + ')' ); + } + if ('auxPressCount' in expected) { + equal( auxPressCount, expected.auxPressCount, expected.description + 'auxPressHandler event count (aux/middle button) matches expected (' + expected.auxPressCount + ')' ); + } + if ('auxReleaseCount' in expected) { + equal( auxReleaseCount, expected.auxReleaseCount, expected.description + 'auxReleaseHandler event count (aux/middle button) matches expected (' + expected.auxReleaseCount + ')' ); + } if ('moveCount' in expected) { equal( moveCount, expected.moveCount, expected.description + 'moveHandler event count matches expected (' + expected.moveCount + ')' ); } @@ -290,6 +359,10 @@ exitCount: 0, pressCount: 0, releaseCount: 1, + rightPressCount: 0, + rightReleaseCount: 0, + auxPressCount: 0, + auxReleaseCount: 0, moveCount: 20, clickCount: 0, dblClickCount: 0, @@ -315,6 +388,10 @@ exitCount: 1, pressCount: 0, releaseCount: 0, + rightPressCount: 0, + rightReleaseCount: 0, + auxPressCount: 0, + auxReleaseCount: 0, moveCount: 20, clickCount: 0, dblClickCount: 0, @@ -338,6 +415,10 @@ exitCount: 1, pressCount: 0, releaseCount: 0, + rightPressCount: 0, + rightReleaseCount: 0, + auxPressCount: 0, + auxReleaseCount: 0, moveCount: 20, clickCount: 0, dblClickCount: 0, @@ -350,7 +431,7 @@ //quickClick: false }); - // enter-press-release-press-release-exit (double click) + // enter-press-release-press-release-exit (primary/left double click) resetForAssessment(); simulateEnter(0, 0); simulateDown(0, 0); @@ -359,11 +440,15 @@ simulateUp(0, 0); simulateLeave(-1, -1); assessGestureExpectations({ - description: 'enter-press-release-press-release-exit (double click): ', + description: 'enter-press-release-press-release-exit (primary/left double click): ', enterCount: 1, exitCount: 1, pressCount: 2, releaseCount: 2, + rightPressCount: 0, + rightReleaseCount: 0, + auxPressCount: 0, + auxReleaseCount: 0, moveCount: 0, clickCount: 2, dblClickCount: 1, @@ -376,18 +461,22 @@ //quickClick: true }); - // enter-press-release-exit (click) + // enter-press-release-exit (primary/left click) resetForAssessment(); simulateEnter(0, 0); simulateDown(0, 0); simulateUp(0, 0); simulateLeave(-1, -1); assessGestureExpectations({ - description: 'enter-press-release-exit (click): ', + description: 'enter-press-release-exit (primary/left click): ', enterCount: 1, exitCount: 1, pressCount: 1, releaseCount: 1, + rightPressCount: 0, + rightReleaseCount: 0, + auxPressCount: 0, + auxReleaseCount: 0, moveCount: 0, clickCount: 1, dblClickCount: 0, @@ -400,6 +489,92 @@ quickClick: true }); + // enter-auxpress-auxrelease-exit (secondary/right click) + resetForAssessment(); + simulateEnter(0, 0); + simulateAuxDown(0, 0, 2); + simulateAuxUp(0, 0, 2); + simulateLeave(-1, -1); + assessGestureExpectations({ + description: 'enter-auxpress-auxrelease-exit (secondary/right click): ', + enterCount: 1, + exitCount: 1, + pressCount: 0, + releaseCount: 0, + rightPressCount: 1, + rightReleaseCount: 1, + auxPressCount: 0, + auxReleaseCount: 0, + moveCount: 0, + clickCount: 0, + dblClickCount: 0, + dragCount: 0, + dragEndCount: 0, + //insideElementPressed: true, + //insideElementReleased: true, + contacts: 0, + trackedPointers: 0, + //quickClick: true + }); + + // enter-auxpress-auxrelease-exit (aux/middle click) + resetForAssessment(); + simulateEnter(0, 0); + simulateAuxDown(0, 0, 1); + simulateAuxUp(0, 0, 1); + simulateLeave(-1, -1); + assessGestureExpectations({ + description: 'enter-auxpress-auxrelease-exit (aux/middle click): ', + enterCount: 1, + exitCount: 1, + pressCount: 0, + releaseCount: 0, + rightPressCount: 0, + rightReleaseCount: 0, + auxPressCount: 1, + auxReleaseCount: 1, + moveCount: 0, + clickCount: 0, + dblClickCount: 0, + dragCount: 0, + dragEndCount: 0, + //insideElementPressed: true, + //insideElementReleased: true, + contacts: 0, + trackedPointers: 0, + //quickClick: true + }); + + // enter-auxpress-move-auxrelease-move-exit (secondary/right button drag, release in tracked element) + resetForAssessment(); + simulateEnter(0, 0); + simulateAuxDown(0, 0, 2); + simulateMove(1, 1, 100); + simulateAuxUp(10, 10, 2); + simulateMove(-1, -1, 100); + simulateLeave(-1, -1); + assessGestureExpectations({ + description: 'enter-auxpress-move-auxrelease-move-exit (secondary/right button drag, release in tracked element): ', + enterCount: 1, + exitCount: 1, + pressCount: 0, + releaseCount: 0, + rightPressCount: 1, + rightReleaseCount: 1, + auxPressCount: 0, + auxReleaseCount: 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-exit (drag, release in tracked element) resetForAssessment(); simulateEnter(0, 0); @@ -414,6 +589,10 @@ exitCount: 1, pressCount: 1, releaseCount: 1, + rightPressCount: 0, + rightReleaseCount: 0, + auxPressCount: 0, + auxReleaseCount: 0, moveCount: 200, clickCount: 1, dblClickCount: 0, @@ -441,6 +620,10 @@ exitCount: 1, pressCount: 1, releaseCount: 1, + rightPressCount: 0, + rightReleaseCount: 0, + auxPressCount: 0, + auxReleaseCount: 0, moveCount: 15, clickCount: 0, dblClickCount: 0, @@ -453,7 +636,6 @@ quickClick: false }); - //// enter-press-move-exit-move-release-outside (drag, release outside iframe) //resetForAssessment(); //simulateEnter(0, 0); @@ -468,6 +650,10 @@ // exitCount: 1, // pressCount: 1, // releaseCount: 1, + // rightPressCount: 0, + // rightReleaseCount: 0, + // auxPressCount: 0, + // auxReleaseCount: 0, // moveCount: 10, // clickCount: 0, // dblClickCount: 0, @@ -479,6 +665,7 @@ // trackedPointers: 0, // quickClick: false //}); + unhookViewerHandlers(); viewer.close(); From 755854d3f7c7f35c0fabd0bcb9398adaaaacbcb8 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Mon, 12 Jan 2015 11:02:54 -0800 Subject: [PATCH 15/52] Renamed non-primary button events/handlers --- src/mousetracker.js | 54 ++++++++++----------- src/viewer.js | 40 +++++++-------- test/events.js | 116 ++++++++++++++++++++++---------------------- 3 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index ff4f15fa..86e23f70 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -72,11 +72,11 @@ * An optional handler for pointer exit. * @param {OpenSeadragon.EventHandler} [options.pressHandler=null] * An optional handler for pointer press. - * @param {OpenSeadragon.EventHandler} [options.auxPressHandler=null] + * @param {OpenSeadragon.EventHandler} [options.nonPrimaryPressHandler=null] * An optional handler for pointer non-primary button press. * @param {OpenSeadragon.EventHandler} [options.releaseHandler=null] * An optional handler for pointer release. - * @param {OpenSeadragon.EventHandler} [options.auxReleaseHandler=null] + * @param {OpenSeadragon.EventHandler} [options.nonPrimaryReleaseHandler=null] * An optional handler for pointer non-primary button release. * @param {OpenSeadragon.EventHandler} [options.moveHandler=null] * An optional handler for pointer move. @@ -148,26 +148,26 @@ * @memberof OpenSeadragon.MouseTracker# */ this.dblClickDistThreshold = options.dblClickDistThreshold || $.DEFAULT_SETTINGS.dblClickDistThreshold; - this.userData = options.userData || null; - this.stopDelay = options.stopDelay || 50; + this.userData = options.userData || null; + this.stopDelay = options.stopDelay || 50; - this.enterHandler = options.enterHandler || null; - this.exitHandler = options.exitHandler || null; - this.pressHandler = options.pressHandler || null; - this.auxPressHandler = options.auxPressHandler || null; - this.releaseHandler = options.releaseHandler || null; - this.auxReleaseHandler = options.auxReleaseHandler || null; - this.moveHandler = options.moveHandler || null; - this.scrollHandler = options.scrollHandler || null; - this.clickHandler = options.clickHandler || null; - this.dblClickHandler = options.dblClickHandler || null; - this.dragHandler = options.dragHandler || null; - this.dragEndHandler = options.dragEndHandler || null; - this.pinchHandler = options.pinchHandler || null; - this.stopHandler = options.stopHandler || null; - this.keyHandler = options.keyHandler || null; - this.focusHandler = options.focusHandler || null; - this.blurHandler = options.blurHandler || null; + this.enterHandler = options.enterHandler || null; + this.exitHandler = options.exitHandler || null; + this.pressHandler = options.pressHandler || null; + this.nonPrimaryPressHandler = options.nonPrimaryPressHandler || null; + this.releaseHandler = options.releaseHandler || null; + this.nonPrimaryReleaseHandler = options.nonPrimaryReleaseHandler || null; + this.moveHandler = options.moveHandler || null; + this.scrollHandler = options.scrollHandler || null; + this.clickHandler = options.clickHandler || null; + this.dblClickHandler = options.dblClickHandler || null; + this.dragHandler = options.dragHandler || null; + this.dragEndHandler = options.dragEndHandler || null; + this.pinchHandler = options.pinchHandler || null; + this.stopHandler = options.stopHandler || null; + this.keyHandler = options.keyHandler || null; + this.focusHandler = options.focusHandler || null; + this.blurHandler = options.blurHandler || null; //Store private properties in a scope sealed hash map var _this = this; @@ -424,7 +424,7 @@ * @param {Object} event.userData * Arbitrary user-defined object. */ - auxPressHandler: function () { }, + nonPrimaryPressHandler: function () { }, /** * Implement or assign implementation to these handlers during or after @@ -482,7 +482,7 @@ * @param {Object} event.userData * Arbitrary user-defined object. */ - auxReleaseHandler: function () { }, + nonPrimaryReleaseHandler: function () { }, /** * Implement or assign implementation to these handlers during or after @@ -2494,8 +2494,8 @@ // Only capture and track primary button, pen, and touch contacts if ( buttonChanged !== 0 ) { // Aux Press - if ( tracker.auxPressHandler ) { - propagate = tracker.auxPressHandler( + if ( tracker.nonPrimaryPressHandler ) { + propagate = tracker.nonPrimaryPressHandler( { eventSource: tracker, pointerType: gPoints[ 0 ].type, @@ -2662,8 +2662,8 @@ // Only capture and track primary button, pen, and touch contacts if ( buttonChanged !== 0 ) { // Aux Release - if ( tracker.auxReleaseHandler ) { - propagate = tracker.auxReleaseHandler( + if ( tracker.nonPrimaryReleaseHandler ) { + propagate = tracker.nonPrimaryReleaseHandler( { eventSource: tracker, pointerType: gPoints[ 0 ].type, diff --git a/src/viewer.js b/src/viewer.js index 5c8b45a8..909e65b1 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -380,20 +380,20 @@ $.Viewer = function( options ) { this.innerTracker = new $.MouseTracker({ - element: this.canvas, - clickTimeThreshold: this.clickTimeThreshold, - clickDistThreshold: this.clickDistThreshold, - dblClickTimeThreshold: this.dblClickTimeThreshold, - dblClickDistThreshold: this.dblClickDistThreshold, - clickHandler: $.delegate( this, onCanvasClick ), - dblClickHandler: $.delegate( this, onCanvasDblClick ), - dragHandler: $.delegate( this, onCanvasDrag ), - dragEndHandler: $.delegate( this, onCanvasDragEnd ), - releaseHandler: $.delegate( this, onCanvasRelease ), - auxPressHandler: $.delegate( this, onCanvasAuxPress ), - auxReleaseHandler: $.delegate( this, onCanvasAuxRelease ), - scrollHandler: $.delegate( this, onCanvasScroll ), - pinchHandler: $.delegate( this, onCanvasPinch ) + element: this.canvas, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + dblClickTimeThreshold: this.dblClickTimeThreshold, + dblClickDistThreshold: this.dblClickDistThreshold, + clickHandler: $.delegate( this, onCanvasClick ), + dblClickHandler: $.delegate( this, onCanvasDblClick ), + dragHandler: $.delegate( this, onCanvasDrag ), + dragEndHandler: $.delegate( this, onCanvasDragEnd ), + releaseHandler: $.delegate( this, onCanvasRelease ), + nonPrimaryPressHandler: $.delegate( this, onCanvasNonPrimaryPress ), + nonPrimaryReleaseHandler: $.delegate( this, onCanvasNonPrimaryRelease ), + scrollHandler: $.delegate( this, onCanvasScroll ), + pinchHandler: $.delegate( this, onCanvasPinch ) }).setTracking( this.mouseNavEnabled ? true : false ); // default state this.outerTracker = new $.MouseTracker({ @@ -2446,11 +2446,11 @@ function onCanvasRelease( event ) { }); } -function onCanvasAuxPress( event ) { +function onCanvasNonPrimaryPress( event ) { /** * Raised when any non-primary pointer button is pressed on the {@link OpenSeadragon.Viewer#canvas} element. * - * @event canvas-aux-press + * @event canvas-nonprimary-press * @memberof OpenSeadragon.Viewer * @type {object} * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. @@ -2464,7 +2464,7 @@ function onCanvasAuxPress( event ) { * @property {Object} originalEvent - The original DOM event. * @property {?Object} userData - Arbitrary subscriber-defined object. */ - this.raiseEvent( 'canvas-aux-press', { + this.raiseEvent( 'canvas-nonprimary-press', { tracker: event.eventSource, position: event.position, pointerType: event.pointerType, @@ -2474,11 +2474,11 @@ function onCanvasAuxPress( event ) { }); } -function onCanvasAuxRelease( event ) { +function onCanvasNonPrimaryRelease( event ) { /** * Raised when any non-primary pointer button is released on the {@link OpenSeadragon.Viewer#canvas} element. * - * @event canvas-aux-release + * @event canvas-nonprimary-release * @memberof OpenSeadragon.Viewer * @type {object} * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. @@ -2492,7 +2492,7 @@ function onCanvasAuxRelease( event ) { * @property {Object} originalEvent - The original DOM event. * @property {?Object} userData - Arbitrary subscriber-defined object. */ - this.raiseEvent( 'canvas-aux-release', { + this.raiseEvent( 'canvas-nonprimary-release', { tracker: event.eventSource, position: event.position, pointerType: event.pointerType, diff --git a/test/events.js b/test/events.js index e9f5074f..43069e96 100644 --- a/test/events.js +++ b/test/events.js @@ -35,8 +35,8 @@ origExitHandler, origPressHandler, origReleaseHandler, - origAuxPressHandler, - origAuxReleaseHandler, + origNonPrimaryPressHandler, + origNonPrimaryReleaseHandler, origMoveHandler, origClickHandler, origDblClickHandler, @@ -48,8 +48,8 @@ releaseCount, rightPressCount, rightReleaseCount, - auxPressCount, - auxReleaseCount, + middlePressCount, + middleReleaseCount, moveCount, clickCount, dblClickCount, @@ -100,32 +100,32 @@ return true; } }; - origAuxPressHandler = tracker.auxPressHandler; - tracker.auxPressHandler = function ( event ) { + origNonPrimaryPressHandler = tracker.nonPrimaryPressHandler; + tracker.nonPrimaryPressHandler = function ( event ) { if (event.button === 0) { pressCount++; } else if (event.button === 1) { - auxPressCount++; + middlePressCount++; } else if (event.button === 2) { rightPressCount++; } - if (origAuxPressHandler) { - return origAuxPressHandler( event ); + if (origNonPrimaryPressHandler) { + return origNonPrimaryPressHandler( event ); } else { return true; } }; - origAuxReleaseHandler = tracker.auxReleaseHandler; - tracker.auxReleaseHandler = function ( event ) { + origNonPrimaryReleaseHandler = tracker.nonPrimaryReleaseHandler; + tracker.nonPrimaryReleaseHandler = function ( event ) { if (event.button === 0) { releaseCount++; } else if (event.button === 1) { - auxReleaseCount++; + middleReleaseCount++; } else if (event.button === 2) { rightReleaseCount++; } - if (origAuxReleaseHandler) { - return origAuxReleaseHandler( event ); + if (origNonPrimaryReleaseHandler) { + return origNonPrimaryReleaseHandler( event ); } else { return true; } @@ -225,14 +225,14 @@ $canvas.simulate( 'mouseup', simEvent ); }; - var simulateAuxDown = function (x, y, button) { + var simulateNonPrimaryDown = function (x, y, button) { simEvent.button = button; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; $canvas.simulate( 'mousedown', simEvent ); }; - var simulateAuxUp = function (x, y, button) { + var simulateNonPrimaryUp = function (x, y, button) { simEvent.button = button; simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; @@ -260,8 +260,8 @@ releaseCount = 0; rightPressCount = 0; rightReleaseCount = 0; - auxPressCount = 0; - auxReleaseCount = 0; + middlePressCount = 0; + middleReleaseCount = 0; moveCount = 0; clickCount = 0; dblClickCount = 0; @@ -289,16 +289,16 @@ equal( releaseCount, expected.releaseCount, expected.description + 'releaseHandler event count matches expected (' + expected.releaseCount + ')' ); } if ('rightPressCount' in expected) { - equal( rightPressCount, expected.rightPressCount, expected.description + 'auxPressHandler event count (secondary/right button) matches expected (' + expected.rightPressCount + ')' ); + equal( rightPressCount, expected.rightPressCount, expected.description + 'nonPrimaryPressHandler event count (secondary/right button) matches expected (' + expected.rightPressCount + ')' ); } if ('rightReleaseCount' in expected) { - equal( rightReleaseCount, expected.rightReleaseCount, expected.description + 'auxReleaseHandler event count (secondary/right button) matches expected (' + expected.rightReleaseCount + ')' ); + equal( rightReleaseCount, expected.rightReleaseCount, expected.description + 'nonPrimaryReleaseHandler event count (secondary/right button) matches expected (' + expected.rightReleaseCount + ')' ); } - if ('auxPressCount' in expected) { - equal( auxPressCount, expected.auxPressCount, expected.description + 'auxPressHandler event count (aux/middle button) matches expected (' + expected.auxPressCount + ')' ); + if ('middlePressCount' in expected) { + equal( middlePressCount, expected.middlePressCount, expected.description + 'nonPrimaryPressHandler event count (aux/middle button) matches expected (' + expected.middlePressCount + ')' ); } - if ('auxReleaseCount' in expected) { - equal( auxReleaseCount, expected.auxReleaseCount, expected.description + 'auxReleaseHandler event count (aux/middle button) matches expected (' + expected.auxReleaseCount + ')' ); + if ('middleReleaseCount' in expected) { + equal( middleReleaseCount, expected.middleReleaseCount, expected.description + 'nonPrimaryReleaseHandler event count (aux/middle button) matches expected (' + expected.middleReleaseCount + ')' ); } if ('moveCount' in expected) { equal( moveCount, expected.moveCount, expected.description + 'moveHandler event count matches expected (' + expected.moveCount + ')' ); @@ -361,8 +361,8 @@ releaseCount: 1, rightPressCount: 0, rightReleaseCount: 0, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 20, clickCount: 0, dblClickCount: 0, @@ -390,8 +390,8 @@ releaseCount: 0, rightPressCount: 0, rightReleaseCount: 0, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 20, clickCount: 0, dblClickCount: 0, @@ -417,8 +417,8 @@ releaseCount: 0, rightPressCount: 0, rightReleaseCount: 0, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 20, clickCount: 0, dblClickCount: 0, @@ -447,8 +447,8 @@ releaseCount: 2, rightPressCount: 0, rightReleaseCount: 0, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 0, clickCount: 2, dblClickCount: 1, @@ -475,8 +475,8 @@ releaseCount: 1, rightPressCount: 0, rightReleaseCount: 0, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 0, clickCount: 1, dblClickCount: 0, @@ -489,22 +489,22 @@ quickClick: true }); - // enter-auxpress-auxrelease-exit (secondary/right click) + // enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click) resetForAssessment(); simulateEnter(0, 0); - simulateAuxDown(0, 0, 2); - simulateAuxUp(0, 0, 2); + simulateNonPrimaryDown(0, 0, 2); + simulateNonPrimaryUp(0, 0, 2); simulateLeave(-1, -1); assessGestureExpectations({ - description: 'enter-auxpress-auxrelease-exit (secondary/right click): ', + description: 'enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click): ', enterCount: 1, exitCount: 1, pressCount: 0, releaseCount: 0, rightPressCount: 1, rightReleaseCount: 1, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 0, clickCount: 0, dblClickCount: 0, @@ -517,22 +517,22 @@ //quickClick: true }); - // enter-auxpress-auxrelease-exit (aux/middle click) + // enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click) resetForAssessment(); simulateEnter(0, 0); - simulateAuxDown(0, 0, 1); - simulateAuxUp(0, 0, 1); + simulateNonPrimaryDown(0, 0, 1); + simulateNonPrimaryUp(0, 0, 1); simulateLeave(-1, -1); assessGestureExpectations({ - description: 'enter-auxpress-auxrelease-exit (aux/middle click): ', + description: 'enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click): ', enterCount: 1, exitCount: 1, pressCount: 0, releaseCount: 0, rightPressCount: 0, rightReleaseCount: 0, - auxPressCount: 1, - auxReleaseCount: 1, + middlePressCount: 1, + middleReleaseCount: 1, moveCount: 0, clickCount: 0, dblClickCount: 0, @@ -545,24 +545,24 @@ //quickClick: true }); - // enter-auxpress-move-auxrelease-move-exit (secondary/right button drag, release in tracked element) + // enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element) resetForAssessment(); simulateEnter(0, 0); - simulateAuxDown(0, 0, 2); + simulateNonPrimaryDown(0, 0, 2); simulateMove(1, 1, 100); - simulateAuxUp(10, 10, 2); + simulateNonPrimaryUp(10, 10, 2); simulateMove(-1, -1, 100); simulateLeave(-1, -1); assessGestureExpectations({ - description: 'enter-auxpress-move-auxrelease-move-exit (secondary/right button drag, release in tracked element): ', + description: 'enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element): ', enterCount: 1, exitCount: 1, pressCount: 0, releaseCount: 0, rightPressCount: 1, rightReleaseCount: 1, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 200, clickCount: 0, dblClickCount: 0, @@ -591,8 +591,8 @@ releaseCount: 1, rightPressCount: 0, rightReleaseCount: 0, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 200, clickCount: 1, dblClickCount: 0, @@ -622,8 +622,8 @@ releaseCount: 1, rightPressCount: 0, rightReleaseCount: 0, - auxPressCount: 0, - auxReleaseCount: 0, + middlePressCount: 0, + middleReleaseCount: 0, moveCount: 15, clickCount: 0, dblClickCount: 0, @@ -652,8 +652,8 @@ // releaseCount: 1, // rightPressCount: 0, // rightReleaseCount: 0, - // auxPressCount: 0, - // auxReleaseCount: 0, + // middlePressCount: 0, + // middleReleaseCount: 0, // moveCount: 10, // clickCount: 0, // dblClickCount: 0, From d582a9563f80b3352b4259df881aad049d009c45 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Mon, 12 Jan 2015 12:26:38 -0800 Subject: [PATCH 16/52] capturePointer()/releasePointer() call fix for pointer event model --- src/mousetracker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 86e23f70..d1722b16 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -2104,7 +2104,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { $.stopEvent( event ); - capturePointer( tracker, 'pointer' ); + capturePointer( tracker, gPoint.type ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { @@ -2154,7 +2154,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - releasePointer( tracker, 'pointer' ); + releasePointer( tracker, gPoint.type ); } } From 1bdb83dc583889582c23d7276659143bdaf41fee Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Mon, 12 Jan 2015 12:56:18 -0800 Subject: [PATCH 17/52] Second attempt: capturePointer()/releasePointer() call fix for pointer event model --- src/mousetracker.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index d1722b16..d566f54a 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -1250,17 +1250,17 @@ * @private * @inner */ - function capturePointer( tracker, pointerType ) { + function capturePointer( tracker, pointerType, isPointerEventModel ) { var pointsList = tracker.getActivePointersListByType( pointerType ), eventParams; pointsList.captureCount++; if ( pointsList.captureCount === 1 ) { - if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 10 ) { tracker.element.setCapture( true ); } else { - eventParams = getCaptureEventParams( tracker, pointerType ); + eventParams = getCaptureEventParams( tracker, tracker, isPointerEventModel ? 'pointerevent' : pointerType ); // We emulate mouse capture by hanging listeners on the document object. // (Note we listen on the capture phase so the captured handlers will get called first) $.addEvent( @@ -1285,17 +1285,17 @@ * @private * @inner */ - function releasePointer( tracker, pointerType ) { + function releasePointer( tracker, pointerType, isPointerEventModel ) { var pointsList = tracker.getActivePointersListByType( pointerType ), eventParams; pointsList.captureCount--; if ( pointsList.captureCount === 0 ) { - if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 10 ) { tracker.element.releaseCapture(); } else { - eventParams = getCaptureEventParams( tracker, pointerType ); + eventParams = getCaptureEventParams( tracker, isPointerEventModel ? 'pointerevent' : pointerType ); // We emulate mouse capture by hanging listeners on the document object. // (Note we listen on the capture phase so the captured handlers will get called first) $.removeEvent( @@ -1718,7 +1718,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { $.stopEvent( event ); - capturePointer( tracker, 'mouse' ); + capturePointer( tracker, 'mouse', false ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) { @@ -1766,7 +1766,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { - releasePointer( tracker, 'mouse' ); + releasePointer( tracker, 'mouse', false ); } } @@ -1889,7 +1889,7 @@ if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact $.stopEvent( event ); - capturePointer( tracker, 'touch' ); + capturePointer( tracker, 'touch', false ); } $.cancelEvent( event ); @@ -1941,7 +1941,7 @@ } if ( updatePointersUp( tracker, event, gPoints, 0 ) ) { - releasePointer( tracker, 'touch' ); + releasePointer( tracker, 'touch', false ); } // simulate touchleave if not natively available @@ -2104,7 +2104,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { $.stopEvent( event ); - capturePointer( tracker, gPoint.type ); + capturePointer( tracker, gPoint.type, true ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { @@ -2154,7 +2154,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - releasePointer( tracker, gPoint.type ); + releasePointer( tracker, gPoint.type, true ); } } From 7b6f7d6a5b35ec2ff9dc0b5ed116e2c21c35e8c1 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 12 Jan 2015 13:40:33 -0800 Subject: [PATCH 18/52] Changelog for #561 --- changelog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.txt b/changelog.txt index 779df7b5..f9a8cda9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,8 @@ OPENSEADRAGON CHANGELOG 1.2.1: (in progress) +* Added preserveOverlays option (#561) + 1.2.0: * New combined IIIF TileSource for 1.0 through 2.0 (#441) From 753bf64e8a4d9cb6ce0dfd16d89b0be278cdafbe Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 12 Jan 2015 14:18:39 -0800 Subject: [PATCH 19/52] * Fixed: DZI tilesource was broken --- src/dzitilesource.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/dzitilesource.js b/src/dzitilesource.js index eb283fab..99dd92d1 100644 --- a/src/dzitilesource.js +++ b/src/dzitilesource.js @@ -107,8 +107,10 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead var ns; if ( data.Image ) { ns = data.Image.xmlns; - } else if ( data.documentElement && "Image" == data.documentElement.localName ) { - ns = data.documentElement.namespaceURI; + } else if ( data.documentElement) { + if ("Image" == data.documentElement.localName || "Image" == data.documentElement.tagName) { + ns = data.documentElement.namespaceURI; + } } return ( "http://schemas.microsoft.com/deepzoom/2008" == ns || @@ -221,7 +223,7 @@ function configureFromXML( tileSource, xmlDoc ){ } var root = xmlDoc.documentElement, - rootName = root.localName, + rootName = root.localName || root.tagName, ns = xmlDoc.documentElement.namespaceURI, configuration = null, displayRects = [], @@ -234,7 +236,10 @@ function configureFromXML( tileSource, xmlDoc ){ if ( rootName == "Image" ) { try { - sizeNode = root.getElementsByTagNameNS(ns, "Size" )[ 0 ]; + sizeNode = root.getElementsByTagName("Size" )[ 0 ]; + if (sizeNode === undefined) { + sizeNode = root.getElementsByTagNameNS(ns, "Size" )[ 0 ]; + } configuration = { Image: { @@ -257,11 +262,17 @@ function configureFromXML( tileSource, xmlDoc ){ ); } - dispRectNodes = root.getElementsByTagNameNS(ns, "DisplayRect" ); + dispRectNodes = root.getElementsByTagName("DisplayRect" ); + if (dispRectNodes === undefined) { + dispRectNodes = root.getElementsByTagNameNS(ns, "DisplayRect" )[ 0 ]; + } for ( i = 0; i < dispRectNodes.length; i++ ) { dispRectNode = dispRectNodes[ i ]; - rectNode = dispRectNode.getElementsByTagNameNS(ns, "Rect" )[ 0 ]; + rectNode = dispRectNode.getElementsByTagName("Rect" )[ 0 ]; + if (rectNode === undefined) { + rectNode = dispRectNode.getElementsByTagNameNS(ns, "Rect" )[ 0 ]; + } displayRects.push({ Rect: { From 00edbe565a40cb192bda753d1d7807571cf0c82a Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 12 Jan 2015 14:21:57 -0800 Subject: [PATCH 20/52] Changelog for #563 --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index f9a8cda9..903e3062 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,7 @@ OPENSEADRAGON CHANGELOG 1.2.1: (in progress) * Added preserveOverlays option (#561) +* Fixed: DZI tilesource was broken (#563) 1.2.0: From 83b7d7597ac7c74422d23f16c94ad2dc287db15c Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 12 Jan 2015 14:22:10 -0800 Subject: [PATCH 21/52] Added a note about preserveOverlays --- src/openseadragon.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openseadragon.js b/src/openseadragon.js index e1a37e2f..27d3262c 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -515,15 +515,17 @@ * * @property {Boolean} [preserveViewport=false] * If the viewer has been configured with a sequence of tile sources, then - * normally navigating to through each image resets the viewport to 'home' + * normally navigating through each image resets the viewport to 'home' * position. If preserveViewport is set to true, then the viewport position * is preserved when navigating between images in the sequence. * * @property {Boolean} [preserveOverlays=false] * If the viewer has been configured with a sequence of tile sources, then - * normally navigating to through each image resets the overlays. + * normally navigating through each image resets the overlays. * If preserveOverlays is set to true, then the overlays * are preserved when navigating between images in the sequence. + * Note: setting preserveOverlays overrides any overlays specified in the + * "overlays" property. * * @property {Boolean} [showReferenceStrip=false] * If the viewer has been configured with a sequence of tile sources, then From 1c465ec59c13920c56c3a4655dc75af619174989 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Mon, 12 Jan 2015 15:33:18 -0800 Subject: [PATCH 22/52] Revert "Second attempt: capturePointer()/releasePointer() call fix for pointer event model" This reverts commit 1bdb83dc583889582c23d7276659143bdaf41fee. --- src/mousetracker.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index d566f54a..d1722b16 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -1250,17 +1250,17 @@ * @private * @inner */ - function capturePointer( tracker, pointerType, isPointerEventModel ) { + function capturePointer( tracker, pointerType ) { var pointsList = tracker.getActivePointersListByType( pointerType ), eventParams; pointsList.captureCount++; if ( pointsList.captureCount === 1 ) { - if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 10 ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { tracker.element.setCapture( true ); } else { - eventParams = getCaptureEventParams( tracker, tracker, isPointerEventModel ? 'pointerevent' : pointerType ); + eventParams = getCaptureEventParams( tracker, pointerType ); // We emulate mouse capture by hanging listeners on the document object. // (Note we listen on the capture phase so the captured handlers will get called first) $.addEvent( @@ -1285,17 +1285,17 @@ * @private * @inner */ - function releasePointer( tracker, pointerType, isPointerEventModel ) { + function releasePointer( tracker, pointerType ) { var pointsList = tracker.getActivePointersListByType( pointerType ), eventParams; pointsList.captureCount--; if ( pointsList.captureCount === 0 ) { - if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 10 ) { + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { tracker.element.releaseCapture(); } else { - eventParams = getCaptureEventParams( tracker, isPointerEventModel ? 'pointerevent' : pointerType ); + eventParams = getCaptureEventParams( tracker, pointerType ); // We emulate mouse capture by hanging listeners on the document object. // (Note we listen on the capture phase so the captured handlers will get called first) $.removeEvent( @@ -1718,7 +1718,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { $.stopEvent( event ); - capturePointer( tracker, 'mouse', false ); + capturePointer( tracker, 'mouse' ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) { @@ -1766,7 +1766,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) { - releasePointer( tracker, 'mouse', false ); + releasePointer( tracker, 'mouse' ); } } @@ -1889,7 +1889,7 @@ if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact $.stopEvent( event ); - capturePointer( tracker, 'touch', false ); + capturePointer( tracker, 'touch' ); } $.cancelEvent( event ); @@ -1941,7 +1941,7 @@ } if ( updatePointersUp( tracker, event, gPoints, 0 ) ) { - releasePointer( tracker, 'touch', false ); + releasePointer( tracker, 'touch' ); } // simulate touchleave if not natively available @@ -2104,7 +2104,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { $.stopEvent( event ); - capturePointer( tracker, gPoint.type, true ); + capturePointer( tracker, gPoint.type ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { @@ -2154,7 +2154,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - releasePointer( tracker, gPoint.type, true ); + releasePointer( tracker, gPoint.type ); } } From 83ff3651216717e36a220936f98dc11866709813 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Mon, 12 Jan 2015 15:33:51 -0800 Subject: [PATCH 23/52] Revert "capturePointer()/releasePointer() call fix for pointer event model" This reverts commit d582a9563f80b3352b4259df881aad049d009c45. --- src/mousetracker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index d1722b16..86e23f70 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -2104,7 +2104,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { $.stopEvent( event ); - capturePointer( tracker, gPoint.type ); + capturePointer( tracker, 'pointer' ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { @@ -2154,7 +2154,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - releasePointer( tracker, gPoint.type ); + releasePointer( tracker, 'pointer' ); } } From 0d6fca35c114e620d40252df7ad0fb9c46444fc5 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Mon, 12 Jan 2015 16:08:26 -0800 Subject: [PATCH 24/52] Fix pointer type passed to capturePointer/releasePointer in pointer events model. Remembered to change the test shim as well. --- src/mousetracker.js | 27 ++++++++++++++++----------- test/legacy.mouse.shim.js | 12 ++++++++++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 86e23f70..09b3c751 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -880,6 +880,7 @@ if ( window.PointerEvent ) { // IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents) + $.MouseTracker.havePointerEvents = true; $.MouseTracker.subscribeEvents.push( "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" ); $.MouseTracker.unprefixedPointerEvents = true; if( navigator.maxTouchPoints ) { @@ -891,6 +892,7 @@ $.MouseTracker.haveMouseEnter = false; } else if ( window.MSPointerEvent ) { // IE10 + $.MouseTracker.havePointerEvents = true; $.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); $.MouseTracker.unprefixedPointerEvents = false; if( navigator.msMaxTouchPoints ) { @@ -902,6 +904,7 @@ $.MouseTracker.haveMouseEnter = false; } else { // Legacy W3C mouse events + $.MouseTracker.havePointerEvents = false; if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" ); $.MouseTracker.haveMouseEnter = true; @@ -1221,7 +1224,14 @@ function getCaptureEventParams( tracker, pointerType ) { var delegate = THIS[ tracker.hash ]; - if ( pointerType === 'mouse' ) { + if ( pointerType === 'pointerevent' ) { + return { + upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', + upHandler: delegate.pointerupcaptured, + moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', + moveHandler: delegate.pointermovecaptured + }; + } else if ( pointerType === 'mouse' ) { return { upName: 'mouseup', upHandler: delegate.mouseupcaptured, @@ -1236,12 +1246,7 @@ moveHandler: delegate.touchmovecaptured }; } else { - return { - upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp', - upHandler: delegate.pointerupcaptured, - moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove', - moveHandler: delegate.pointermovecaptured - }; + throw new Error( "MouseTracker.getCaptureEventParams: Unknown pointer type." ); } } @@ -1260,7 +1265,7 @@ if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { tracker.element.setCapture( true ); } else { - eventParams = getCaptureEventParams( tracker, pointerType ); + eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType ); // We emulate mouse capture by hanging listeners on the document object. // (Note we listen on the capture phase so the captured handlers will get called first) $.addEvent( @@ -1295,7 +1300,7 @@ if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { tracker.element.releaseCapture(); } else { - eventParams = getCaptureEventParams( tracker, pointerType ); + eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : pointerType ); // We emulate mouse capture by hanging listeners on the document object. // (Note we listen on the capture phase so the captured handlers will get called first) $.removeEvent( @@ -2104,7 +2109,7 @@ if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { $.stopEvent( event ); - capturePointer( tracker, 'pointer' ); + capturePointer( tracker, gPoint.type ); } if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { @@ -2154,7 +2159,7 @@ }; if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { - releasePointer( tracker, 'pointer' ); + releasePointer( tracker, gPoint.type ); } } diff --git a/test/legacy.mouse.shim.js b/test/legacy.mouse.shim.js index 7a8ff7cc..535f8815 100644 --- a/test/legacy.mouse.shim.js +++ b/test/legacy.mouse.shim.js @@ -11,8 +11,15 @@ $.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" ); } - $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" ); - $.MouseTracker.haveMouseEnter = false; + $.MouseTracker.havePointerEvents = false; + if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) { + $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" ); + $.MouseTracker.haveMouseEnter = true; + } else { + $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" ); + $.MouseTracker.haveMouseEnter = false; + } + $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" ); if ( 'ontouchstart' in window ) { // iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505) $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); @@ -33,4 +40,5 @@ $.MouseTracker.mousePointerId = "legacy-mouse"; $.MouseTracker.maxTouchPoints = 10; + }(OpenSeadragon)); From cc1b6b7c6ff05467e76ba0c774ae557cd34f0ac5 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 13 Jan 2015 08:41:02 -0800 Subject: [PATCH 25/52] Minor events.js test comment fix --- test/events.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/events.js b/test/events.js index 43069e96..5f850082 100644 --- a/test/events.js +++ b/test/events.js @@ -201,15 +201,16 @@ var simulateLeave = function (x, y) { simEvent.clientX = offset.left + x; simEvent.clientY = offset.top + y; - // simEvent.relatedTarget = document.body; - // $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); - //}; + simEvent.relatedTarget = document.body; + $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); + }; + //var simulateLeaveFrame = function (x, y) { // simEvent.clientX = offset.left + x; // simEvent.clientY = offset.top + y; // simEvent.relatedTarget = document.getElementsByTagName("html")[0]; - $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); - }; + // $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); + //}; var simulateDown = function (x, y) { simEvent.button = 0; From aa735c1e001213db999e63d1a7fe5c599603c9f4 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Tue, 13 Jan 2015 09:27:39 -0800 Subject: [PATCH 26/52] Changelog fix --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 0bff9545..04986505 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ OPENSEADRAGON CHANGELOG 1.2.1: (in progress) * Added preserveOverlays option (#561) -* Fixed: DZI tilesource was broken (#563) +* Fixed: DZI tilesource was broken on IE8/IE9 (#563) * Exposed secondary pointer button (middle, right, etc.) events from MouseTracker and through viewer (#479) * MouseTracker - Improved IE 8 compatibility (#562) From d26d3f939319b5bbd1e943c201c9e606c1f8d8ca Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 14 Jan 2015 08:44:14 -0800 Subject: [PATCH 27/52] MouseTracker - Improved IE 9+ compatibility --- src/mousetracker.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 09b3c751..c90382f9 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -215,7 +215,6 @@ MSPointerOver: function ( event ) { onPointerOver( _this, event ); }, pointerout: function ( event ) { onPointerOut( _this, event ); }, MSPointerOut: function ( event ) { onPointerOut( _this, event ); }, - pointerdown: function ( event ) { onPointerDown( _this, event ); }, MSPointerDown: function ( event ) { onPointerDown( _this, event ); }, pointerup: function ( event ) { onPointerUp( _this, event ); }, @@ -1609,7 +1608,7 @@ function onMouseOver( tracker, event ) { event = $.getEvent( event ); - if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { return; } @@ -1654,7 +1653,7 @@ function onMouseOut( tracker, event ) { event = $.getEvent( event ); - if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { return; } @@ -2054,7 +2053,7 @@ function onPointerOver( tracker, event ) { var gPoint; - if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { return; } @@ -2077,7 +2076,7 @@ function onPointerOut( tracker, event ) { var gPoint; - if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { + if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { return; } @@ -2092,6 +2091,7 @@ updatePointersExit( tracker, event, [ gPoint ] ); } + /** * @private * @inner From 960b4a0d14ab66df7447559336c3cd1db0994d2f Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 14 Jan 2015 08:46:06 -0800 Subject: [PATCH 28/52] changelog update --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 04986505..2e64452b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,7 @@ OPENSEADRAGON CHANGELOG * Fixed: DZI tilesource was broken on IE8/IE9 (#563) * Exposed secondary pointer button (middle, right, etc.) events from MouseTracker and through viewer (#479) * MouseTracker - Improved IE 8 compatibility (#562) +* MouseTracker - Improved IE 9+ compatibility (#564) 1.2.0: From cb56e352cfce113af68d67b9247a12247638e80d Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Thu, 15 Jan 2015 12:15:22 -0800 Subject: [PATCH 29/52] Mousetracker Improvements 1) MouseTracker - Simulated touchenter/touchleave events now bubble to parent element MouseTrackers 2) MouseTracker - Improved multitouch support in enter/exit event handlers 3) MouseTracker - orphaned tracked touch pointers removed (fix for #539) 4) MouseTracker - removed touchenter/touchleave event support since the events don't exist on any known platform and have been removed from the W3C specification 5) Removed Viewer onContainerPress/onContainerRelease handlers (and the associated 'container-release' event ) that were never fired due to the canvas (child) element capturing the DOM events 6) Added 'canvas-enter', 'canvas-exit', and 'canvas-press' events to Viewer 7) ButtonGroup - removed obsolete MouseTracker event handlers --- src/buttongroup.js | 16 ---- src/mousetracker.js | 159 +++++++++++++++++++------------ src/viewer.js | 190 ++++++++++++++++++++++++-------------- test/legacy.mouse.shim.js | 15 +-- 4 files changed, 228 insertions(+), 152 deletions(-) diff --git a/src/buttongroup.js b/src/buttongroup.js index 2837805a..7505af0a 100644 --- a/src/buttongroup.js +++ b/src/buttongroup.js @@ -105,22 +105,6 @@ $.ButtonGroup = function( options ) { } } }, - pressHandler: function ( event ) { - if ( event.pointerType === 'touch' && !$.MouseTracker.haveTouchEnter ) { - var i; - for ( i = 0; i < _this.buttons.length; i++ ) { - _this.buttons[ i ].notifyGroupEnter(); - } - } - }, - releaseHandler: function ( event ) { - var i; - if ( !event.insideElementReleased || ( event.pointerType === 'touch' && !$.MouseTracker.haveTouchEnter ) ) { - for ( i = 0; i < _this.buttons.length; i++ ) { - _this.buttons[ i ].notifyGroupExit(); - } - } - } }).setTracking( true ); }; diff --git a/src/mousetracker.js b/src/mousetracker.js index c90382f9..8d2c0b74 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -34,7 +34,10 @@ (function ( $ ) { - // dictionary from hash to private properties + // All MouseTracker instances + var MOUSETRACKERS = []; + + // dictionary from hash to private properties var THIS = {}; @@ -103,6 +106,8 @@ */ $.MouseTracker = function ( options ) { + MOUSETRACKERS.push( this ); + var args = arguments; if ( !$.isPlainObject( options ) ) { @@ -199,8 +204,6 @@ mousemove: function ( event ) { onMouseMove( _this, event ); }, mousemovecaptured: function ( event ) { onMouseMoveCaptured( _this, event ); }, - touchenter: function ( event ) { onTouchEnter( _this, event ); }, - touchleave: function ( event ) { onTouchLeave( _this, event ); }, touchstart: function ( event ) { onTouchStart( _this, event ); }, touchend: function ( event ) { onTouchEnd( _this, event ); }, touchendcaptured: function ( event ) { onTouchEndCaptured( _this, event ); }, @@ -255,9 +258,18 @@ * @function */ destroy: function () { + var i; + stopTracking( this ); this.element = null; + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] === this ) { + MOUSETRACKERS.splice( i, 1 ); + break; + } + } + THIS[ this.hash ] = null; delete THIS[ this.hash ]; }, @@ -312,6 +324,24 @@ return list; }, + /** + * Returns the total number of pointers currently active on the tracked element. + * @function + * @returns {Number} + */ + getActivePointerCount: function () { + var delegate = THIS[ this.hash ], + i, + len = delegate.activePointersLists.length, + count = 0; + + for ( i = 0; i < len; i++ ) { + count += delegate.activePointersLists[ i ].getLength(); + } + + return count; + }, + /** * Implement or assign implementation to these handlers during or after * calling the constructor. @@ -326,6 +356,8 @@ * @param {Number} event.buttons * Current buttons pressed. * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Number} event.pointers + * Number of pointers (all types) active in the tracked element. * @param {Boolean} event.insideElementPressed * True if the left mouse button is currently being pressed and was * initiated inside the tracked element, otherwise false. @@ -356,6 +388,8 @@ * @param {Number} event.buttons * Current buttons pressed. * Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @param {Number} event.pointers + * Number of pointers (all types) active in the tracked element. * @param {Boolean} event.insideElementPressed * True if the left mouse button is currently being pressed and was * initiated inside the tracked element, otherwise false. @@ -887,7 +921,6 @@ } else { $.MouseTracker.maxTouchPoints = 0; } - $.MouseTracker.haveTouchEnter = false; $.MouseTracker.haveMouseEnter = false; } else if ( window.MSPointerEvent ) { // IE10 @@ -899,7 +932,6 @@ } else { $.MouseTracker.maxTouchPoints = 0; } - $.MouseTracker.haveTouchEnter = false; $.MouseTracker.haveMouseEnter = false; } else { // Legacy W3C mouse events @@ -913,19 +945,14 @@ } $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" ); if ( 'ontouchstart' in window ) { - // iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505) + // iOS, Android, and other W3c Touch Event implementations + // (see http://www.w3.org/TR/touch-events/) + // (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) + // (see https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); - if ( 'ontouchenter' in window ) { - $.MouseTracker.subscribeEvents.push( "touchenter", "touchleave" ); - $.MouseTracker.haveTouchEnter = true; - } else { - $.MouseTracker.haveTouchEnter = false; - } - } else { - $.MouseTracker.haveTouchEnter = false; } if ( 'ongesturestart' in window ) { - // iOS (see https://developer.apple.com/library/safari/documentation/UserExperience/Reference/GestureEventClassReference/GestureEvent/GestureEvent.html) + // iOS (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) // Subscribe to these to prevent default gesture handling $.MouseTracker.subscribeEvents.push( "gesturestart", "gesturechange" ); } @@ -1822,45 +1849,21 @@ * @private * @inner */ - function onTouchEnter( tracker, event ) { + function abortTouchContacts( tracker, event, pointsList ) { var i, - touchCount = event.changedTouches.length, - gPoints = []; + gPointCount = pointsList.getLength(), + abortGPoints = []; - for ( i = 0; i < touchCount; i++ ) { - gPoints.push( { - id: event.changedTouches[ i ].identifier, - type: 'touch', - // isPrimary not set - let the updatePointers functions determine it - currentPos: getMouseAbsolute( event.changedTouches[ i ] ), - currentTime: $.now() - } ); + for ( i = 0; i < gPointCount; i++ ) { + abortGPoints.push( pointsList.getByIndex( i ) ); } - updatePointersEnter( tracker, event, gPoints ); - } - - - /** - * @private - * @inner - */ - function onTouchLeave( tracker, event ) { - var i, - touchCount = event.changedTouches.length, - gPoints = []; - - for ( i = 0; i < touchCount; i++ ) { - gPoints.push( { - id: event.changedTouches[ i ].identifier, - type: 'touch', - // isPrimary not set - let the updatePointers functions determine it - currentPos: getMouseAbsolute( event.changedTouches[ i ] ), - currentTime: $.now() - } ); + if ( abortGPoints.length > 0 ) { + // simulate touchend + updatePointersUp( tracker, event, abortGPoints, 0 ); // 0 means primary button press/release or touch contact + // simulate touchleave + updatePointersExit( tracker, event, abortGPoints ); } - - updatePointersExit( tracker, event, gPoints ); } @@ -1871,11 +1874,19 @@ function onTouchStart( tracker, event ) { var time, i, + j, touchCount = event.changedTouches.length, - gPoints = []; + gPoints = [], + parentGPoints, + pointsList = tracker.getActivePointersListByType( 'touch' ); time = $.now(); + if ( pointsList.getLength() > event.touches.length - touchCount ) { + $.console.warn('Tracked touch contact count doesn\'t match event.touches.length. Removing all tracked touch pointers.'); + abortTouchContacts( tracker, event, pointsList ); + } + for ( i = 0; i < touchCount; i++ ) { gPoints.push( { id: event.changedTouches[ i ].identifier, @@ -1886,9 +1897,24 @@ } ); } - // simulate touchenter if not natively available - if ( !$.MouseTracker.haveTouchEnter ) { - updatePointersEnter( tracker, event, gPoints ); + // simulate touchenter on our tracked element + updatePointersEnter( tracker, event, gPoints ); + + // simulate touchenter on our tracked element's tracked ancestor elements + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) { + parentGPoints = []; + for ( j = 0; j < touchCount; j++ ) { + parentGPoints.push( { + id: event.changedTouches[ j ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ j ] ), + currentTime: time + } ); + } + updatePointersEnter( MOUSETRACKERS[ i ], event, parentGPoints ); + } } if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact @@ -1929,8 +1955,10 @@ function handleTouchEnd( tracker, event ) { var time, i, + j, touchCount = event.changedTouches.length, - gPoints = []; + gPoints = [], + parentGPoints; time = $.now(); @@ -1948,9 +1976,24 @@ releasePointer( tracker, 'touch' ); } - // simulate touchleave if not natively available - if ( !$.MouseTracker.haveTouchEnter && touchCount > 0 ) { - updatePointersExit( tracker, event, gPoints ); + // simulate touchleave on our tracked element + updatePointersExit( tracker, event, gPoints ); + + // simulate touchleave on our tracked element's tracked ancestor elements + for ( i = 0; i < MOUSETRACKERS.length; i++ ) { + if ( MOUSETRACKERS[ i ] !== tracker && MOUSETRACKERS[ i ].isTracking() && isParentChild( MOUSETRACKERS[ i ].element, tracker.element ) ) { + parentGPoints = []; + for ( j = 0; j < touchCount; j++ ) { + parentGPoints.push( { + id: event.changedTouches[ j ].identifier, + type: 'touch', + // isPrimary not set - let the updatePointers functions determine it + currentPos: getMouseAbsolute( event.changedTouches[ j ] ), + currentTime: time + } ); + } + updatePointersExit( MOUSETRACKERS[ i ], event, parentGPoints ); + } } $.cancelEvent( event ); @@ -2344,6 +2387,7 @@ pointerType: curGPoint.type, position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ), buttons: pointsList.buttons, + pointers: tracker.getActivePointerCount(), insideElementPressed: curGPoint.insideElementPressed, buttonDownAny: pointsList.buttons !== 0, isTouchEvent: curGPoint.type === 'touch', @@ -2407,6 +2451,7 @@ pointerType: curGPoint.type, position: getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ), buttons: pointsList.buttons, + pointers: tracker.getActivePointerCount(), insideElementPressed: updateGPoint ? updateGPoint.insideElementPressed : false, buttonDownAny: pointsList.buttons !== 0, isTouchEvent: curGPoint.type === 'touch', diff --git a/src/viewer.js b/src/viewer.js index 2d2604d9..b26b1837 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -389,6 +389,9 @@ $.Viewer = function( options ) { dblClickHandler: $.delegate( this, onCanvasDblClick ), dragHandler: $.delegate( this, onCanvasDrag ), dragEndHandler: $.delegate( this, onCanvasDragEnd ), + enterHandler: $.delegate( this, onCanvasEnter ), + exitHandler: $.delegate( this, onCanvasExit ), + pressHandler: $.delegate( this, onCanvasPress ), releaseHandler: $.delegate( this, onCanvasRelease ), nonPrimaryPressHandler: $.delegate( this, onCanvasNonPrimaryPress ), nonPrimaryReleaseHandler: $.delegate( this, onCanvasNonPrimaryRelease ), @@ -403,9 +406,7 @@ $.Viewer = function( options ) { dblClickTimeThreshold: this.dblClickTimeThreshold, dblClickDistThreshold: this.dblClickDistThreshold, enterHandler: $.delegate( this, onContainerEnter ), - exitHandler: $.delegate( this, onContainerExit ), - pressHandler: $.delegate( this, onContainerPress ), - releaseHandler: $.delegate( this, onContainerRelease ) + exitHandler: $.delegate( this, onContainerExit ) }).setTracking( this.mouseNavEnabled ? true : false ); // always tracking if( this.toolbar ){ @@ -2430,6 +2431,92 @@ function onCanvasDragEnd( event ) { }); } +function onCanvasEnter( event ) { + /** + * Raised when a pointer enters the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-enter + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-enter', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + +function onCanvasExit( event ) { + /** + * Raised when a pointer leaves the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-exit + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-exit', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + buttons: event.buttons, + pointers: event.pointers, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + +function onCanvasPress( event ) { + /** + * Raised when the primary mouse button is pressed or touch starts on the {@link OpenSeadragon.Viewer#canvas} element. + * + * @event canvas-press + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'canvas-press', { + tracker: event.eventSource, + pointerType: event.pointerType, + position: event.position, + insideElementPressed: event.insideElementPressed, + insideElementReleased: event.insideElementReleased, + originalEvent: event.originalEvent + }); +} + function onCanvasRelease( event ) { /** * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element. @@ -2439,6 +2526,7 @@ function onCanvasRelease( event ) { * @type {object} * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {String} pointerType - "mouse", "touch", "pen", etc. * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released. @@ -2447,6 +2535,7 @@ function onCanvasRelease( event ) { */ this.raiseEvent( 'canvas-release', { tracker: event.eventSource, + pointerType: event.pointerType, position: event.position, insideElementPressed: event.insideElementPressed, insideElementReleased: event.insideElementReleased, @@ -2612,8 +2701,36 @@ function onCanvasScroll( event ) { return false; } +function onContainerEnter( event ) { + THIS[ this.hash ].mouseInside = true; + abortControlsAutoHide( this ); + /** + * Raised when the cursor enters the {@link OpenSeadragon.Viewer#container} element. + * + * @event container-enter + * @memberof OpenSeadragon.Viewer + * @type {object} + * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. + * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. + * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. + * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. + * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. + * @property {Object} originalEvent - The original DOM event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'container-enter', { + tracker: event.eventSource, + position: event.position, + buttons: event.buttons, + insideElementPressed: event.insideElementPressed, + buttonDownAny: event.buttonDownAny, + originalEvent: event.originalEvent + }); +} + function onContainerExit( event ) { - if ( !event.insideElementPressed ) { + if ( event.pointers < 1 ) { THIS[ this.hash ].mouseInside = false; if ( !THIS[ this.hash ].animating ) { beginControlsAutoHide( this ); @@ -2644,71 +2761,6 @@ function onContainerExit( event ) { }); } -function onContainerPress( event ) { - if ( event.pointerType === 'touch' && !$.MouseTracker.haveTouchEnter ) { - THIS[ this.hash ].mouseInside = true; - abortControlsAutoHide( this ); - } -} - -function onContainerRelease( event ) { - if ( !event.insideElementReleased || ( event.pointerType === 'touch' && !$.MouseTracker.haveTouchEnter ) ) { - THIS[ this.hash ].mouseInside = false; - if ( !THIS[ this.hash ].animating ) { - beginControlsAutoHide( this ); - } - } - /** - * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#container} element. - * - * @event container-release - * @memberof OpenSeadragon.Viewer - * @type {object} - * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. - * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. - * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. - * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. - * @property {Boolean} insideElementReleased - True if the cursor still inside the tracked element when the button was released. - * @property {Object} originalEvent - The original DOM event. - * @property {?Object} userData - Arbitrary subscriber-defined object. - */ - this.raiseEvent( 'container-release', { - tracker: event.eventSource, - position: event.position, - insideElementPressed: event.insideElementPressed, - insideElementReleased: event.insideElementReleased, - originalEvent: event.originalEvent - }); -} - -function onContainerEnter( event ) { - THIS[ this.hash ].mouseInside = true; - abortControlsAutoHide( this ); - /** - * Raised when the cursor enters the {@link OpenSeadragon.Viewer#container} element. - * - * @event container-enter - * @memberof OpenSeadragon.Viewer - * @type {object} - * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event. - * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. - * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. - * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. - * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. - * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. - * @property {Object} originalEvent - The original DOM event. - * @property {?Object} userData - Arbitrary subscriber-defined object. - */ - this.raiseEvent( 'container-enter', { - tracker: event.eventSource, - position: event.position, - buttons: event.buttons, - insideElementPressed: event.insideElementPressed, - buttonDownAny: event.buttonDownAny, - originalEvent: event.originalEvent - }); -} - /////////////////////////////////////////////////////////////////////////////// // Page update routines ( aka Views - for future reference ) diff --git a/test/legacy.mouse.shim.js b/test/legacy.mouse.shim.js index 535f8815..3609ed85 100644 --- a/test/legacy.mouse.shim.js +++ b/test/legacy.mouse.shim.js @@ -21,19 +21,14 @@ } $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" ); if ( 'ontouchstart' in window ) { - // iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505) + // iOS, Android, and other W3c Touch Event implementations + // (see http://www.w3.org/TR/touch-events/) + // (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) + // (see https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); - if ( 'ontouchenter' in window ) { - $.MouseTracker.subscribeEvents.push( "touchenter", "touchleave" ); - $.MouseTracker.haveTouchEnter = true; - } else { - $.MouseTracker.haveTouchEnter = false; - } - } else { - $.MouseTracker.haveTouchEnter = false; } if ( 'ongesturestart' in window ) { - // iOS (see https://developer.apple.com/library/safari/documentation/UserExperience/Reference/GestureEventClassReference/GestureEvent/GestureEvent.html) + // iOS (see https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html) // Subscribe to these to prevent default gesture handling $.MouseTracker.subscribeEvents.push( "gesturestart", "gesturechange" ); } From 3d8ddcf1ff1c8afa9f3f8e7e30059760d4b14ea7 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Thu, 15 Jan 2015 12:18:35 -0800 Subject: [PATCH 30/52] changelog update --- changelog.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.txt b/changelog.txt index 2e64452b..ad7ff86f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,13 @@ OPENSEADRAGON CHANGELOG * Exposed secondary pointer button (middle, right, etc.) events from MouseTracker and through viewer (#479) * MouseTracker - Improved IE 8 compatibility (#562) * MouseTracker - Improved IE 9+ compatibility (#564) +* MouseTracker - Simulated touchenter/touchleave events now bubble to parent element MouseTrackers (#566) +* MouseTracker - Improved multitouch support in enter/exit event handlers (#566) +* MouseTracker - orphaned tracked touch pointers removed (fix for #539) +* MouseTracker - removed touchenter/touchleave event support since the events don't exist on any known platform and have been removed from the W3C specification (#566) +* Removed Viewer onContainerPress/onContainerRelease handlers (and the associated 'container-release' event ) that were never fired due to the canvas (child) element capturing the DOM events (#566) +* Added 'canvas-enter', 'canvas-exit', and 'canvas-press' events to Viewer (#566) +* ButtonGroup - removed obsolete MouseTracker event handlers (#566) 1.2.0: From 00aae52a08619f12fb8b81f9b2df49bfac868de0 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Thu, 15 Jan 2015 12:37:54 -0800 Subject: [PATCH 31/52] Fix container-enter/container-exit event properties --- src/viewer.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/viewer.js b/src/viewer.js index b26b1837..215f9432 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2714,6 +2714,7 @@ function onContainerEnter( event ) { * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. * @property {Object} originalEvent - The original DOM event. @@ -2723,6 +2724,7 @@ function onContainerEnter( event ) { tracker: event.eventSource, position: event.position, buttons: event.buttons, + pointers: event.pointers, insideElementPressed: event.insideElementPressed, buttonDownAny: event.buttonDownAny, originalEvent: event.originalEvent @@ -2746,6 +2748,7 @@ function onContainerExit( event ) { * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event. * @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element. * @property {Number} buttons - Current buttons pressed. A combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser. + * @property {Number} pointers - Number of pointers (all types) active in the tracked element. * @property {Boolean} insideElementPressed - True if the left mouse button is currently being pressed and was initiated inside the tracked element, otherwise false. * @property {Boolean} buttonDownAny - Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead. * @property {Object} originalEvent - The original DOM event. @@ -2755,6 +2758,7 @@ function onContainerExit( event ) { tracker: event.eventSource, position: event.position, buttons: event.buttons, + pointers: event.pointers, insideElementPressed: event.insideElementPressed, buttonDownAny: event.buttonDownAny, originalEvent: event.originalEvent From 8e5e2168c832135f182b8b85eddb014e17ea6f1e Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Fri, 16 Jan 2015 08:33:34 -0800 Subject: [PATCH 32/52] Ensure capture released in abortTouchContacts() --- src/mousetracker.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mousetracker.js b/src/mousetracker.js index 8d2c0b74..20748ba0 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -1861,6 +1861,9 @@ if ( abortGPoints.length > 0 ) { // simulate touchend updatePointersUp( tracker, event, abortGPoints, 0 ); // 0 means primary button press/release or touch contact + // release pointer capture + pointsList.captureCount = 1; + releasePointer( tracker, 'touch' ); // simulate touchleave updatePointersExit( tracker, event, abortGPoints ); } From 2831771af5a74f556e9d430104e411cbc6b28622 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Fri, 16 Jan 2015 16:26:30 -0800 Subject: [PATCH 33/52] MouseTracker - keyboard handling 1) MouseTracker - added keydown and keyup handlers 2) Modifier keys ignored in keyboard navigation handlers (#503) 3) Arrow key navigation fixed across platforms (#565) --- src/mousetracker.js | 133 +++++++++++++++++++++++++++++++++++++++++- src/referencestrip.js | 90 +++++++++++++++++++--------- src/viewer.js | 44 ++++++++++++-- 3 files changed, 231 insertions(+), 36 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 20748ba0..9e8f25ef 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -95,6 +95,10 @@ * An optional handler for after a drag gesture. * @param {OpenSeadragon.EventHandler} [options.pinchHandler=null] * An optional handler for the pinch gesture. + * @param {OpenSeadragon.EventHandler} [options.keyDownHandler=null] + * An optional handler for keydown. + * @param {OpenSeadragon.EventHandler} [options.keyUpHandler=null] + * An optional handler for keyup. * @param {OpenSeadragon.EventHandler} [options.keyHandler=null] * An optional handler for keypress. * @param {OpenSeadragon.EventHandler} [options.focusHandler=null] @@ -170,6 +174,8 @@ this.dragEndHandler = options.dragEndHandler || null; this.pinchHandler = options.pinchHandler || null; this.stopHandler = options.stopHandler || null; + this.keyDownHandler = options.keyDownHandler || null; + this.keyUpHandler = options.keyUpHandler || null; this.keyHandler = options.keyHandler || null; this.focusHandler = options.focusHandler || null; this.blurHandler = options.blurHandler || null; @@ -185,6 +191,8 @@ THIS[ this.hash ] = { click: function ( event ) { onClick( _this, event ); }, dblclick: function ( event ) { onDblClick( _this, event ); }, + keydown: function ( event ) { onKeyDown( _this, event ); }, + keyup: function ( event ) { onKeyUp( _this, event ); }, keypress: function ( event ) { onKeyPress( _this, event ); }, focus: function ( event ) { onFocus( _this, event ); }, blur: function ( event ) { onBlur( _this, event ); }, @@ -743,8 +751,66 @@ * A reference to the tracker instance. * @param {Number} event.keyCode * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. * @param {Boolean} event.shift * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + keyDownHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Number} event.keyCode + * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. + * @param {Object} event.originalEvent + * The original event object. + * @param {Boolean} event.preventDefaultAction + * Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false. + * @param {Object} event.userData + * Arbitrary user-defined object. + */ + keyUpHandler: function () { }, + + /** + * Implement or assign implementation to these handlers during or after + * calling the constructor. + * @function + * @param {Object} event + * @param {OpenSeadragon.MouseTracker} event.eventSource + * A reference to the tracker instance. + * @param {Number} event.keyCode + * The key code that was pressed. + * @param {Boolean} event.ctrl + * True if the ctrl key was pressed during this event. + * @param {Boolean} event.shift + * True if the shift key was pressed during this event. + * @param {Boolean} event.alt + * True if the alt key was pressed during this event. + * @param {Boolean} event.meta + * True if the meta key was pressed during this event. * @param {Object} event.originalEvent * The original event object. * @param {Boolean} event.preventDefaultAction @@ -904,7 +970,7 @@ /** * Detect browser pointer device event model(s) and build appropriate list of events to subscribe to. */ - $.MouseTracker.subscribeEvents = [ "click", "dblclick", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ]; + $.MouseTracker.subscribeEvents = [ "click", "dblclick", "keydown", "keyup", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ]; if( $.MouseTracker.wheelEventName == "DOMMouseScroll" ) { // Older Firefox @@ -1440,12 +1506,72 @@ } + /** + * @private + * @inner + */ + function onKeyDown( tracker, event ) { + //$.console.log( "keydown %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + var propagate; + if ( tracker.keyDownHandler ) { + event = $.getEvent( event ); + propagate = tracker.keyDownHandler( + { + eventSource: tracker, + position: getMouseRelative( event, tracker.element ), + keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( !propagate ) { + $.cancelEvent( event ); + } + } + } + + + /** + * @private + * @inner + */ + function onKeyUp( tracker, event ) { + //$.console.log( "keyup %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + var propagate; + if ( tracker.keyUpHandler ) { + event = $.getEvent( event ); + propagate = tracker.keyUpHandler( + { + eventSource: tracker, + position: getMouseRelative( event, tracker.element ), + keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, + shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, + originalEvent: event, + preventDefaultAction: false, + userData: tracker.userData + } + ); + if ( !propagate ) { + $.cancelEvent( event ); + } + } + } + + /** * @private * @inner */ function onKeyPress( tracker, event ) { - //console.log( "keypress %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); + //$.console.log( "keypress %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); var propagate; if ( tracker.keyHandler ) { event = $.getEvent( event ); @@ -1454,7 +1580,10 @@ eventSource: tracker, position: getMouseRelative( event, tracker.element ), keyCode: event.keyCode ? event.keyCode : event.charCode, + ctrl: event.ctrlKey, shift: event.shiftKey, + alt: event.altKey, + meta: event.metaKey, originalEvent: event, preventDefaultAction: false, userData: tracker.userData diff --git a/src/referencestrip.js b/src/referencestrip.js index f68744b2..a872ca58 100644 --- a/src/referencestrip.js +++ b/src/referencestrip.js @@ -125,6 +125,7 @@ $.ReferenceStrip = function ( options ) { scrollHandler: $.delegate( this, onStripScroll ), enterHandler: $.delegate( this, onStripEnter ), exitHandler: $.delegate( this, onStripExit ), + keyDownHandler: $.delegate( this, onKeyDown ), keyHandler: $.delegate( this, onKeyPress ) } ).setTracking( true ); @@ -511,6 +512,37 @@ function onStripExit( event ) { } +/** + * @private + * @inner + * @function + */ +function onKeyDown( event ) { + //console.log( event.keyCode ); + + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch ( event.keyCode ) { + case 38: //up arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 40: //down arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 37: //left arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 39: //right arrow + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + /** * @private @@ -520,35 +552,35 @@ function onStripExit( event ) { function onKeyPress( event ) { //console.log( event.keyCode ); - switch ( event.keyCode ) { - case 61: //=|+ - onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); - return false; - case 45: //-|_ - onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); - return false; - case 48: //0|) - case 119: //w - case 87: //W - case 38: //up arrow - onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); - return false; - case 115: //s - case 83: //S - case 40: //down arrow - onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); - return false; - case 97: //a - case 37: //left arrow - onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); - return false; - case 100: //d - case 39: //right arrow - onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); - return false; - default: - //console.log( 'navigator keycode %s', event.keyCode ); - return true; + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch ( event.keyCode ) { + case 61: //=|+ + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 45: //-|_ + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 48: //0|) + case 119: //w + case 87: //W + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + case 115: //s + case 83: //S + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 97: //a + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: -1, shift: null } ); + return false; + case 100: //d + onStripScroll.call( this, { eventSource: this.tracker, position: null, scroll: 1, shift: null } ); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; } } diff --git a/src/viewer.js b/src/viewer.js index 215f9432..1a7490d0 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -325,8 +325,44 @@ $.Viewer = function( options ) { } }, + keyDownHandler: function( event ){ + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch( event.keyCode ){ + case 38://up arrow + if ( event.shift ) { + _this.viewport.zoomBy(1.1); + } else { + _this.viewport.panBy(new $.Point(0, -0.05)); + } + _this.viewport.applyConstraints(); + return false; + case 40://down arrow + if ( event.shift ) { + _this.viewport.zoomBy(0.9); + } else { + _this.viewport.panBy(new $.Point(0, 0.05)); + } + _this.viewport.applyConstraints(); + return false; + case 37://left arrow + _this.viewport.panBy(new $.Point(-0.05, 0)); + _this.viewport.applyConstraints(); + return false; + case 39://right arrow + _this.viewport.panBy(new $.Point(0.05, 0)); + _this.viewport.applyConstraints(); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } + }, + keyHandler: function( event ){ - if ( !event.preventDefaultAction ) { + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { switch( event.keyCode ){ case 61://=|+ _this.viewport.zoomBy(1.1); @@ -342,7 +378,6 @@ $.Viewer = function( options ) { return false; case 119://w case 87://W - case 38://up arrow if ( event.shift ) { _this.viewport.zoomBy(1.1); } else { @@ -352,7 +387,6 @@ $.Viewer = function( options ) { return false; case 115://s case 83://S - case 40://down arrow if ( event.shift ) { _this.viewport.zoomBy(0.9); } else { @@ -361,12 +395,10 @@ $.Viewer = function( options ) { _this.viewport.applyConstraints(); return false; case 97://a - case 37://left arrow _this.viewport.panBy(new $.Point(-0.05, 0)); _this.viewport.applyConstraints(); return false; case 100://d - case 39://right arrow _this.viewport.panBy(new $.Point(0.05, 0)); _this.viewport.applyConstraints(); return false; @@ -374,6 +406,8 @@ $.Viewer = function( options ) { //console.log( 'navigator keycode %s', event.keyCode ); return true; } + } else { + return true; } } }).setTracking( true ); // default state From abacc50820f1142bda40246d7e9cf0ba0f3216a3 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Fri, 16 Jan 2015 16:31:23 -0800 Subject: [PATCH 34/52] changelog update --- changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.txt b/changelog.txt index ad7ff86f..2f0b38a6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -15,6 +15,9 @@ OPENSEADRAGON CHANGELOG * Removed Viewer onContainerPress/onContainerRelease handlers (and the associated 'container-release' event ) that were never fired due to the canvas (child) element capturing the DOM events (#566) * Added 'canvas-enter', 'canvas-exit', and 'canvas-press' events to Viewer (#566) * ButtonGroup - removed obsolete MouseTracker event handlers (#566) +* MouseTracker - added keydown and keyup handlers (#568) +* Modifier keys ignored in keyboard navigation handlers (#503) +* Arrow key navigation fixed across platforms (#565) 1.2.0: From 412ebce94d8b8eca0f3ddeb2d9a128f7b9d5de87 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Sat, 17 Jan 2015 11:18:55 -0800 Subject: [PATCH 35/52] Keyboard navigation fixes Removed textarea element from Viewer DOM. Viewer.canvas now handles keyboard navigation. --- changelog.txt | 1 + src/viewer.js | 226 ++++++++++++++++++++++---------------------------- 2 files changed, 100 insertions(+), 127 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2f0b38a6..ef16389a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -18,6 +18,7 @@ OPENSEADRAGON CHANGELOG * MouseTracker - added keydown and keyup handlers (#568) * Modifier keys ignored in keyboard navigation handlers (#503) * Arrow key navigation fixed across platforms (#565) +* Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation 1.2.0: diff --git a/src/viewer.js b/src/viewer.js index 7e20ec85..0e2fa818 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -108,14 +108,6 @@ $.Viewer = function( options ) { * @memberof OpenSeadragon.Viewer# */ container: null, - /** - * A <textarea> element, the element where keyboard events are handled.

- * Child element of {@link OpenSeadragon.Viewer#container}, - * positioned below {@link OpenSeadragon.Viewer#canvas}. - * @member {Element} keyboardCommandArea - * @memberof OpenSeadragon.Viewer# - */ - keyboardCommandArea: null, /** * A <div> element, the element where user-input events are handled for panning and zooming.

* Child element of {@link OpenSeadragon.Viewer#container}, @@ -263,7 +255,6 @@ $.Viewer = function( options ) { this.element = this.element || document.getElementById( this.id ); this.canvas = $.makeNeutralElement( "div" ); - this.keyboardCommandArea = $.makeNeutralElement( "textarea" ); this.drawersContainer = $.makeNeutralElement( "div" ); this.overlaysContainer = $.makeNeutralElement( "div" ); @@ -277,6 +268,7 @@ $.Viewer = function( options ) { style.left = "0px"; }(this.canvas.style)); $.setElementTouchActionNone( this.canvas ); + this.canvas.tabIndex = 0; //the container is created through applying the ControlDock constructor above this.container.className = "openseadragon-container"; @@ -290,21 +282,7 @@ $.Viewer = function( options ) { style.textAlign = "left"; // needed to protect against }( this.container.style )); - this.keyboardCommandArea.className = "keyboard-command-area"; - (function( style ){ - style.width = "100%"; - style.height = "100%"; - style.overflow = "hidden"; - style.position = "absolute"; - style.top = "0px"; - style.left = "0px"; - style.resize = "none"; - }( this.keyboardCommandArea.style )); - // Set read-only - hides keyboard on mobile devices, still allows input. - this.keyboardCommandArea.readOnly = true; - this.container.insertBefore( this.canvas, this.container.firstChild ); - this.container.insertBefore( this.keyboardCommandArea, this.container.firstChild ); this.element.appendChild( this.container ); this.canvas.appendChild( this.drawersContainer ); this.canvas.appendChild( this.overlaysContainer ); @@ -317,110 +295,15 @@ $.Viewer = function( options ) { this.bodyOverflow = document.body.style.overflow; this.docOverflow = document.documentElement.style.overflow; - this.keyboardCommandArea.innerTracker = new $.MouseTracker({ - _this : this, - element: this.keyboardCommandArea, - focusHandler: function( event ){ - if ( !event.preventDefaultAction ) { - var point = $.getElementPosition( this.element ); - window.scrollTo( 0, point.y ); - } - }, - - keyDownHandler: function( event ){ - if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { - switch( event.keyCode ){ - case 38://up arrow - if ( event.shift ) { - _this.viewport.zoomBy(1.1); - } else { - _this.viewport.panBy(new $.Point(0, -0.05)); - } - _this.viewport.applyConstraints(); - return false; - case 40://down arrow - if ( event.shift ) { - _this.viewport.zoomBy(0.9); - } else { - _this.viewport.panBy(new $.Point(0, 0.05)); - } - _this.viewport.applyConstraints(); - return false; - case 37://left arrow - _this.viewport.panBy(new $.Point(-0.05, 0)); - _this.viewport.applyConstraints(); - return false; - case 39://right arrow - _this.viewport.panBy(new $.Point(0.05, 0)); - _this.viewport.applyConstraints(); - return false; - default: - //console.log( 'navigator keycode %s', event.keyCode ); - return true; - } - } else { - return true; - } - }, - - keyHandler: function( event ){ - if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { - switch( event.keyCode ){ - case 61://=|+ - _this.viewport.zoomBy(1.1); - _this.viewport.applyConstraints(); - return false; - case 45://-|_ - _this.viewport.zoomBy(0.9); - _this.viewport.applyConstraints(); - return false; - case 48://0|) - _this.viewport.goHome(); - _this.viewport.applyConstraints(); - return false; - case 119://w - case 87://W - if ( event.shift ) { - _this.viewport.zoomBy(1.1); - } else { - _this.viewport.panBy(new $.Point(0, -0.05)); - } - _this.viewport.applyConstraints(); - return false; - case 115://s - case 83://S - if ( event.shift ) { - _this.viewport.zoomBy(0.9); - } else { - _this.viewport.panBy(new $.Point(0, 0.05)); - } - _this.viewport.applyConstraints(); - return false; - case 97://a - _this.viewport.panBy(new $.Point(-0.05, 0)); - _this.viewport.applyConstraints(); - return false; - case 100://d - _this.viewport.panBy(new $.Point(0.05, 0)); - _this.viewport.applyConstraints(); - return false; - default: - //console.log( 'navigator keycode %s', event.keyCode ); - return true; - } - } else { - return true; - } - } - }).setTracking( true ); // default state - - this.innerTracker = new $.MouseTracker({ element: this.canvas, clickTimeThreshold: this.clickTimeThreshold, clickDistThreshold: this.clickDistThreshold, dblClickTimeThreshold: this.dblClickTimeThreshold, dblClickDistThreshold: this.dblClickDistThreshold, + focusHandler: $.delegate( this, onCanvasFocus ), + keyDownHandler: $.delegate( this, onCanvasKeyDown ), + keyHandler: $.delegate( this, onCanvasKeyPress ), clickHandler: $.delegate( this, onCanvasClick ), dblClickHandler: $.delegate( this, onCanvasDblClick ), dragHandler: $.delegate( this, onCanvasDrag ), @@ -648,9 +531,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, } // destroy the mouse trackers - if (this.keyboardCommandArea){ - this.keyboardCommandArea.innerTracker.destroy(); - } if (this.innerTracker){ this.innerTracker.destroy(); } @@ -663,7 +543,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, // clear all our references to dom objects this.canvas = null; - this.keyboardCommandArea = null; this.container = null; // clear our reference to the main element - they will need to pass it in again, creating a new viewer @@ -2309,14 +2188,107 @@ function onBlur(){ } +function onCanvasFocus( event ) { + if ( !event.preventDefaultAction ) { + var point = $.getElementPosition( this.element ); + window.scrollTo( 0, point.y ); + } +} + +function onCanvasKeyDown( event ) { + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch( event.keyCode ){ + case 38://up arrow + if ( event.shift ) { + _this.viewport.zoomBy(1.1); + } else { + _this.viewport.panBy(new $.Point(0, -0.05)); + } + _this.viewport.applyConstraints(); + return false; + case 40://down arrow + if ( event.shift ) { + _this.viewport.zoomBy(0.9); + } else { + _this.viewport.panBy(new $.Point(0, 0.05)); + } + _this.viewport.applyConstraints(); + return false; + case 37://left arrow + _this.viewport.panBy(new $.Point(-0.05, 0)); + _this.viewport.applyConstraints(); + return false; + case 39://right arrow + _this.viewport.panBy(new $.Point(0.05, 0)); + _this.viewport.applyConstraints(); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + +function onCanvasKeyPress( event ) { + if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { + switch( event.keyCode ){ + case 61://=|+ + _this.viewport.zoomBy(1.1); + _this.viewport.applyConstraints(); + return false; + case 45://-|_ + _this.viewport.zoomBy(0.9); + _this.viewport.applyConstraints(); + return false; + case 48://0|) + _this.viewport.goHome(); + _this.viewport.applyConstraints(); + return false; + case 119://w + case 87://W + if ( event.shift ) { + _this.viewport.zoomBy(1.1); + } else { + _this.viewport.panBy(new $.Point(0, -0.05)); + } + _this.viewport.applyConstraints(); + return false; + case 115://s + case 83://S + if ( event.shift ) { + _this.viewport.zoomBy(0.9); + } else { + _this.viewport.panBy(new $.Point(0, 0.05)); + } + _this.viewport.applyConstraints(); + return false; + case 97://a + _this.viewport.panBy(new $.Point(-0.05, 0)); + _this.viewport.applyConstraints(); + return false; + case 100://d + _this.viewport.panBy(new $.Point(0.05, 0)); + _this.viewport.applyConstraints(); + return false; + default: + //console.log( 'navigator keycode %s', event.keyCode ); + return true; + } + } else { + return true; + } +} + function onCanvasClick( event ) { var gestureSettings; - var haveKeyboardFocus = document.activeElement == this.keyboardCommandArea; + var haveKeyboardFocus = document.activeElement == this.canvas; // If we don't have keyboard focus, request it. if ( !haveKeyboardFocus ) { - this.keyboardCommandArea.focus(); + this.canvas.focus(); } if ( !event.preventDefaultAction && this.viewport && event.quick ) { From b5b4131f49fee7b06933219b7f88aaa9283b0bc2 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Sat, 17 Jan 2015 11:21:16 -0800 Subject: [PATCH 36/52] changelog update --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index ef16389a..28631801 100644 --- a/changelog.txt +++ b/changelog.txt @@ -18,7 +18,7 @@ OPENSEADRAGON CHANGELOG * MouseTracker - added keydown and keyup handlers (#568) * Modifier keys ignored in keyboard navigation handlers (#503) * Arrow key navigation fixed across platforms (#565) -* Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation +* Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation (#569) 1.2.0: From 0f5c205656c1f68db0d8f42f63c2a4e64afc2c05 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Sat, 17 Jan 2015 11:25:24 -0800 Subject: [PATCH 37/52] Cut/pasted code fix --- src/viewer.js | 52 +++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/viewer.js b/src/viewer.js index 0e2fa818..04587719 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2200,27 +2200,27 @@ function onCanvasKeyDown( event ) { switch( event.keyCode ){ case 38://up arrow if ( event.shift ) { - _this.viewport.zoomBy(1.1); + this.viewport.zoomBy(1.1); } else { - _this.viewport.panBy(new $.Point(0, -0.05)); + this.viewport.panBy(new $.Point(0, -0.05)); } - _this.viewport.applyConstraints(); + this.viewport.applyConstraints(); return false; case 40://down arrow if ( event.shift ) { - _this.viewport.zoomBy(0.9); + this.viewport.zoomBy(0.9); } else { - _this.viewport.panBy(new $.Point(0, 0.05)); + this.viewport.panBy(new $.Point(0, 0.05)); } - _this.viewport.applyConstraints(); + this.viewport.applyConstraints(); return false; case 37://left arrow - _this.viewport.panBy(new $.Point(-0.05, 0)); - _this.viewport.applyConstraints(); + this.viewport.panBy(new $.Point(-0.05, 0)); + this.viewport.applyConstraints(); return false; case 39://right arrow - _this.viewport.panBy(new $.Point(0.05, 0)); - _this.viewport.applyConstraints(); + this.viewport.panBy(new $.Point(0.05, 0)); + this.viewport.applyConstraints(); return false; default: //console.log( 'navigator keycode %s', event.keyCode ); @@ -2235,42 +2235,42 @@ function onCanvasKeyPress( event ) { if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { switch( event.keyCode ){ case 61://=|+ - _this.viewport.zoomBy(1.1); - _this.viewport.applyConstraints(); + this.viewport.zoomBy(1.1); + this.viewport.applyConstraints(); return false; case 45://-|_ - _this.viewport.zoomBy(0.9); - _this.viewport.applyConstraints(); + this.viewport.zoomBy(0.9); + this.viewport.applyConstraints(); return false; case 48://0|) - _this.viewport.goHome(); - _this.viewport.applyConstraints(); + this.viewport.goHome(); + this.viewport.applyConstraints(); return false; case 119://w case 87://W if ( event.shift ) { - _this.viewport.zoomBy(1.1); + this.viewport.zoomBy(1.1); } else { - _this.viewport.panBy(new $.Point(0, -0.05)); + this.viewport.panBy(new $.Point(0, -0.05)); } - _this.viewport.applyConstraints(); + this.viewport.applyConstraints(); return false; case 115://s case 83://S if ( event.shift ) { - _this.viewport.zoomBy(0.9); + this.viewport.zoomBy(0.9); } else { - _this.viewport.panBy(new $.Point(0, 0.05)); + this.viewport.panBy(new $.Point(0, 0.05)); } - _this.viewport.applyConstraints(); + this.viewport.applyConstraints(); return false; case 97://a - _this.viewport.panBy(new $.Point(-0.05, 0)); - _this.viewport.applyConstraints(); + this.viewport.panBy(new $.Point(-0.05, 0)); + this.viewport.applyConstraints(); return false; case 100://d - _this.viewport.panBy(new $.Point(0.05, 0)); - _this.viewport.applyConstraints(); + this.viewport.panBy(new $.Point(0.05, 0)); + this.viewport.applyConstraints(); return false; default: //console.log( 'navigator keycode %s', event.keyCode ); From 2bd105042af80586500e3b39c8b9d786c443e108 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 19 Jan 2015 10:31:30 -0800 Subject: [PATCH 38/52] Changelog for #537 --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 28631801..e3bd3156 100644 --- a/changelog.txt +++ b/changelog.txt @@ -17,6 +17,7 @@ OPENSEADRAGON CHANGELOG * ButtonGroup - removed obsolete MouseTracker event handlers (#566) * MouseTracker - added keydown and keyup handlers (#568) * Modifier keys ignored in keyboard navigation handlers (#503) +* Requesting keyboard focus when viewer is clicked (#537) * Arrow key navigation fixed across platforms (#565) * Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation (#569) From e87020cf7868689b3a55584b60cc6b275d1531d3 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 20 Jan 2015 09:48:28 -0800 Subject: [PATCH 39/52] Removed 'position' property from MouseTracker keyDownHandler/keyUpHandler/keyHandler functions Positional data is not available in the corresponding DOM event objects --- src/mousetracker.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 9e8f25ef..86e87076 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -1518,7 +1518,6 @@ propagate = tracker.keyDownHandler( { eventSource: tracker, - position: getMouseRelative( event, tracker.element ), keyCode: event.keyCode ? event.keyCode : event.charCode, ctrl: event.ctrlKey, shift: event.shiftKey, @@ -1548,7 +1547,6 @@ propagate = tracker.keyUpHandler( { eventSource: tracker, - position: getMouseRelative( event, tracker.element ), keyCode: event.keyCode ? event.keyCode : event.charCode, ctrl: event.ctrlKey, shift: event.shiftKey, @@ -1578,7 +1576,6 @@ propagate = tracker.keyHandler( { eventSource: tracker, - position: getMouseRelative( event, tracker.element ), keyCode: event.keyCode ? event.keyCode : event.charCode, ctrl: event.ctrlKey, shift: event.shiftKey, From 7c39794bd9fce4e6ee5a7fabcc3712e912e0d8a8 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 20 Jan 2015 09:52:18 -0800 Subject: [PATCH 40/52] changelog update --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index e3bd3156..e6c0369e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -20,6 +20,7 @@ OPENSEADRAGON CHANGELOG * Requesting keyboard focus when viewer is clicked (#537) * Arrow key navigation fixed across platforms (#565) * Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation (#569) +* Removed 'position' property from MouseTracker keyDownHandler/keyUpHandler/keyHandler functions (#573) 1.2.0: From 3b01014ac8893d3726acb75fd79c70225e5d4690 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 20 Jan 2015 10:26:14 -0800 Subject: [PATCH 41/52] Fixed pointer event model detection for IE 10 (#571) --- changelog.txt | 1 + src/mousetracker.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index e3bd3156..4d0ebbae 100644 --- a/changelog.txt +++ b/changelog.txt @@ -20,6 +20,7 @@ OPENSEADRAGON CHANGELOG * Requesting keyboard focus when viewer is clicked (#537) * Arrow key navigation fixed across platforms (#565) * Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation (#569) +* Fixed pointer event model detection for IE 10 (#571) 1.2.0: diff --git a/src/mousetracker.js b/src/mousetracker.js index 9e8f25ef..8693067e 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -988,7 +988,7 @@ $.MouseTracker.maxTouchPoints = 0; } $.MouseTracker.haveMouseEnter = false; - } else if ( window.MSPointerEvent ) { + } else if ( window.MSPointerEvent && window.navigator.msPointerEnabled ) { // IE10 $.MouseTracker.havePointerEvents = true; $.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); From 198d4de0e6f5ca926d15eac363bc2aedc639877b Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 20 Jan 2015 11:01:09 -0800 Subject: [PATCH 42/52] Added setMouseNavEnabled() and isMouseNavEnabled() method overrides to Navigator (#572) --- changelog.txt | 1 + src/navigator.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/changelog.txt b/changelog.txt index e3bd3156..db650743 100644 --- a/changelog.txt +++ b/changelog.txt @@ -20,6 +20,7 @@ OPENSEADRAGON CHANGELOG * Requesting keyboard focus when viewer is clicked (#537) * Arrow key navigation fixed across platforms (#565) * Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation (#569) +* Added setMouseNavEnabled() and isMouseNavEnabled() method overrides to Navigator (#572) 1.2.0: diff --git a/src/navigator.js b/src/navigator.js index 9e18d6ca..3638efde 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -229,6 +229,36 @@ $.Navigator = function( options ){ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{ + /** + * @function + * @return {Boolean} + */ + isMouseNavEnabled: function () { + return this.element.innerTracker.isTracking(); + }, + + /** + * @function + * @param {Boolean} enabled - true to enable, false to disable + * @return {OpenSeadragon.Navigator} Chainable. + * @fires OpenSeadragon.Navigator.event:mouse-enabled + */ + setMouseNavEnabled: function( enabled ){ + this.element.innerTracker.setTracking( enabled ); + /** + * Raised when mouse/touch navigation is enabled or disabled (see {@link OpenSeadragon.Navigator#setMouseNavEnabled}). + * + * @event mouse-enabled + * @memberof OpenSeadragon.Navigator + * @type {object} + * @property {OpenSeadragon.Navigator} eventSource - A reference to the Navigator which raised the event. + * @property {Boolean} enabled + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent( 'mouse-enabled', { enabled: enabled } ); + return this; + }, + /** * Used to notify the navigator when its size has changed. * Especially useful when {@link OpenSeadragon.Options}.navigatorAutoResize is set to false and the navigator is resizable. From 674a208d95b50e1f5db610c3cea0d713140caa85 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 20 Jan 2015 13:56:06 -0800 Subject: [PATCH 43/52] Replace base class innerTracker instead of using a new one --- src/navigator.js | 75 +++++++++++++----------------------------------- 1 file changed, 20 insertions(+), 55 deletions(-) diff --git a/src/navigator.js b/src/navigator.js index 3638efde..9991dbac 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -52,8 +52,7 @@ $.Navigator = function( options ){ var viewer = options.viewer, _this = this, viewerSize, - navigatorSize, - unneededElement; + navigatorSize; //We may need to create a new element and id if they did not //provide the id for the existing element @@ -168,24 +167,6 @@ $.Navigator = function( options ){ this.displayRegionContainer.style.width = "100%"; this.displayRegionContainer.style.height = "100%"; - this.element.innerTracker = new $.MouseTracker({ - element: this.element, - dragHandler: $.delegate( this, onCanvasDrag ), - clickHandler: $.delegate( this, onCanvasClick ), - releaseHandler: $.delegate( this, onCanvasRelease ), - scrollHandler: $.delegate( this, onCanvasScroll ) - }).setTracking( true ); - - /*this.displayRegion.outerTracker = new $.MouseTracker({ - element: this.container, - clickTimeThreshold: this.clickTimeThreshold, - clickDistThreshold: this.clickDistThreshold, - enterHandler: $.delegate( this, onContainerEnter ), - exitHandler: $.delegate( this, onContainerExit ), - releaseHandler: $.delegate( this, onContainerRelease ) - }).setTracking( this.mouseNavEnabled ? true : false ); // always tracking*/ - - viewer.addControl( this.element, options.controlOptions @@ -211,10 +192,6 @@ $.Navigator = function( options ){ this.displayRegionContainer.appendChild(this.displayRegion); this.element.getElementsByTagName('div')[0].appendChild(this.displayRegionContainer); - unneededElement = this.element.getElementsByTagName('textarea')[0]; - if (unneededElement) { - unneededElement.parentNode.removeChild(unneededElement); - } if (options.navigatorRotate) { @@ -223,42 +200,30 @@ $.Navigator = function( options ){ _setTransformRotate(_this.displayRegion, -args.degrees); _this.viewport.setRotation(args.degrees); }); - } + + // Remove the base class' (Viewer's) innerTracker and replace it with our own + this.innerTracker.destroy(); + this.innerTracker = new $.MouseTracker({ + element: this.element, + dragHandler: $.delegate( this, onCanvasDrag ), + clickHandler: $.delegate( this, onCanvasClick ), + releaseHandler: $.delegate( this, onCanvasRelease ), + scrollHandler: $.delegate( this, onCanvasScroll ) + }).setTracking( true ); + + /*this.displayRegion.outerTracker = new $.MouseTracker({ + element: this.container, + clickTimeThreshold: this.clickTimeThreshold, + clickDistThreshold: this.clickDistThreshold, + enterHandler: $.delegate( this, onContainerEnter ), + exitHandler: $.delegate( this, onContainerExit ), + releaseHandler: $.delegate( this, onContainerRelease ) + }).setTracking( this.mouseNavEnabled ? true : false ); // always tracking*/ }; $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{ - /** - * @function - * @return {Boolean} - */ - isMouseNavEnabled: function () { - return this.element.innerTracker.isTracking(); - }, - - /** - * @function - * @param {Boolean} enabled - true to enable, false to disable - * @return {OpenSeadragon.Navigator} Chainable. - * @fires OpenSeadragon.Navigator.event:mouse-enabled - */ - setMouseNavEnabled: function( enabled ){ - this.element.innerTracker.setTracking( enabled ); - /** - * Raised when mouse/touch navigation is enabled or disabled (see {@link OpenSeadragon.Navigator#setMouseNavEnabled}). - * - * @event mouse-enabled - * @memberof OpenSeadragon.Navigator - * @type {object} - * @property {OpenSeadragon.Navigator} eventSource - A reference to the Navigator which raised the event. - * @property {Boolean} enabled - * @property {?Object} userData - Arbitrary subscriber-defined object. - */ - this.raiseEvent( 'mouse-enabled', { enabled: enabled } ); - return this; - }, - /** * Used to notify the navigator when its size has changed. * Especially useful when {@link OpenSeadragon.Options}.navigatorAutoResize is set to false and the navigator is resizable. From 269f9ee71d52d149eee07f70215184bedb062833 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 20 Jan 2015 17:45:13 -0800 Subject: [PATCH 44/52] changelog update --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 42812042..4eb7f7e7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -21,7 +21,7 @@ OPENSEADRAGON CHANGELOG * Arrow key navigation fixed across platforms (#565) * Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation (#569) * Removed 'position' property from MouseTracker keyDownHandler/keyUpHandler/keyHandler functions (#573) -* Added setMouseNavEnabled() and isMouseNavEnabled() method overrides to Navigator (#572) +* Added setMouseNavEnabled() support to Navigator (#572) 1.2.0: From 545997bace25950a11942d9afc4e026cd9e631e1 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Tue, 20 Jan 2015 18:35:58 -0800 Subject: [PATCH 45/52] MouseTracker now defaults to tracking on (#558) --- changelog.txt | 1 + src/button.js | 2 +- src/buttongroup.js | 2 +- src/mousetracker.js | 6 ++++++ src/navigator.js | 5 +++-- src/referencestrip.js | 8 +++++--- src/viewer.js | 6 ++++-- test/events.js | 2 +- 8 files changed, 22 insertions(+), 10 deletions(-) diff --git a/changelog.txt b/changelog.txt index e6c0369e..6412a2b0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -21,6 +21,7 @@ OPENSEADRAGON CHANGELOG * Arrow key navigation fixed across platforms (#565) * Removed textarea element from viewer DOM. Viewer.canvas now handles keyboard navigation (#569) * Removed 'position' property from MouseTracker keyDownHandler/keyUpHandler/keyHandler functions (#573) +* MouseTracker now defaults to tracking on (#558) 1.2.0: diff --git a/src/button.js b/src/button.js index 104955e0..42f68afc 100644 --- a/src/button.js +++ b/src/button.js @@ -355,7 +355,7 @@ $.Button = function( options ) { return true; } - }).setTracking( true ); + }); outTo( this, $.ButtonState.REST ); }; diff --git a/src/buttongroup.js b/src/buttongroup.js index 7505af0a..49cc9c2e 100644 --- a/src/buttongroup.js +++ b/src/buttongroup.js @@ -105,7 +105,7 @@ $.ButtonGroup = function( options ) { } } }, - }).setTracking( true ); + }); }; $.ButtonGroup.prototype = /** @lends OpenSeadragon.ButtonGroup.prototype */{ diff --git a/src/mousetracker.js b/src/mousetracker.js index 86e87076..20f58541 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -54,6 +54,9 @@ * @param {Element|String} options.element * A reference to an element or an element id for which the pointer/key * events will be monitored. + * @param {Boolean} [options.startDisabled=false] + * If true, event tracking on the element will not start until + * {@link OpenSeadragon.MouseTracker.setTracking|setTracking} is called. * @param {Number} options.clickTimeThreshold * The number of milliseconds within which a pointer down-up event combination * will be treated as a click gesture. @@ -257,6 +260,9 @@ currentPinchCenter: null }; + if ( !options.startDisabled ) { + this.setTracking( true ); + } }; $.MouseTracker.prototype = /** @lends OpenSeadragon.MouseTracker.prototype */{ diff --git a/src/navigator.js b/src/navigator.js index 9e18d6ca..7c25b742 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -174,16 +174,17 @@ $.Navigator = function( options ){ clickHandler: $.delegate( this, onCanvasClick ), releaseHandler: $.delegate( this, onCanvasRelease ), scrollHandler: $.delegate( this, onCanvasScroll ) - }).setTracking( true ); + }); /*this.displayRegion.outerTracker = new $.MouseTracker({ element: this.container, + startDisabled: this.mouseNavEnabled ? false : true, clickTimeThreshold: this.clickTimeThreshold, clickDistThreshold: this.clickDistThreshold, enterHandler: $.delegate( this, onContainerEnter ), exitHandler: $.delegate( this, onContainerExit ), releaseHandler: $.delegate( this, onContainerRelease ) - }).setTracking( this.mouseNavEnabled ? true : false ); // always tracking*/ + });*/ viewer.addControl( diff --git a/src/referencestrip.js b/src/referencestrip.js index a872ca58..480009ec 100644 --- a/src/referencestrip.js +++ b/src/referencestrip.js @@ -127,7 +127,7 @@ $.ReferenceStrip = function ( options ) { exitHandler: $.delegate( this, onStripExit ), keyDownHandler: $.delegate( this, onKeyDown ), keyHandler: $.delegate( this, onKeyPress ) - } ).setTracking( true ); + } ); //Controls the position and orientation of the reference strip and sets the //appropriate width and height @@ -215,7 +215,7 @@ $.ReferenceStrip = function ( options ) { viewer.goToPage( page ); } } - } ).setTracking( true ); + } ); this.element.appendChild( element ); @@ -447,8 +447,10 @@ function loadPanels( strip, viewerSize, scroll ) { style.width = ( strip.panelWidth - 4 ) + 'px'; style.height = ( strip.panelHeight - 4 ) + 'px'; + // TODO: What is this for? Future keyboard navigation support? miniViewer.displayRegion.innerTracker = new $.MouseTracker( { - element: miniViewer.displayRegion + element: miniViewer.displayRegion, + startDisabled: true } ); element.getElementsByTagName( 'div' )[0].appendChild( diff --git a/src/viewer.js b/src/viewer.js index 04587719..865a92a5 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -297,6 +297,7 @@ $.Viewer = function( options ) { this.innerTracker = new $.MouseTracker({ element: this.canvas, + startDisabled: this.mouseNavEnabled ? false : true, clickTimeThreshold: this.clickTimeThreshold, clickDistThreshold: this.clickDistThreshold, dblClickTimeThreshold: this.dblClickTimeThreshold, @@ -316,17 +317,18 @@ $.Viewer = function( options ) { nonPrimaryReleaseHandler: $.delegate( this, onCanvasNonPrimaryRelease ), scrollHandler: $.delegate( this, onCanvasScroll ), pinchHandler: $.delegate( this, onCanvasPinch ) - }).setTracking( this.mouseNavEnabled ? true : false ); // default state + }); this.outerTracker = new $.MouseTracker({ element: this.container, + startDisabled: this.mouseNavEnabled ? false : true, clickTimeThreshold: this.clickTimeThreshold, clickDistThreshold: this.clickDistThreshold, dblClickTimeThreshold: this.dblClickTimeThreshold, dblClickDistThreshold: this.dblClickDistThreshold, enterHandler: $.delegate( this, onContainerEnter ), exitHandler: $.delegate( this, onContainerExit ) - }).setTracking( this.mouseNavEnabled ? true : false ); // always tracking + }); if( this.toolbar ){ this.toolbar = new $.ControlDock({ element: this.toolbar }); diff --git a/test/events.js b/test/events.js index 5f850082..677e805f 100644 --- a/test/events.js +++ b/test/events.js @@ -790,7 +790,7 @@ releaseHandler: onMouseTrackerRelease, clickHandler: onMouseTrackerClick, exitHandler: onMouseTrackerExit - } ).setTracking( true ); + } ); var event = { clientX:1, From 406005c8c9eda35d4ab38f6e4de374d4a9eaae86 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 21 Jan 2015 09:42:03 -0800 Subject: [PATCH 46/52] Removed dead code --- src/navigator.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/navigator.js b/src/navigator.js index 9991dbac..fb0756e8 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -212,14 +212,6 @@ $.Navigator = function( options ){ scrollHandler: $.delegate( this, onCanvasScroll ) }).setTracking( true ); - /*this.displayRegion.outerTracker = new $.MouseTracker({ - element: this.container, - clickTimeThreshold: this.clickTimeThreshold, - clickDistThreshold: this.clickDistThreshold, - enterHandler: $.delegate( this, onContainerEnter ), - exitHandler: $.delegate( this, onContainerExit ), - releaseHandler: $.delegate( this, onContainerRelease ) - }).setTracking( this.mouseNavEnabled ? true : false ); // always tracking*/ }; $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{ From 1e8b3a1ea6ebd5c49213610a511319f361736e71 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 21 Jan 2015 11:49:19 -0800 Subject: [PATCH 47/52] Removed Viewer focusHandler/onCanvasFocus Presumably, this was meant to manually scroll the viewer into view when it receives focus. This is already handled by browsers when tabbing to the viewer, so doing it explicitly isn't necessary, and it creates a negative user experience when clicking on a viewer to give it focus (as of #569). --- src/viewer.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/viewer.js b/src/viewer.js index 04587719..4ba9ab48 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -301,7 +301,6 @@ $.Viewer = function( options ) { clickDistThreshold: this.clickDistThreshold, dblClickTimeThreshold: this.dblClickTimeThreshold, dblClickDistThreshold: this.dblClickDistThreshold, - focusHandler: $.delegate( this, onCanvasFocus ), keyDownHandler: $.delegate( this, onCanvasKeyDown ), keyHandler: $.delegate( this, onCanvasKeyPress ), clickHandler: $.delegate( this, onCanvasClick ), @@ -2188,13 +2187,6 @@ function onBlur(){ } -function onCanvasFocus( event ) { - if ( !event.preventDefaultAction ) { - var point = $.getElementPosition( this.element ); - window.scrollTo( 0, point.y ); - } -} - function onCanvasKeyDown( event ) { if ( !event.preventDefaultAction && !event.ctrl && !event.alt && !event.meta ) { switch( event.keyCode ){ From b639f1e168a1629f8bcfcc0a9ece2d728861c285 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 21 Jan 2015 11:51:56 -0800 Subject: [PATCH 48/52] changelog update --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 1cd6f9df..7a747759 100644 --- a/changelog.txt +++ b/changelog.txt @@ -23,6 +23,7 @@ OPENSEADRAGON CHANGELOG * Removed 'position' property from MouseTracker keyDownHandler/keyUpHandler/keyHandler functions (#573) * Fixed pointer event model detection for IE 10 and IE 11 (#571) * Added setMouseNavEnabled() support to Navigator (#572) +* Removed Viewer focusHandler/onCanvasFocus (#577) 1.2.0: From 43d892451339f65a74b12d98301d0132f6579de0 Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 21 Jan 2015 12:47:42 -0800 Subject: [PATCH 49/52] Added tabIndex option to viewer --- src/navigator.js | 1 + src/openseadragon.js | 4 ++++ src/viewer.js | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/navigator.js b/src/navigator.js index fb0756e8..dcea7687 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -98,6 +98,7 @@ $.Navigator = function( options ){ sizeRatio: $.DEFAULT_SETTINGS.navigatorSizeRatio }, options, { element: this.element, + tabIndex: -1, // No keyboard navigation, omit from tab order //These need to be overridden to prevent recursion since //the navigator is a viewer and a viewer has a navigator showNavigator: false, diff --git a/src/openseadragon.js b/src/openseadragon.js index 27d3262c..f56f10da 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -126,6 +126,10 @@ * The element to append the viewer's container element to. If not provided, the 'id' property must be provided. * If both the element and id properties are specified, the viewer is appended to the element provided in the element property. * + * @property {Number} [tabIndex=0] + * Tabbing order index to assign to the viewer element. Positive values are selected in increasing order. When tabIndex is 0 + * source order is used. A negative value omits the viewer from the tabbing order. + * * @property {Array|String|Function|Object[]|Array[]|String[]|Function[]} [tileSources=null] * As an Array, the tileSource can hold either Objects or mixed * types of Arrays of Objects, Strings, or Functions. When a value is a String, diff --git a/src/viewer.js b/src/viewer.js index 4ba9ab48..4cf7fad7 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -268,7 +268,7 @@ $.Viewer = function( options ) { style.left = "0px"; }(this.canvas.style)); $.setElementTouchActionNone( this.canvas ); - this.canvas.tabIndex = 0; + this.canvas.tabIndex = options.tabIndex || 0; //the container is created through applying the ControlDock constructor above this.container.className = "openseadragon-container"; From a09b6837d3d9e1032bc6b3a8d4fd2e73c48788ee Mon Sep 17 00:00:00 2001 From: Mark Salsbery Date: Wed, 21 Jan 2015 12:49:45 -0800 Subject: [PATCH 50/52] changelog update --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 7a747759..6ab20b94 100644 --- a/changelog.txt +++ b/changelog.txt @@ -24,6 +24,7 @@ OPENSEADRAGON CHANGELOG * Fixed pointer event model detection for IE 10 and IE 11 (#571) * Added setMouseNavEnabled() support to Navigator (#572) * Removed Viewer focusHandler/onCanvasFocus (#577) +* Added tabIndex option to viewer (#577) 1.2.0: From 2f9563d58cf3cba70e83193f7a2fd300f8216dc0 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Thu, 29 Jan 2015 13:10:59 -0800 Subject: [PATCH 51/52] Version bump --- changelog.txt | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 16e4088b..bbe09fbc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,7 @@ OPENSEADRAGON CHANGELOG ======================= -1.2.1: (in progress) +1.2.1: * Added preserveOverlays option (#561) * Fixed: DZI tilesource was broken on IE8/IE9 (#563) diff --git a/package.json b/package.json index 6aa039fe..992fd364 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "OpenSeadragon", - "version": "1.2.0", + "version": "1.2.1", "description": "Provides a smooth, zoomable user interface for HTML/Javascript.", "devDependencies": { "grunt": "^0.4.5", From 0b5b776db6f5c69dbd40c362c753a74e58d70b8f Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Thu, 29 Jan 2015 13:20:56 -0800 Subject: [PATCH 52/52] Starting next version --- changelog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.txt b/changelog.txt index bbe09fbc..a68ba727 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,8 @@ OPENSEADRAGON CHANGELOG ======================= +1.2.2: (in progress) + 1.2.1: * Added preserveOverlays option (#561)