diff --git a/changelog.txt b/changelog.txt
index e77bb84d..a68ba727 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,7 +1,35 @@
OPENSEADRAGON CHANGELOG
=======================
-1.2.0: (in progress)
+1.2.2: (in progress)
+
+1.2.1:
+
+* Added preserveOverlays option (#561)
+* 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)
+* 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)
+* 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)
+* 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)
+* MouseTracker now defaults to tracking on (#558)
+* Removed Viewer focusHandler/onCanvasFocus (#577)
+* Added tabIndex option to viewer (#577)
+
+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)
@@ -18,8 +46,9 @@ 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)
+* Added explicit pointer capture for touch event model touchstart events (#552)
1.1.1:
diff --git a/package.json b/package.json
index 486d8743..992fd364 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "OpenSeadragon",
- "version": "1.1.1",
+ "version": "1.2.1",
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
"devDependencies": {
"grunt": "^0.4.5",
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 2837805a..49cc9c2e 100644
--- a/src/buttongroup.js
+++ b/src/buttongroup.js
@@ -105,23 +105,7 @@ $.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 );
+ });
};
$.ButtonGroup.prototype = /** @lends OpenSeadragon.ButtonGroup.prototype */{
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: {
diff --git a/src/mousetracker.js b/src/mousetracker.js
index 0c865c74..ec677fb7 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 = {};
@@ -51,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.
@@ -72,8 +78,12 @@
* An optional handler for pointer exit.
* @param {OpenSeadragon.EventHandler} [options.pressHandler=null]
* An optional handler for pointer press.
+ * @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.nonPrimaryReleaseHandler=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]
@@ -88,6 +98,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]
@@ -99,6 +113,8 @@
*/
$.MouseTracker = function ( options ) {
+ MOUSETRACKERS.push( this );
+
var args = arguments;
if ( !$.isPlainObject( options ) ) {
@@ -144,24 +160,28 @@
* @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.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.keyDownHandler = options.keyDownHandler || null;
+ this.keyUpHandler = options.keyUpHandler || 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;
@@ -170,12 +190,12 @@
* @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 ); },
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 ); },
@@ -185,6 +205,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 ); },
@@ -193,13 +215,11 @@
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 ); },
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 ); },
@@ -209,10 +229,6 @@
MSPointerOver: function ( event ) { onPointerOver( _this, event ); },
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 ); },
@@ -232,12 +248,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,
@@ -250,6 +260,9 @@
currentPinchCenter: null
};
+ if ( !options.startDisabled ) {
+ this.setTracking( true );
+ }
};
$.MouseTracker.prototype = /** @lends OpenSeadragon.MouseTracker.prototype */{
@@ -259,9 +272,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 ];
},
@@ -316,6 +338,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.
@@ -330,6 +370,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.
@@ -360,6 +402,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.
@@ -401,6 +445,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.
+ */
+ nonPrimaryPressHandler: function () { },
+
/**
* Implement or assign implementation to these handlers during or after
* calling the constructor.
@@ -431,6 +503,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.
+ */
+ nonPrimaryReleaseHandler: function () { },
+
/**
* Implement or assign implementation to these handlers during or after
* calling the constructor.
@@ -657,8 +757,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
@@ -797,6 +955,8 @@
// Pointer event model and feature detection
///////////////////////////////////////////////////////////////////////////////
+ $.MouseTracker.captureElement = document;
+
/**
* Detect available mouse wheel event name.
*/
@@ -816,15 +976,17 @@
/**
* 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
$.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" );
}
- if ( window.PointerEvent ) {
+ // Note: window.navigator.pointerEnable is deprecated on IE 11 and not part of W3C spec.
+ if ( window.PointerEvent && ( window.navigator.pointerEnabled || $.Browser.vendor !== $.BROWSERS.IE ) ) {
// 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 ) {
@@ -832,10 +994,10 @@
} else {
$.MouseTracker.maxTouchPoints = 0;
}
- $.MouseTracker.haveTouchEnter = false;
$.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" );
$.MouseTracker.unprefixedPointerEvents = false;
if( navigator.msMaxTouchPoints ) {
@@ -843,26 +1005,27 @@
} else {
$.MouseTracker.maxTouchPoints = 0;
}
- $.MouseTracker.haveTouchEnter = false;
$.MouseTracker.haveMouseEnter = false;
} else {
// Legacy W3C mouse events
- $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" );
- $.MouseTracker.haveMouseEnter = false;
- 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" );
- if ( 'ontouchenter' in window ) {
- $.MouseTracker.subscribeEvents.push( "touchenter", "touchleave" );
- $.MouseTracker.haveTouchEnter = true;
- } else {
- $.MouseTracker.haveTouchEnter = false;
- }
+ $.MouseTracker.havePointerEvents = false;
+ if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
+ $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" );
+ $.MouseTracker.haveMouseEnter = true;
} else {
- $.MouseTracker.haveTouchEnter = false;
+ $.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/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 ( '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" );
}
@@ -947,6 +1110,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 */{
/**
@@ -1035,6 +1204,64 @@
// Utility functions
///////////////////////////////////////////////////////////////////////////////
+ /**
+ * Removes all tracked pointers.
+ * @private
+ * @inner
+ */
+ function clearTrackedPointers( tracker ) {
+ var delegate = THIS[ tracker.hash ],
+ i,
+ pointerListCount = delegate.activePointersLists.length;
+
+ 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.activePointersLists[ i ].captureCount = 0;
+ }
+ }
+
+ for ( i = 0; i < pointerListCount; i++ ) {
+ delegate.activePointersLists.pop();
+ }
+ }
+
/**
* Starts tracking pointer events on the tracked element.
* @private
@@ -1056,14 +1283,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,45 +1310,76 @@
);
}
- // 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;
}
}
+ /**
+ * @private
+ * @inner
+ */
+ function getCaptureEventParams( tracker, pointerType ) {
+ var delegate = THIS[ tracker.hash ];
+
+ 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,
+ moveName: 'mousemove',
+ moveHandler: delegate.mousemovecaptured
+ };
+ } else if ( pointerType === 'touch' ) {
+ return {
+ upName: 'touchend',
+ upHandler: delegate.touchendcaptured,
+ moveName: 'touchmove',
+ moveHandler: delegate.touchmovecaptured
+ };
+ } else {
+ throw new Error( "MouseTracker.getCaptureEventParams: Unknown pointer type." );
+ }
+ }
+
/**
* Begin capturing pointer events to the tracked element.
* @private
* @inner
*/
- function capturePointer( tracker, isLegacyMouse ) {
- var delegate = THIS[ tracker.hash ];
+ function capturePointer( tracker, pointerType ) {
+ var pointsList = tracker.getActivePointersListByType( pointerType ),
+ eventParams;
- delegate.pointerCaptureCount++;
- //$.console.log('pointerCaptureCount++ ', delegate.pointerCaptureCount);
+ pointsList.captureCount++;
- 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,
- isLegacyMouse ? 'mouseup' : ($.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp'),
- isLegacyMouse ? delegate.mouseupcaptured : delegate.pointerupcaptured,
- true
- );
- $.addEvent(
- window,
- isLegacyMouse ? 'mousemove' : ($.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove'),
- isLegacyMouse ? delegate.mousemovecaptured : delegate.pointermovecaptured,
- true
- );
+ if ( pointsList.captureCount === 1 ) {
+ if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
+ tracker.element.setCapture( true );
+ } else {
+ 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(
+ $.MouseTracker.captureElement,
+ eventParams.upName,
+ eventParams.upHandler,
+ true
+ );
+ $.addEvent(
+ $.MouseTracker.captureElement,
+ eventParams.moveName,
+ eventParams.moveHandler,
+ true
+ );
+ }
}
}
@@ -1138,27 +1389,32 @@
* @private
* @inner
*/
- function releasePointer( tracker, isLegacyMouse ) {
- var delegate = THIS[ tracker.hash ];
+ function releasePointer( tracker, pointerType ) {
+ var pointsList = tracker.getActivePointersListByType( pointerType ),
+ eventParams;
- delegate.pointerCaptureCount--;
- //$.console.log('pointerCaptureCount-- ', delegate.pointerCaptureCount);
+ pointsList.captureCount--;
- 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,
- isLegacyMouse ? 'mousemove' : ($.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove'),
- isLegacyMouse ? delegate.mousemovecaptured : delegate.pointermovecaptured,
- true
- );
- $.removeEvent(
- window,
- isLegacyMouse ? 'mouseup' : ($.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp'),
- isLegacyMouse ? delegate.mouseupcaptured : delegate.pointerupcaptured,
- true
- );
+ if ( pointsList.captureCount === 0 ) {
+ if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
+ tracker.element.releaseCapture();
+ } else {
+ 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(
+ $.MouseTracker.captureElement,
+ eventParams.moveName,
+ eventParams.moveHandler,
+ true
+ );
+ $.removeEvent(
+ $.MouseTracker.captureElement,
+ eventParams.upName,
+ eventParams.upHandler,
+ true
+ );
+ }
}
}
@@ -1257,21 +1513,81 @@
}
+ /**
+ * @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,
+ 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,
+ 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 );
propagate = tracker.keyHandler(
{
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
@@ -1432,20 +1748,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 ) ) {
+ if ( event.currentTarget === 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,
@@ -1457,20 +1793,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 ) ) {
+ if ( event.currentTarget === 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,
@@ -1481,36 +1837,32 @@
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.
- *
+ * 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 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 );
+ 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
@@ -1528,9 +1880,9 @@
currentTime: $.now()
};
- if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) {
+ if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {
$.stopEvent( event );
- capturePointer( tracker, true );
+ capturePointer( tracker, 'mouse' );
}
if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) {
@@ -1577,11 +1929,12 @@
currentTime: $.now()
};
- if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) {
- releasePointer( tracker, true );
+ if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {
+ releasePointer( tracker, 'mouse' );
}
}
+
/**
* @private
* @inner
@@ -1629,45 +1982,24 @@
* @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
+ // release pointer capture
+ pointsList.captureCount = 1;
+ releasePointer( tracker, 'touch' );
+ // simulate touchleave
+ updatePointersExit( tracker, event, abortGPoints );
}
-
- updatePointersExit( tracker, event, gPoints );
}
@@ -1678,11 +2010,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,
@@ -1693,13 +2033,29 @@
} );
}
- // 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
- // 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 );
@@ -1711,10 +2067,34 @@
* @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,
+ j,
touchCount = event.changedTouches.length,
- gPoints = [];
+ gPoints = [],
+ parentGPoints;
time = $.now();
@@ -1728,13 +2108,28 @@
} );
}
- // 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 ) {
- 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 );
@@ -1746,6 +2141,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 = [];
@@ -1815,7 +2232,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;
}
@@ -1838,7 +2255,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;
}
@@ -1853,32 +2270,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
@@ -1896,8 +2287,8 @@
};
if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) {
- capturePointer( tracker, false );
$.stopEvent( event );
+ capturePointer( tracker, gPoint.type );
}
if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
@@ -1947,8 +2338,7 @@
};
if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) {
- releasePointer( tracker, false );
- //$.stopEvent( event );
+ releasePointer( tracker, gPoint.type );
}
}
@@ -2133,6 +2523,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',
@@ -2196,6 +2587,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',
@@ -2224,7 +2616,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.
*
@@ -2242,30 +2634,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.nonPrimaryPressHandler ) {
+ propagate = tracker.nonPrimaryPressHandler(
+ {
+ 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;
}
@@ -2345,7 +2778,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.
*
@@ -2369,30 +2802,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.nonPrimaryReleaseHandler ) {
+ propagate = tracker.nonPrimaryReleaseHandler(
+ {
+ 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/navigator.js b/src/navigator.js
index 9e18d6ca..464cd988 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
@@ -99,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,
@@ -168,24 +168,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 +193,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,8 +201,18 @@ $.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 )
+ });
+
};
$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{
diff --git a/src/openseadragon.js b/src/openseadragon.js
index f8b744de..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,
@@ -515,10 +519,18 @@
*
* @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 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
* display a scrolling strip of image thumbnails for navigating through the images.
@@ -945,6 +957,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/referencestrip.js b/src/referencestrip.js
index f68744b2..480009ec 100644
--- a/src/referencestrip.js
+++ b/src/referencestrip.js
@@ -125,8 +125,9 @@ $.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 );
+ } );
//Controls the position and orientation of the reference strip and sets the
//appropriate width and height
@@ -214,7 +215,7 @@ $.ReferenceStrip = function ( options ) {
viewer.goToPage( page );
}
}
- } ).setTracking( true );
+ } );
this.element.appendChild( element );
@@ -446,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(
@@ -511,6 +514,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 +554,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 39ed6294..85ec594a 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 = options.tabIndex || 0;
//the container is created through applying the ControlDock constructor above
this.container.className = "openseadragon-container";
@@ -290,19 +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 ));
-
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 );
@@ -315,96 +295,39 @@ $.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 );
- }
- },
-
- keyHandler: function( event ){
- if ( !event.preventDefaultAction ) {
- 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
- 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 115://s
- case 83://S
- 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 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;
- default:
- //console.log( 'navigator keycode %s', event.keyCode );
- 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,
- clickHandler: $.delegate( this, onCanvasClick ),
- dblClickHandler: $.delegate( this, onCanvasDblClick ),
- dragHandler: $.delegate( this, onCanvasDrag ),
- dragEndHandler: $.delegate( this, onCanvasDragEnd ),
- releaseHandler: $.delegate( this, onCanvasRelease ),
- scrollHandler: $.delegate( this, onCanvasScroll ),
- pinchHandler: $.delegate( this, onCanvasPinch )
- }).setTracking( this.mouseNavEnabled ? true : false ); // default state
+ element: this.canvas,
+ startDisabled: this.mouseNavEnabled ? false : true,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
+ dblClickTimeThreshold: this.dblClickTimeThreshold,
+ dblClickDistThreshold: this.dblClickDistThreshold,
+ keyDownHandler: $.delegate( this, onCanvasKeyDown ),
+ keyHandler: $.delegate( this, onCanvasKeyPress ),
+ clickHandler: $.delegate( this, onCanvasClick ),
+ 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 ),
+ scrollHandler: $.delegate( this, onCanvasScroll ),
+ pinchHandler: $.delegate( this, onCanvasPinch )
+ });
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 ),
- pressHandler: $.delegate( this, onContainerPress ),
- releaseHandler: $.delegate( this, onContainerRelease )
- }).setTracking( this.mouseNavEnabled ? true : false ); // always tracking
+ exitHandler: $.delegate( this, onContainerExit )
+ });
if( this.toolbar ){
this.toolbar = new $.ControlDock({ element: this.toolbar });
@@ -539,9 +462,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();
@@ -605,9 +532,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();
}
@@ -620,7 +544,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
@@ -1968,6 +1891,10 @@ function openTileSource( viewer, source ) {
_this.viewport.resetContentSize( _this.source.dimensions );
}
+ if( _this.preserveOverlays ){
+ _this.overlays = _this.currentOverlays;
+ }
+
_this.source.overlays = _this.source.overlays || [];
_this.drawer = new $.Drawer({
@@ -2262,9 +2189,102 @@ function onBlur(){
}
+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.canvas;
+
+ // If we don't have keyboard focus, request it.
+ if ( !haveKeyboardFocus ) {
+ this.canvas.focus();
+ }
+
if ( !event.preventDefaultAction && this.viewport && event.quick ) {
gestureSettings = this.gestureSettingsByDeviceType( event.pointerType );
if ( gestureSettings.clickToZoom ) {
@@ -2420,15 +2440,102 @@ 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 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
* @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.
@@ -2437,6 +2544,7 @@ function onCanvasRelease( event ) {
*/
this.raiseEvent( 'canvas-release', {
tracker: event.eventSource,
+ pointerType: event.pointerType,
position: event.position,
insideElementPressed: event.insideElementPressed,
insideElementReleased: event.insideElementReleased,
@@ -2444,6 +2552,62 @@ function onCanvasRelease( event ) {
});
}
+function onCanvasNonPrimaryPress( event ) {
+ /**
+ * Raised when any non-primary pointer button is pressed on the {@link OpenSeadragon.Viewer#canvas} element.
+ *
+ * @event canvas-nonprimary-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-nonprimary-press', {
+ tracker: event.eventSource,
+ position: event.position,
+ pointerType: event.pointerType,
+ button: event.button,
+ buttons: event.buttons,
+ originalEvent: event.originalEvent
+ });
+}
+
+function onCanvasNonPrimaryRelease( event ) {
+ /**
+ * Raised when any non-primary pointer button is released on the {@link OpenSeadragon.Viewer#canvas} element.
+ *
+ * @event canvas-nonprimary-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-nonprimary-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,
@@ -2546,8 +2710,38 @@ 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 {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( 'container-enter', {
+ tracker: event.eventSource,
+ position: event.position,
+ buttons: event.buttons,
+ pointers: event.pointers,
+ 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 );
@@ -2563,6 +2757,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.
@@ -2572,71 +2767,7 @@ function onContainerExit( event ) {
tracker: event.eventSource,
position: event.position,
buttons: event.buttons,
- insideElementPressed: event.insideElementPressed,
- buttonDownAny: event.buttonDownAny,
- originalEvent: event.originalEvent
- });
-}
-
-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 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,
+ pointers: event.pointers,
insideElementPressed: event.insideElementPressed,
buttonDownAny: event.buttonDownAny,
originalEvent: event.originalEvent
diff --git a/test/events.js b/test/events.js
index ba1a36e2..677e805f 100644
--- a/test/events.js
+++ b/test/events.js
@@ -35,6 +35,8 @@
origExitHandler,
origPressHandler,
origReleaseHandler,
+ origNonPrimaryPressHandler,
+ origNonPrimaryReleaseHandler,
origMoveHandler,
origClickHandler,
origDblClickHandler,
@@ -44,6 +46,10 @@
exitCount,
pressCount,
releaseCount,
+ rightPressCount,
+ rightReleaseCount,
+ middlePressCount,
+ middleReleaseCount,
moveCount,
clickCount,
dblClickCount,
@@ -94,6 +100,36 @@
return true;
}
};
+ origNonPrimaryPressHandler = tracker.nonPrimaryPressHandler;
+ tracker.nonPrimaryPressHandler = function ( event ) {
+ if (event.button === 0) {
+ pressCount++;
+ } else if (event.button === 1) {
+ middlePressCount++;
+ } else if (event.button === 2) {
+ rightPressCount++;
+ }
+ if (origNonPrimaryPressHandler) {
+ return origNonPrimaryPressHandler( event );
+ } else {
+ return true;
+ }
+ };
+ origNonPrimaryReleaseHandler = tracker.nonPrimaryReleaseHandler;
+ tracker.nonPrimaryReleaseHandler = function ( event ) {
+ if (event.button === 0) {
+ releaseCount++;
+ } else if (event.button === 1) {
+ middleReleaseCount++;
+ } else if (event.button === 2) {
+ rightReleaseCount++;
+ }
+ if (origNonPrimaryReleaseHandler) {
+ return origNonPrimaryReleaseHandler( event );
+ } else {
+ return true;
+ }
+ };
origMoveHandler = tracker.moveHandler;
tracker.moveHandler = function ( event ) {
moveCount++;
@@ -168,20 +204,37 @@
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 );
- };
+
+ //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 );
+ //};
var simulateDown = function (x, y) {
+ simEvent.button = 0;
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mousedown', simEvent );
};
var simulateUp = function (x, y) {
+ simEvent.button = 0;
+ simEvent.clientX = offset.left + x;
+ simEvent.clientY = offset.top + y;
+ $canvas.simulate( 'mouseup', simEvent );
+ };
+
+ var simulateNonPrimaryDown = function (x, y, button) {
+ simEvent.button = button;
+ simEvent.clientX = offset.left + x;
+ simEvent.clientY = offset.top + y;
+ $canvas.simulate( 'mousedown', simEvent );
+ };
+
+ var simulateNonPrimaryUp = function (x, y, button) {
+ simEvent.button = button;
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mouseup', simEvent );
@@ -198,6 +251,7 @@
var resetForAssessment = function () {
simEvent = {
+ button: 0,
clientX: offset.left,
clientY: offset.top
};
@@ -205,6 +259,10 @@
exitCount = 0;
pressCount = 0;
releaseCount = 0;
+ rightPressCount = 0;
+ rightReleaseCount = 0;
+ middlePressCount = 0;
+ middleReleaseCount = 0;
moveCount = 0;
clickCount = 0;
dblClickCount = 0;
@@ -231,6 +289,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 + 'nonPrimaryPressHandler event count (secondary/right button) matches expected (' + expected.rightPressCount + ')' );
+ }
+ if ('rightReleaseCount' in expected) {
+ equal( rightReleaseCount, expected.rightReleaseCount, expected.description + 'nonPrimaryReleaseHandler event count (secondary/right button) matches expected (' + expected.rightReleaseCount + ')' );
+ }
+ if ('middlePressCount' in expected) {
+ equal( middlePressCount, expected.middlePressCount, expected.description + 'nonPrimaryPressHandler event count (aux/middle button) matches expected (' + expected.middlePressCount + ')' );
+ }
+ 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 + ')' );
}
@@ -290,6 +360,10 @@
exitCount: 0,
pressCount: 0,
releaseCount: 1,
+ rightPressCount: 0,
+ rightReleaseCount: 0,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
moveCount: 20,
clickCount: 0,
dblClickCount: 0,
@@ -315,6 +389,10 @@
exitCount: 1,
pressCount: 0,
releaseCount: 0,
+ rightPressCount: 0,
+ rightReleaseCount: 0,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
moveCount: 20,
clickCount: 0,
dblClickCount: 0,
@@ -338,6 +416,10 @@
exitCount: 1,
pressCount: 0,
releaseCount: 0,
+ rightPressCount: 0,
+ rightReleaseCount: 0,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
moveCount: 20,
clickCount: 0,
dblClickCount: 0,
@@ -350,7 +432,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 +441,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,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
moveCount: 0,
clickCount: 2,
dblClickCount: 1,
@@ -376,18 +462,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,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
moveCount: 0,
clickCount: 1,
dblClickCount: 0,
@@ -400,6 +490,92 @@
quickClick: true
});
+ // enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click)
+ resetForAssessment();
+ simulateEnter(0, 0);
+ simulateNonPrimaryDown(0, 0, 2);
+ simulateNonPrimaryUp(0, 0, 2);
+ simulateLeave(-1, -1);
+ assessGestureExpectations({
+ description: 'enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click): ',
+ enterCount: 1,
+ exitCount: 1,
+ pressCount: 0,
+ releaseCount: 0,
+ rightPressCount: 1,
+ rightReleaseCount: 1,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
+ moveCount: 0,
+ clickCount: 0,
+ dblClickCount: 0,
+ dragCount: 0,
+ dragEndCount: 0,
+ //insideElementPressed: true,
+ //insideElementReleased: true,
+ contacts: 0,
+ trackedPointers: 0,
+ //quickClick: true
+ });
+
+ // enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click)
+ resetForAssessment();
+ simulateEnter(0, 0);
+ simulateNonPrimaryDown(0, 0, 1);
+ simulateNonPrimaryUp(0, 0, 1);
+ simulateLeave(-1, -1);
+ assessGestureExpectations({
+ description: 'enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click): ',
+ enterCount: 1,
+ exitCount: 1,
+ pressCount: 0,
+ releaseCount: 0,
+ rightPressCount: 0,
+ rightReleaseCount: 0,
+ middlePressCount: 1,
+ middleReleaseCount: 1,
+ moveCount: 0,
+ clickCount: 0,
+ dblClickCount: 0,
+ dragCount: 0,
+ dragEndCount: 0,
+ //insideElementPressed: true,
+ //insideElementReleased: true,
+ contacts: 0,
+ trackedPointers: 0,
+ //quickClick: true
+ });
+
+ // enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element)
+ resetForAssessment();
+ simulateEnter(0, 0);
+ simulateNonPrimaryDown(0, 0, 2);
+ simulateMove(1, 1, 100);
+ simulateNonPrimaryUp(10, 10, 2);
+ simulateMove(-1, -1, 100);
+ simulateLeave(-1, -1);
+ assessGestureExpectations({
+ description: 'enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element): ',
+ enterCount: 1,
+ exitCount: 1,
+ pressCount: 0,
+ releaseCount: 0,
+ rightPressCount: 1,
+ rightReleaseCount: 1,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
+ moveCount: 200,
+ clickCount: 0,
+ dblClickCount: 0,
+ dragCount: 0,
+ dragEndCount: 0,
+ //insideElementPressed: true,
+ //insideElementReleased: true,
+ contacts: 0,
+ trackedPointers: 0,
+ //quickClick: false
+ });
+
// enter-press-move-release-move-exit (drag, release in tracked element)
resetForAssessment();
simulateEnter(0, 0);
@@ -414,6 +590,10 @@
exitCount: 1,
pressCount: 1,
releaseCount: 1,
+ rightPressCount: 0,
+ rightReleaseCount: 0,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
moveCount: 200,
clickCount: 1,
dblClickCount: 0,
@@ -441,6 +621,10 @@
exitCount: 1,
pressCount: 1,
releaseCount: 1,
+ rightPressCount: 0,
+ rightReleaseCount: 0,
+ middlePressCount: 0,
+ middleReleaseCount: 0,
moveCount: 15,
clickCount: 0,
dblClickCount: 0,
@@ -453,32 +637,36 @@
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,
+ // rightPressCount: 0,
+ // rightReleaseCount: 0,
+ // middlePressCount: 0,
+ // middleReleaseCount: 0,
+ // moveCount: 10,
+ // clickCount: 0,
+ // dblClickCount: 0,
+ // dragCount: 10,
+ // dragEndCount: 1,
+ // insideElementPressed: true,
+ // insideElementReleased: false,
+ // contacts: 0,
+ // trackedPointers: 0,
+ // quickClick: false
+ //});
- // 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();
@@ -602,7 +790,7 @@
releaseHandler: onMouseTrackerRelease,
clickHandler: onMouseTrackerClick,
exitHandler: onMouseTrackerExit
- } ).setTracking( true );
+ } );
var event = {
clientX:1,
diff --git a/test/legacy.mouse.shim.js b/test/legacy.mouse.shim.js
index 7a8ff7cc..3609ed85 100644
--- a/test/legacy.mouse.shim.js
+++ b/test/legacy.mouse.shim.js
@@ -11,26 +11,29 @@
$.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" );
}
- $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" );
- $.MouseTracker.haveMouseEnter = false;
- 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" );
- if ( 'ontouchenter' in window ) {
- $.MouseTracker.subscribeEvents.push( "touchenter", "touchleave" );
- $.MouseTracker.haveTouchEnter = true;
- } else {
- $.MouseTracker.haveTouchEnter = false;
- }
+ $.MouseTracker.havePointerEvents = false;
+ if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
+ $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" );
+ $.MouseTracker.haveMouseEnter = true;
} else {
- $.MouseTracker.haveTouchEnter = false;
+ $.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/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 ( '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" );
}
$.MouseTracker.mousePointerId = "legacy-mouse";
$.MouseTracker.maxTouchPoints = 10;
+
}(OpenSeadragon));