diff --git a/Gruntfile.js b/Gruntfile.js
index e030188c..e3395308 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -202,7 +202,7 @@ module.exports = function(grunt) {
target: sources
},
"git-describe": {
- "options": {
+ options: {
failOnError: false
},
build: {}
diff --git a/changelog.txt b/changelog.txt
index c079381d..38fcc2d4 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,15 +1,41 @@
OPENSEADRAGON CHANGELOG
=======================
-2.4.3: (In progress)
+2.5.0: (In progress)
+* BREAKING CHANGE: Dropped support for older browsers (IE < 11) (#1949 @msalsbery)
+* BREAKING CHANGE: Removed deprecated OpenSeadragon.getEvent function (#1949 @msalsbery)
+* DEPRECATION: MouseTracker exitHandler deprecated for name change to leaveHandler for consistency with DOM event names (#1872 @msalsbery)
* Now when "simple image" tile sources are removed from the viewer, they free the memory used by the pyramid they create (#1789 @TakumaKira)
* Documentation fix (#1814 @kenanchristian)
* Better cleanup on destruction, to avoid memory leaks (#1832 @JoFrMueller)
+* Better handle destruction when navigator in custom location (#1884 @woodchuck)
* Miscellaneous code cleanup (#1840 @msalsbery)
* You can now specify tileSize for the Zoomify Tile Source (#1868 @abrlam)
* Better use of IIIF "max" and "full" URL parameters (#1871 @MImranAsghar)
* You can now specify the file format of the tiles in the Zoomify tile source (#1889 @abrlam)
+* Improved browser sniffing - detect EDGE and CHROMEEDGE browsers (#1872 @msalsbery)
+* Improved DOM event model feature detection (#1872 @msalsbery)
+* Added support for options parameter on addEvent()/removeEvent (to support passive option) (#1872 @msalsbery)
+* Added OpenSeadragon.eventIsCanceled() function for defaultPrevented detection on DOM events (#1872 @msalsbery)
+* MouseTracker: better PointerEvent model detection - removed use of deprecated window.navigator.pointerEnabled (#1872 @msalsbery)
+* MouseTracker: added overHandler/outHandler options for handling corresponding pointerover/pointerout events (#1872 @msalsbery)
+* MouseTracker: changed enterHandler/leaveHandler to use DOM pointerenter/pointerleave events instead of simulating using pointerover/pointerout (#1872 @msalsbery)
+* All internal uses of MouseTracker use pointerenter/pointerleave events instead of pointerover/pointerout events for more consistent pointer tracking (#1872 @msalsbery)
+* Fixed bug in Button class where two MouseTracker event handlers used an invalid "this" causing issues in some browsers (#1872 @msalsbery)
+* Added pointerType property to Viewer container-enter, container-exit, canvas-drag, canvas-drag-end, canvas-pinch events (#1872 @msalsbery)
+* MouseTracker: Fire dragEndHandler event even if release point same as initial contact point (#1872 @msalsbery)
+* MouseTracker: Pointer capture implemented with capture APIs where available. Only fallback to emulated capture on extremely old browsers (#1872 @msalsbery)
+* MouseTracker: Added preProcessEventHandler option to allow MouseTracker instances to control bubbling and default behavior of events on their associated element (#1872 @msalsbery)
+* MouseTracker: Improved handling of canceled events (#1872 @msalsbery)
+* MouseTracker: Improved releasing of tracked pointers on destroy()/stopTracking() (#1872 @msalsbery)
+* Updated Viewer, Button, Drawer, Navigator, ReferenceStrip DOM for proper DOM event handling (#1872 @msalsbery)
+* Added OpenSeadragon.setElementPointerEventsNone() for setting pointer-events:'none' on DOM elements (#1872 @msalsbery)
+* MouseTracker: added contextMenuHandler option for handling contextmenu events (#1872 @msalsbery)
+* Viewer: added a canvas-contextmenu event (#1872 @msalsbery)
+* Added additional documentation for the zoomPerSecond viewer option (#1872 @msalsbery)
+* MouseTracker: Per #1863, dropped support for Internet Explorer < 11 (#1872 @msalsbery) (#1950 @rmontroy)
+* Fixed simulated drag events in navigator tests (#1949 @msalsbery)
2.4.2:
@@ -57,7 +83,7 @@ OPENSEADRAGON CHANGELOG
* You can now prevent canvas-click events on the navigator (#1416)
* The navigator can now be restricted to just horizontal or just vertical panning (#1416)
* Fixed DziTileSource so it doesn't load levels above maxLevel or below minLevel, if set (#1492)
-
+
2.3.1:
* Debug mode now uses different colors for different tiled images (customizable via debugGridColor) (#1271)
diff --git a/package-lock.json b/package-lock.json
index 04ffb707..96715f72 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -389,9 +389,9 @@
}
},
"bl": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
- "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
+ "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
"dev": true,
"requires": {
"readable-stream": "^2.3.5",
@@ -2578,9 +2578,9 @@
"dev": true
},
"ini": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
- "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz",
+ "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==",
"dev": true
},
"is-accessor-descriptor": {
@@ -4938,9 +4938,9 @@
},
"dependencies": {
"bl": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
- "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"dev": true,
"optional": true,
"requires": {
diff --git a/src/button.js b/src/button.js
index 7b00f9ee..5eaabfc3 100644
--- a/src/button.js
+++ b/src/button.js
@@ -77,6 +77,7 @@ $.ButtonState = {
* @param {OpenSeadragon.EventHandler} [options.onExit=null] Event handler callback for {@link OpenSeadragon.Button.event:exit}.
* @param {OpenSeadragon.EventHandler} [options.onFocus=null] Event handler callback for {@link OpenSeadragon.Button.event:focus}.
* @param {OpenSeadragon.EventHandler} [options.onBlur=null] Event handler callback for {@link OpenSeadragon.Button.event:blur}.
+ * @param {Object} [options.userData=null] Arbitrary object to be passed unchanged to any attached handler methods.
*/
$.Button = function( options ) {
@@ -111,7 +112,8 @@ $.Button = function( options ) {
onEnter: null,
onExit: null,
onFocus: null,
- onBlur: null
+ onBlur: null,
+ userData: null
}, options );
@@ -136,6 +138,13 @@ $.Button = function( options ) {
this.imgDown.alt =
this.tooltip;
+ // Allow pointer events to pass through the img elements so implicit
+ // pointer capture works on touch devices
+ $.setElementPointerEventsNone( this.imgRest );
+ $.setElementPointerEventsNone( this.imgGroup );
+ $.setElementPointerEventsNone( this.imgHover );
+ $.setElementPointerEventsNone( this.imgDown );
+
this.element.style.position = "relative";
$.setElementTouchActionNone( this.element );
@@ -203,6 +212,7 @@ $.Button = function( options ) {
*/
this.tracker = new $.MouseTracker({
+ userData: 'Button.tracker',
element: this.element,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
@@ -227,7 +237,7 @@ $.Button = function( options ) {
},
focusHandler: function ( event ) {
- this.enterHandler( event );
+ _this.tracker.enterHandler( event );
/**
* Raised when the Button element receives focus.
*
@@ -241,7 +251,7 @@ $.Button = function( options ) {
_this.raiseEvent( "focus", { originalEvent: event.originalEvent } );
},
- exitHandler: function( event ) {
+ leaveHandler: function( event ) {
outTo( _this, $.ButtonState.GROUP );
if ( event.insideElementPressed ) {
/**
@@ -259,7 +269,7 @@ $.Button = function( options ) {
},
blurHandler: function ( event ) {
- this.exitHandler( event );
+ _this.tracker.leaveHandler( event );
/**
* Raised when the Button element loses focus.
*
@@ -363,8 +373,8 @@ $.Button = function( options ) {
$.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.Button.prototype */{
/**
- * TODO: Determine what this function is intended to do and if it's actually
- * useful as an API point.
+ * Used by a button container element (e.g. a ButtonGroup) to transition the button state
+ * to ButtonState.GROUP.
* @function
*/
notifyGroupEnter: function() {
@@ -372,8 +382,8 @@ $.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.
},
/**
- * TODO: Determine what this function is intended to do and if it's actually
- * useful as an API point.
+ * Used by a button container element (e.g. a ButtonGroup) to transition the button state
+ * to ButtonState.REST.
* @function
*/
notifyGroupExit: function() {
@@ -399,14 +409,22 @@ $.extend( $.Button.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.
},
destroy: function() {
- this.element.removeChild(this.imgRest);
- this.imgRest = null;
- this.element.removeChild(this.imgGroup);
- this.imgGroup = null;
- this.element.removeChild(this.imgHover);
- this.imgHover = null;
- this.element.removeChild(this.imgDown);
- this.imgDown = null;
+ if (this.imgRest) {
+ this.element.removeChild(this.imgRest);
+ this.imgRest = null;
+ }
+ if (this.imgGroup) {
+ this.element.removeChild(this.imgGroup);
+ this.imgGroup = null;
+ }
+ if (this.imgHover) {
+ this.element.removeChild(this.imgHover);
+ this.imgHover = null;
+ }
+ if (this.imgDown) {
+ this.element.removeChild(this.imgDown);
+ this.imgDown = null;
+ }
this.removeAllHandlers();
this.tracker.destroy();
this.element = null;
diff --git a/src/buttongroup.js b/src/buttongroup.js
index 995f90d3..5af71fea 100644
--- a/src/buttongroup.js
+++ b/src/buttongroup.js
@@ -88,6 +88,7 @@ $.ButtonGroup = function( options ) {
* @memberof OpenSeadragon.ButtonGroup#
*/
this.tracker = new $.MouseTracker({
+ userData: 'ButtonGroup.tracker',
element: this.element,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
@@ -97,7 +98,7 @@ $.ButtonGroup = function( options ) {
_this.buttons[ i ].notifyGroupEnter();
}
},
- exitHandler: function ( event ) {
+ leaveHandler: function ( event ) {
var i;
if ( !event.insideElementPressed ) {
for ( i = 0; i < _this.buttons.length; i++ ) {
@@ -127,8 +128,8 @@ $.ButtonGroup.prototype = {
* @function
* @private
*/
- emulateExit: function() {
- this.tracker.exitHandler( { eventSource: this.tracker } );
+ emulateLeave: function() {
+ this.tracker.leaveHandler( { eventSource: this.tracker } );
},
destroy: function() {
diff --git a/src/control.js b/src/control.js
index 64f762d7..6cb229f8 100644
--- a/src/control.js
+++ b/src/control.js
@@ -161,7 +161,9 @@ $.Control.prototype = {
*/
destroy: function() {
this.wrapper.removeChild( this.element );
- this.container.removeChild( this.wrapper );
+ if (this.anchor !== $.ControlAnchor.NONE) {
+ this.container.removeChild(this.wrapper);
+ }
},
/**
diff --git a/src/drawer.js b/src/drawer.js
index 31968224..fca4b956 100644
--- a/src/drawer.js
+++ b/src/drawer.js
@@ -126,6 +126,10 @@ $.Drawer = function( options ) {
this.canvas.style.height = "100%";
this.canvas.style.position = "absolute";
$.setElementOpacity( this.canvas, this.opacity, true );
+ // Allow pointer events to pass through the canvas element so implicit
+ // pointer capture works on touch devices
+ $.setElementPointerEventsNone( this.canvas );
+ $.setElementTouchActionNone( this.canvas );
// explicit left-align
this.container.style.textAlign = "left";
diff --git a/src/mousetracker.js b/src/mousetracker.js
index d1b584ae..4aefd249 100644
--- a/src/mousetracker.js
+++ b/src/mousetracker.js
@@ -72,10 +72,20 @@
* @param {Number} [options.stopDelay=50]
* The number of milliseconds without pointer move before the stop
* event is fired.
+ * @param {OpenSeadragon.EventHandler} [options.preProcessEventHandler=null]
+ * An optional handler for controlling DOM event propagation and processing.
+ * @param {OpenSeadragon.EventHandler} [options.contextMenuHandler=null]
+ * An optional handler for contextmenu.
* @param {OpenSeadragon.EventHandler} [options.enterHandler=null]
* An optional handler for pointer enter.
+ * @param {OpenSeadragon.EventHandler} [options.leaveHandler=null]
+ * An optional handler for pointer leave.
* @param {OpenSeadragon.EventHandler} [options.exitHandler=null]
- * An optional handler for pointer exit.
+ * An optional handler for pointer leave. Deprecated. Use leaveHandler instead.
+ * @param {OpenSeadragon.EventHandler} [options.overHandler=null]
+ * An optional handler for pointer over.
+ * @param {OpenSeadragon.EventHandler} [options.outHandler=null]
+ * An optional handler for pointer out.
* @param {OpenSeadragon.EventHandler} [options.pressHandler=null]
* An optional handler for pointer press.
* @param {OpenSeadragon.EventHandler} [options.nonPrimaryPressHandler=null]
@@ -164,8 +174,13 @@
this.userData = options.userData || null;
this.stopDelay = options.stopDelay || 50;
+ this.preProcessEventHandler = options.preProcessEventHandler || null;
+ this.contextMenuHandler = options.contextMenuHandler || null;
this.enterHandler = options.enterHandler || null;
- this.exitHandler = options.exitHandler || null;
+ this.leaveHandler = options.leaveHandler || null;
+ this.exitHandler = options.exitHandler || null; // Deprecated v2.5.0
+ this.overHandler = options.overHandler || null;
+ this.outHandler = options.outHandler || null;
this.pressHandler = options.pressHandler || null;
this.nonPrimaryPressHandler = options.nonPrimaryPressHandler || null;
this.releaseHandler = options.releaseHandler || null;
@@ -201,44 +216,41 @@
keypress: function ( event ) { onKeyPress( _this, event ); },
focus: function ( event ) { onFocus( _this, event ); },
blur: function ( event ) { onBlur( _this, event ); },
+ contextmenu: function ( event ) { onContextMenu( _this, event ); },
wheel: function ( event ) { onWheel( _this, event ); },
mousewheel: function ( event ) { onMouseWheel( _this, event ); },
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 ); },
- mouseup: function ( event ) { onMouseUp( _this, event ); },
- mouseupcaptured: function ( event ) { onMouseUpCaptured( _this, event ); },
- mousemove: function ( event ) { onMouseMove( _this, event ); },
- mousemovecaptured: function ( event ) { onMouseMoveCaptured( _this, event ); },
+ losecapture: function ( event ) { onLoseCapture( _this, event ); },
+
+ mouseenter: function ( event ) { onPointerEnter( _this, event ); },
+ mouseleave: function ( event ) { onPointerLeave( _this, event ); },
+ mouseover: function ( event ) { onPointerOver( _this, event ); },
+ mouseout: function ( event ) { onPointerOut( _this, event ); },
+ mousedown: function ( event ) { onPointerDown( _this, event ); },
+ mouseup: function ( event ) { onPointerUp( _this, event ); },
+ mousemove: function ( event ) { onPointerMove( _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 ); },
- gesturechange: function ( event ) { onGestureChange( _this, event ); },
+ gesturestart: function ( event ) { onGestureStart( _this, event ); }, // Safari/Safari iOS
+ gesturechange: function ( event ) { onGestureChange( _this, event ); }, // Safari/Safari iOS
+ gotpointercapture: function ( event ) { onGotPointerCapture( _this, event ); },
+ lostpointercapture: function ( event ) { onLostPointerCapture( _this, event ); },
+ pointerenter: function ( event ) { onPointerEnter( _this, event ); },
+ pointerleave: function ( event ) { onPointerLeave( _this, event ); },
pointerover: function ( event ) { onPointerOver( _this, event ); },
- MSPointerOver: function ( event ) { onPointerOver( _this, event ); },
pointerout: function ( event ) { onPointerOut( _this, event ); },
- MSPointerOut: function ( event ) { onPointerOut( _this, event ); },
pointerdown: function ( event ) { onPointerDown( _this, event ); },
- MSPointerDown: function ( event ) { onPointerDown( _this, event ); },
pointerup: function ( event ) { onPointerUp( _this, event ); },
- MSPointerUp: function ( event ) { onPointerUp( _this, event ); },
pointermove: function ( event ) { onPointerMove( _this, event ); },
- MSPointerMove: function ( event ) { onPointerMove( _this, event ); },
pointercancel: function ( event ) { onPointerCancel( _this, event ); },
- MSPointerCancel: function ( event ) { onPointerCancel( _this, event ); },
pointerupcaptured: function ( event ) { onPointerUpCaptured( _this, event ); },
pointermovecaptured: function ( event ) { onPointerMoveCaptured( _this, event ); },
@@ -262,6 +274,18 @@
currentPinchCenter: null
};
+ this.hasGestureHandlers = !!( this.pressHandler || this.nonPrimaryPressHandler ||
+ this.releaseHandler || this.nonPrimaryReleaseHandler ||
+ this.clickHandler || this.dblClickHandler ||
+ this.dragHandler || this.dragEndHandler ||
+ this.pinchHandler );
+ this.hasScrollHandler = !!this.scrollHandler;
+ this.hasContextMenuHandler = !!this.contextMenuHandler;
+
+ if (this.exitHandler) {
+ $.console.error("MouseTracker.exitHandler is deprecated. Use MouseTracker.leaveHandler instead.");
+ }
+
if ( !options.startDisabled ) {
this.setTracking( true );
}
@@ -317,25 +341,6 @@
return this;
},
- /**
- * Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for all but the given pointer device type.
- * @function
- * @param {String} type - The pointer device type: "mouse", "touch", "pen", etc.
- * @returns {Array.}
- */
- getActivePointersListsExceptType: function ( type ) {
- var delegate = THIS[ this.hash ];
- var listArray = [];
-
- for (var i = 0; i < delegate.activePointersLists.length; ++i) {
- if (delegate.activePointersLists[i].type !== type) {
- listArray.push(delegate.activePointersLists[i]);
- }
- }
-
- return listArray;
- },
-
/**
* Returns the {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} for the given pointer device type,
* creating and caching a new {@link OpenSeadragon.MouseTracker.GesturePointList|GesturePointList} if one doesn't already exist for the type.
@@ -378,6 +383,30 @@
return count;
},
+ /**
+ * Implement or assign implementation to these handlers during or after
+ * calling the constructor.
+ * @function
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ */
+ preProcessEventHandler: 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 {OpenSeadragon.Point} event.position
+ * The position of the event relative to the tracked element.
+ * @param {Object} event.originalEvent
+ * The original event object.
+ * @param {Object} event.userData
+ * Arbitrary user-defined object.
+ */
+ contextMenuHandler: function () { },
+
/**
* Implement or assign implementation to these handlers during or after
* calling the constructor.
@@ -403,8 +432,6 @@
* 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.
*/
@@ -414,6 +441,38 @@
* Implement or assign implementation to these handlers during or after
* calling the constructor.
* @function
+ * @since v2.5.0
+ * @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.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.
+ * @param {Boolean} event.buttonDownAny
+ * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.
+ * @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 {Object} event.userData
+ * Arbitrary user-defined object.
+ */
+ leaveHandler: function () { },
+
+ /**
+ * Implement or assign implementation to these handlers during or after
+ * calling the constructor.
+ * @function
+ * @deprecated v2.5.0 Use leaveHandler instead
* @param {Object} event
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
@@ -442,6 +501,72 @@
*/
exitHandler: function () { },
+ /**
+ * Implement or assign implementation to these handlers during or after
+ * calling the constructor.
+ * @function
+ * @since v2.5.0
+ * @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.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.
+ * @param {Boolean} event.buttonDownAny
+ * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.
+ * @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.
+ */
+ overHandler: function () { },
+
+ /**
+ * Implement or assign implementation to these handlers during or after
+ * calling the constructor.
+ * @function
+ * @since v2.5.0
+ * @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.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.
+ * @param {Boolean} event.buttonDownAny
+ * Was the button down anywhere in the screen during the event. Deprecated. Use buttons instead.
+ * @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.
+ */
+ outHandler: function () { },
+
/**
* Implement or assign implementation to these handlers during or after
* calling the constructor.
@@ -881,21 +1006,35 @@
blurHandler: function () { }
};
+ // https://github.com/openseadragon/openseadragon/pull/790
/**
- * Resets all active mousetrakers. (Added to patch issue #697 "Mouse up outside map will cause "canvas-drag" event to stick")
- *
+ * True if inside an iframe, otherwise false.
+ * @member {Boolean} isInIframe
* @private
- * @member resetAllMouseTrackers
- * @memberof OpenSeadragon.MouseTracker
+ * @inner
*/
- $.MouseTracker.resetAllMouseTrackers = function(){
- for(var i = 0; i < MOUSETRACKERS.length; i++){
- if (MOUSETRACKERS[i].isTracking()){
- MOUSETRACKERS[i].setTracking(false);
- MOUSETRACKERS[i].setTracking(true);
- }
+ var isInIframe = (function() {
+ try {
+ return window.self !== window.top;
+ } catch (e) {
+ return true;
}
- };
+ })();
+
+ // https://github.com/openseadragon/openseadragon/pull/790
+ /**
+ * @function
+ * @private
+ * @inner
+ * @returns {Boolean} True if the target supports DOM Level 2 event subscription methods, otherwise false.
+ */
+ function canAccessEvents (target) {
+ try {
+ return target.addEventListener && target.removeEventListener;
+ } catch (e) {
+ return false;
+ }
+ }
/**
* Provides continuous computation of velocity (speed and direction) of active pointers.
@@ -1002,58 +1141,42 @@
document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least 'mousewheel'
'DOMMouseScroll'; // Assume old Firefox
- /**
- * Detect legacy mouse capture support.
- */
- $.MouseTracker.supportsMouseCapture = (function () {
- var divElement = document.createElement( 'div' );
- return $.isFunction( divElement.setCapture ) && $.isFunction( divElement.releaseCapture );
- }());
-
/**
* Detect browser pointer device event model(s) and build appropriate list of events to subscribe to.
*/
- $.MouseTracker.subscribeEvents = [ "click", "dblclick", "keydown", "keyup", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ];
+ $.MouseTracker.subscribeEvents = [ "click", "dblclick", "keydown", "keyup", "keypress", "focus", "blur", "contextmenu", $.MouseTracker.wheelEventName ];
if( $.MouseTracker.wheelEventName === "DOMMouseScroll" ) {
// Older Firefox
$.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" );
}
- // 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 ) ) {
+ if ( window.PointerEvent ) {
// IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents)
$.MouseTracker.havePointerEvents = true;
- $.MouseTracker.subscribeEvents.push( "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" );
- $.MouseTracker.unprefixedPointerEvents = true;
- if( navigator.maxTouchPoints ) {
- $.MouseTracker.maxTouchPoints = navigator.maxTouchPoints;
- } else {
- $.MouseTracker.maxTouchPoints = 0;
+ $.MouseTracker.subscribeEvents.push( "pointerenter", "pointerleave", "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" );
+ // Pointer events capture support
+ $.MouseTracker.havePointerCapture = (function () {
+ var divElement = document.createElement( 'div' );
+ return $.isFunction( divElement.setPointerCapture ) && $.isFunction( divElement.releasePointerCapture );
+ }());
+ if ( $.MouseTracker.havePointerCapture ) {
+ $.MouseTracker.subscribeEvents.push( "gotpointercapture", "lostpointercapture" );
}
- $.MouseTracker.haveMouseEnter = false;
- } 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 ) {
- $.MouseTracker.maxTouchPoints = navigator.msMaxTouchPoints;
- } else {
- $.MouseTracker.maxTouchPoints = 0;
- }
- $.MouseTracker.haveMouseEnter = false;
} else {
// Legacy W3C mouse events
$.MouseTracker.havePointerEvents = false;
- if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
- $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" );
- $.MouseTracker.haveMouseEnter = true;
- } else {
- $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" );
- $.MouseTracker.haveMouseEnter = false;
+ $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave", "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" );
+ $.MouseTracker.mousePointerId = "legacy-mouse";
+ // Legacy mouse events capture support (IE/Firefox only?)
+ $.MouseTracker.havePointerCapture = (function () {
+ var divElement = document.createElement( 'div' );
+ return $.isFunction( divElement.setCapture ) && $.isFunction( divElement.releaseCapture );
+ }());
+ if ( $.MouseTracker.havePointerCapture ) {
+ $.MouseTracker.subscribeEvents.push( "losecapture" );
}
- $.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" );
+ // Legacy touch events
if ( 'ontouchstart' in window ) {
// iOS, Android, and other W3c Touch Event implementations
// (see http://www.w3.org/TR/touch-events/)
@@ -1066,8 +1189,6 @@
// Subscribe to these to prevent default gesture handling
$.MouseTracker.subscribeEvents.push( "gesturestart", "gesturechange" );
}
- $.MouseTracker.mousePointerId = "legacy-mouse";
- $.MouseTracker.maxTouchPoints = 10;
}
@@ -1075,6 +1196,50 @@
// Classes and typedefs
///////////////////////////////////////////////////////////////////////////////
+ /**
+ * Used for the processing/disposition of DOM events (propagation, default handling, capture, etc.)
+ *
+ * @typedef {Object} EventProcessInfo
+ * @memberof OpenSeadragon.MouseTracker
+ * @since v2.5.0
+ *
+ * @property {OpenSeadragon.MouseTracker} eventSource
+ * A reference to the tracker instance.
+ * @property {Object} originalEvent
+ * The original DOM event object.
+ * @property {Number} eventPhase
+ * 0 == NONE, 1 == CAPTURING_PHASE, 2 == AT_TARGET, 3 == BUBBLING_PHASE.
+ * @property {String} eventType
+ * "contextmenu", "gotpointercapture", "lostpointercapture", "pointerenter", "pointerleave", "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel", "wheel", "click", "dblclick".
+ * @property {String} pointerType
+ * "mouse", "touch", "pen", etc.
+ * @property {Boolean} isEmulated
+ * True if this is an emulated event. If true, originalEvent is either the event that caused
+ * the emulated event, a synthetic event object created with values from the actual DOM event,
+ * or null if no DOM event applies. Emulated events can occur on eventType "wheel" on legacy mouse-scroll
+ * event emitting user agents.
+ * @property {Boolean} isStopable
+ * True if propagation of the event (e.g. bubbling) can be stopped with stopPropagation/stopImmediatePropagation.
+ * @property {Boolean} isCancelable
+ * True if the event's default handling by the browser can be prevented with preventDefault.
+ * @property {Boolean} defaultPrevented
+ * True if the event's default handling has already been prevented by a descendent element.
+ * @property {Boolean} preventDefault
+ * Set to true to prevent the event's default handling by the browser.
+ * @property {Boolean} preventGesture
+ * Set to true to prevent this MouseTracker from generating a gesture from the event.
+ * Valid on eventType "pointerdown".
+ * @property {Boolean} stopPropagation
+ * Set to true prevent the event from propagating to ancestor/descendent elements on capture/bubble phase.
+ * @property {Boolean} shouldCapture
+ * (Internal Use) Set to true if the pointer should be captured (events (re)targeted to tracker element).
+ * @property {Boolean} shouldReleaseCapture
+ * (Internal Use) Set to true if the captured pointer should be released.
+ * @property {Object} userData
+ * Arbitrary user-defined object.
+ */
+
+
/**
* Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointer device.
*
@@ -1238,7 +1403,7 @@
},
/**
- * Increment this pointer's contact count.
+ * Increment this pointer list's contact count.
* It will evaluate whether this pointer type is allowed to have multiple contacts.
* @function
*/
@@ -1246,12 +1411,13 @@
++this.contacts;
if (this.contacts > 1 && (this.type === "mouse" || this.type === "pen")) {
+ $.console.warn('GesturePointList.addContact() Implausible contacts value');
this.contacts = 1;
}
},
/**
- * Decrement this pointer's contact count.
+ * Decrement this pointer list's contact count.
* It will make sure the count does not go below 0.
* @function
*/
@@ -1259,6 +1425,7 @@
--this.contacts;
if (this.contacts < 0) {
+ $.console.warn('GesturePointList.removeContact() Implausible contacts value');
this.contacts = 0;
}
}
@@ -1276,49 +1443,28 @@
*/
function clearTrackedPointers( tracker ) {
var delegate = THIS[ tracker.hash ],
- i,
+ i, j,
+ pointsList,
+ gPoints,
+ gPointsToRemove,
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
- );
+ pointsList = delegate.activePointersLists[ i ];
- delegate.activePointersLists[ i ].captureCount = 0;
+ if ( pointsList.getLength() > 0 ) {
+ // Make an array containing references to the gPoints in the pointer list
+ // (because calls to stopTrackingPointer() are going to modify the pointer list)
+ gPointsToRemove = [];
+ gPoints = pointsList.asArray();
+ for ( j = 0; j < gPoints.length; j++ ) {
+ gPointsToRemove.push( gPoints[ j ] );
+ }
+
+ // Release and remove all gPoints from the pointer list
+ for ( j = 0; j < gPointsToRemove.length; j++ ) {
+ stopTrackingPointer( tracker, pointsList, gPointsToRemove[ j ] );
+ }
}
}
@@ -1390,17 +1536,17 @@
if ( pointerType === 'pointerevent' ) {
return {
- upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp',
+ upName: 'pointerup',
upHandler: delegate.pointerupcaptured,
- moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove',
+ moveName: 'pointermove',
moveHandler: delegate.pointermovecaptured
};
} else if ( pointerType === 'mouse' ) {
return {
- upName: 'mouseup',
- upHandler: delegate.mouseupcaptured,
- moveName: 'mousemove',
- moveHandler: delegate.mousemovecaptured
+ upName: 'pointerup',
+ upHandler: delegate.pointerupcaptured,
+ moveName: 'pointermove',
+ moveHandler: delegate.pointermovecaptured
};
} else if ( pointerType === 'touch' ) {
return {
@@ -1419,42 +1565,53 @@
* @private
* @inner
*/
- function capturePointer( tracker, pointerType, pointerCount ) {
- var pointsList = tracker.getActivePointersListByType( pointerType ),
- eventParams;
+ function capturePointer( tracker, gPoint ) {
+ var eventParams;
- pointsList.captureCount += (pointerCount || 1);
-
- 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)
- // eslint-disable-next-line no-use-before-define
- if (isInIframe && canAccessEvents(window.top)) {
- $.addEvent(
- window.top,
- eventParams.upName,
- eventParams.upHandler,
- true
- );
+ if ( $.MouseTracker.havePointerCapture ) {
+ if ( $.MouseTracker.havePointerEvents ) {
+ // Can throw InvalidPointerId
+ // (should never happen so we'll log a warning)
+ try {
+ tracker.element.setPointerCapture( gPoint.id );
+ //$.console.log('element.setPointerCapture() called');
+ } catch ( e ) {
+ $.console.warn('setPointerCapture() called on invalid pointer ID');
}
+ } else {
+ tracker.element.setCapture( true );
+ //$.console.log('element.setCapture() called');
+ }
+ } else {
+ // 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)
+ // eslint-disable-next-line no-use-before-define
+ //$.console.log('Emulated mouse capture set');
+ eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : gPoint.type );
+ // https://github.com/openseadragon/openseadragon/pull/790
+ if (isInIframe && canAccessEvents(window.top)) {
$.addEvent(
- $.MouseTracker.captureElement,
+ window.top,
eventParams.upName,
eventParams.upHandler,
true
);
- $.addEvent(
- $.MouseTracker.captureElement,
- eventParams.moveName,
- eventParams.moveHandler,
- true
- );
}
+ $.addEvent(
+ $.MouseTracker.captureElement,
+ eventParams.upName,
+ eventParams.upHandler,
+ true
+ );
+ $.addEvent(
+ $.MouseTracker.captureElement,
+ eventParams.moveName,
+ eventParams.moveHandler,
+ true
+ );
}
+
+ updatePointerCaptured( tracker, gPoint, true );
}
@@ -1463,76 +1620,102 @@
* @private
* @inner
*/
- function releasePointer( tracker, pointerType, pointerCount ) {
- var pointsList = tracker.getActivePointersListByType( pointerType ),
- eventParams;
+ function releasePointer( tracker, gPoint ) {
+ var eventParams;
+ var pointsList;
+ var cachedGPoint;
- pointsList.captureCount -= (pointerCount || 1);
-
- 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)
- // eslint-disable-next-line no-use-before-define
- if (isInIframe && canAccessEvents(window.top)) {
- $.removeEvent(
- window.top,
- eventParams.upName,
- eventParams.upHandler,
- true
- );
+ if ( $.MouseTracker.havePointerCapture ) {
+ if ( $.MouseTracker.havePointerEvents ) {
+ pointsList = tracker.getActivePointersListByType( gPoint.type );
+ cachedGPoint = pointsList.getById( gPoint.id );
+ if ( !cachedGPoint || !cachedGPoint.captured ) {
+ return;
}
+ // Can throw InvalidPointerId
+ // (should never happen, but it does on Firefox 79 touch so we won't log a warning)
+ try {
+ tracker.element.releasePointerCapture( gPoint.id );
+ //$.console.log('element.releasePointerCapture() called');
+ } catch ( e ) {
+ //$.console.warn('releasePointerCapture() called on invalid pointer ID');
+ }
+ } else {
+ tracker.element.releaseCapture();
+ //$.console.log('element.releaseCapture() called');
+ }
+ } else {
+ // 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)
+ //$.console.log('Emulated mouse capture release');
+ eventParams = getCaptureEventParams( tracker, $.MouseTracker.havePointerEvents ? 'pointerevent' : gPoint.type );
+ // https://github.com/openseadragon/openseadragon/pull/790
+ if (isInIframe && canAccessEvents(window.top)) {
$.removeEvent(
- $.MouseTracker.captureElement,
- eventParams.moveName,
- eventParams.moveHandler,
- true
- );
- $.removeEvent(
- $.MouseTracker.captureElement,
+ window.top,
eventParams.upName,
eventParams.upHandler,
true
);
}
+ $.removeEvent(
+ $.MouseTracker.captureElement,
+ eventParams.moveName,
+ eventParams.moveHandler,
+ true
+ );
+ $.removeEvent(
+ $.MouseTracker.captureElement,
+ eventParams.upName,
+ eventParams.upHandler,
+ true
+ );
}
+
+ updatePointerCaptured( tracker, gPoint, false );
+ }
+
+
+ /**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ * @private
+ * @inner
+ */
+ function getPointerId( event ) {
+ return ( $.MouseTracker.havePointerEvents ) ? event.pointerId : $.MouseTracker.mousePointerId;
}
/**
* Gets a W3C Pointer Events model compatible pointer type string from a DOM pointer event.
* IE10 used a long integer value, but the W3C specification (and IE11+) use a string "mouse", "touch", "pen", etc.
+ *
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
* @private
* @inner
*/
function getPointerType( event ) {
- var pointerTypeStr;
- if ( $.MouseTracker.unprefixedPointerEvents ) {
- pointerTypeStr = event.pointerType;
+ if ( $.MouseTracker.havePointerEvents ) {
+ // Note: IE pointer events bug - sends invalid pointerType on lostpointercapture events
+ // and possibly other events. We rely on sane, valid property values in DOM events, so for
+ // IE, when the pointerType is missing, we'll default to 'mouse'...should be right most of the time
+ return event.pointerType || (( $.Browser.vendor === $.BROWSERS.IE ) ? 'mouse' : '');
} else {
- // IE10
- // MSPOINTER_TYPE_TOUCH: 0x00000002
- // MSPOINTER_TYPE_PEN: 0x00000003
- // MSPOINTER_TYPE_MOUSE: 0x00000004
- switch( event.pointerType )
- {
- case 0x00000002:
- pointerTypeStr = 'touch';
- break;
- case 0x00000003:
- pointerTypeStr = 'pen';
- break;
- case 0x00000004:
- pointerTypeStr = 'mouse';
- break;
- default:
- pointerTypeStr = '';
- }
+ return 'mouse';
}
- return pointerTypeStr;
+ }
+
+
+ /**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ * @private
+ * @inner
+ */
+ function getIsPrimary( event ) {
+ return ( $.MouseTracker.havePointerEvents ) ? event.isPrimary : true;
}
@@ -1579,9 +1762,22 @@
* @inner
*/
function onClick( tracker, event ) {
- if ( tracker.clickHandler ) {
+ //$.console.log('onClick ' + (tracker.userData ? tracker.userData.toString() : ''));
+
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'click',
+ pointerType: 'mouse',
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
$.cancelEvent( event );
}
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
}
@@ -1590,9 +1786,22 @@
* @inner
*/
function onDblClick( tracker, event ) {
- if ( tracker.dblClickHandler ) {
+ //$.console.log('onDblClick ' + (tracker.userData ? tracker.userData.toString() : ''));
+
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'dblclick',
+ pointerType: 'mouse',
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
$.cancelEvent( event );
}
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
}
@@ -1604,7 +1813,6 @@
//$.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,
@@ -1633,7 +1841,6 @@
//$.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,
@@ -1662,7 +1869,6 @@
//$.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,
@@ -1691,7 +1897,6 @@
//console.log( "focus %s", event );
var propagate;
if ( tracker.focusHandler ) {
- event = $.getEvent( event );
propagate = tracker.focusHandler(
{
eventSource: tracker,
@@ -1715,7 +1920,6 @@
//console.log( "blur %s", event );
var propagate;
if ( tracker.blurHandler ) {
- event = $.getEvent( event );
propagate = tracker.blurHandler(
{
eventSource: tracker,
@@ -1731,6 +1935,42 @@
}
+ /**
+ * @private
+ * @inner
+ */
+ function onContextMenu( tracker, event ) {
+ //$.console.log('contextmenu ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
+
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'contextmenu',
+ pointerType: 'mouse',
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ // ContextMenu
+ if ( tracker.contextMenuHandler && !eventInfo.preventGesture && !eventInfo.defaultPrevented ) {
+ tracker.contextMenuHandler(
+ {
+ eventSource: tracker,
+ position: getPointRelativeToAbsolute( getMouseAbsolute( event ), tracker.element ),
+ originalEvent: eventInfo.originalEvent,
+ userData: tracker.userData
+ }
+ );
+ }
+
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( event );
+ }
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
+ }
+
+
/**
* Handler for 'wheel' events
*
@@ -1749,8 +1989,6 @@
* @inner
*/
function onMouseWheel( tracker, event ) {
- event = $.getEvent( event );
-
// Simulate a 'wheel' event
var simulatedEvent = {
target: event.target || event.srcElement,
@@ -1785,7 +2023,7 @@
*/
function handleWheelEvent( tracker, event, originalEvent ) {
var nDelta = 0,
- propagate;
+ eventInfo;
// The nDelta variable is gated to provide smooth z-index scrolling
// since the mouse wheel allows for substantial deltas meant for rapid
@@ -1794,8 +2032,18 @@
// TODO: Deltas in pixel mode should be accumulated then a scroll value computed after $.DEFAULT_SETTINGS.pixelsPerWheelLine threshold reached
nDelta = event.deltaY < 0 ? 1 : -1;
- if ( tracker.scrollHandler ) {
- propagate = tracker.scrollHandler(
+ eventInfo = {
+ originalEvent: event,
+ eventType: 'wheel',
+ pointerType: 'mouse',
+ isEmulated: event !== originalEvent
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ if ( tracker.scrollHandler && !eventInfo.preventGesture && !eventInfo.defaultPrevented ) {
+ eventInfo.preventDefault = true;
+
+ tracker.scrollHandler(
{
eventSource: tracker,
pointerType: 'mouse',
@@ -1808,283 +2056,42 @@
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( originalEvent );
- }
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function isParentChild( parent, child )
- {
- if ( parent === child ) {
- return false;
- }
- while ( child && child !== parent ) {
- child = child.parentNode;
- }
- return child === parent;
- }
-
-
- /**
- * Only used on IE 8
- *
- * @private
- * @inner
- */
- function onMouseEnter( tracker, event ) {
- event = $.getEvent( event );
-
- handleMouseEnter( tracker, event );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseOver( tracker, event ) {
- event = $.getEvent( event );
-
- if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {
- return;
}
- handleMouseEnter( tracker, event );
- }
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( originalEvent );
+ }
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( originalEvent );
+ }
+}
/**
+ * TODO Never actually seen this event fired, and documentation is tough to find
* @private
* @inner
*/
- function handleMouseEnter( tracker, event ) {
+ function onLoseCapture( tracker, event ) {
+ //$.console.log('losecapture ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
+
var gPoint = {
id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
+ type: 'mouse'
};
- updatePointersEnter( tracker, event, [ gPoint ] );
- }
-
-
- /**
- * Only used on IE 8
- *
- * @private
- * @inner
- */
- function onMouseLeave( tracker, event ) {
- event = $.getEvent( event );
-
- handleMouseExit( tracker, event );
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseOut( tracker, event ) {
- event = $.getEvent( event );
-
- if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {
- return;
- }
-
- handleMouseExit( tracker, event );
- }
-
-
- /**
- * @private
- * @inner
- */
- function handleMouseExit( tracker, event ) {
- var gPoint = {
- id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'lostpointercapture',
+ pointerType: 'mouse',
+ isEmulated: false
};
+ preProcessEvent( tracker, eventInfo );
- updatePointersExit( tracker, event, [ gPoint ] );
- }
+ updatePointerCaptured( tracker, gPoint, false );
-
- /**
- * Returns a W3C DOM level 3 standard button value given an event.button property:
- * -1 == none, 0 == primary/left, 1 == middle, 2 == secondary/right, 3 == X1/back, 4 == X2/forward, 5 == eraser (pen)
- * @private
- * @inner
- */
- function getStandardizedButton( button ) {
- if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
- // On IE 8, 0 == none, 1 == left, 2 == right, 3 == left and right, 4 == middle, 5 == left and middle, 6 == right and middle, 7 == all three
- // TODO: Support chorded (multiple) button presses on IE 8?
- if ( button === 1 ) {
- return 0;
- } else if ( button === 2 ) {
- return 2;
- } else if ( button === 4 ) {
- return 1;
- } else {
- return -1;
- }
- } else {
- return button;
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseDown( tracker, event ) {
- var gPoint;
-
- event = $.getEvent( event );
-
- gPoint = {
- id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {
+ if ( eventInfo.stopPropagation ) {
$.stopEvent( event );
- capturePointer( tracker, 'mouse' );
- }
-
- if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler ) {
- $.cancelEvent( event );
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseUp( tracker, event ) {
- handleMouseUp( tracker, event );
- }
-
- /**
- * This handler is attached to the window object (on the capture phase) to emulate mouse capture.
- * onMouseUp is still attached to the tracked element, so stop propagation to avoid processing twice.
- *
- * @private
- * @inner
- */
- function onMouseUpCaptured( tracker, event ) {
- handleMouseUp( tracker, event );
- $.stopEvent( event );
- }
-
-
- /**
- * @private
- * @inner
- */
- function handleMouseUp( tracker, event ) {
- var gPoint;
-
- event = $.getEvent( event );
-
- gPoint = {
- id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {
- releasePointer( tracker, 'mouse' );
- }
- }
-
-
- /**
- * @private
- * @inner
- */
- function onMouseMove( tracker, event ) {
- handleMouseMove( tracker, event );
- }
-
-
- /**
- * This handler is attached to the window object (on the capture phase) to emulate mouse capture.
- * onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice.
- *
- * @private
- * @inner
- */
- function onMouseMoveCaptured( tracker, event ) {
- handleMouseMove( tracker, event );
- $.stopEvent( event );
- }
-
-
- /**
- * @private
- * @inner
- */
- function handleMouseMove( tracker, event ) {
- var gPoint;
-
- event = $.getEvent( event );
-
- gPoint = {
- id: $.MouseTracker.mousePointerId,
- type: 'mouse',
- isPrimary: true,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- updatePointersMove( tracker, event, [ gPoint ] );
- }
-
-
- /**
- * @private
- * @inner
- */
- function abortContacts( tracker, event, pointsList ) {
- var i,
- gPointCount = pointsList.getLength(),
- abortGPoints = [];
-
- // Check contact count for hoverable pointer types before aborting
- if (pointsList.type === 'touch' || pointsList.contacts > 0) {
- for ( i = 0; i < gPointCount; i++ ) {
- abortGPoints.push( pointsList.getByIndex( i ) );
- }
-
- if ( abortGPoints.length > 0 ) {
- // simulate touchend/mouseup
- updatePointersUp( tracker, event, abortGPoints, 0 ); // 0 means primary button press/release or touch contact
- // release pointer capture
- pointsList.captureCount = 1;
- releasePointer( tracker, pointsList.type );
- // simulate touchleave/mouseout
- updatePointersExit( tracker, event, abortGPoints );
- }
}
}
@@ -2096,55 +2103,50 @@
function onTouchStart( tracker, event ) {
var time,
i,
- j,
touchCount = event.changedTouches.length,
- gPoints = [],
- parentGPoints,
+ gPoint,
pointsList = tracker.getActivePointersListByType( 'touch' );
time = $.now();
+ //$.console.log('touchstart ' + (tracker.userData ? tracker.userData.toString() : ''));
+
if ( pointsList.getLength() > event.touches.length - touchCount ) {
- $.console.warn('Tracked touch contact count doesn\'t match event.touches.length. Removing all tracked touch pointers.');
- abortContacts( tracker, event, pointsList );
+ $.console.warn('Tracked touch contact count doesn\'t match event.touches.length');
}
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointerdown',
+ pointerType: 'touch',
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
+ gPoint = {
id: event.changedTouches[ i ].identifier,
type: 'touch',
- // isPrimary not set - let the updatePointers functions determine it
+ // Simulate isPrimary
+ isPrimary: pointsList.getLength() === 0,
currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
currentTime: time
- } );
+ };
+
+ // simulate touchenter on our tracked element
+ updatePointerEnter( tracker, eventInfo, gPoint );
+
+ updatePointerCaptured( tracker, gPoint, true );
+
+ updatePointerDown( tracker, eventInfo, gPoint, 0 );
}
- // 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 ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( event );
}
-
- if ( updatePointersDown( tracker, event, gPoints, 0 ) ) { // 0 means primary button press/release or touch contact
+ if ( eventInfo.stopPropagation ) {
$.stopEvent( event );
- capturePointer( tracker, 'touch', touchCount );
}
-
- $.cancelEvent( event );
}
@@ -2153,72 +2155,45 @@
* @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 = [],
- parentGPoints;
+ gPoint;
time = $.now();
+ //$.console.log('touchend ' + (tracker.userData ? tracker.userData.toString() : ''));
+
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointerup',
+ pointerType: 'touch',
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
+ gPoint = {
id: event.changedTouches[ i ].identifier,
type: 'touch',
- // isPrimary not set - let the updatePointers functions determine it
currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
currentTime: time
- } );
+ };
+
+ updatePointerUp( tracker, eventInfo, gPoint, 0 );
+
+ updatePointerCaptured( tracker, gPoint, false );
+
+ // simulate touchleave on our tracked element
+ updatePointerLeave( tracker, eventInfo, gPoint );
}
- if ( updatePointersUp( tracker, event, gPoints, 0 ) ) {
- releasePointer( tracker, 'touch', touchCount );
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( event );
}
-
- // 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 );
- }
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
}
-
- $.cancelEvent( event );
}
@@ -2227,45 +2202,38 @@
* @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,
+ var time,
+ i,
touchCount = event.changedTouches.length,
- gPoints = [];
+ gPoint;
+
+ time = $.now();
+
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointermove',
+ pointerType: 'touch',
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
for ( i = 0; i < touchCount; i++ ) {
- gPoints.push( {
+ gPoint = {
id: event.changedTouches[ i ].identifier,
type: 'touch',
- // isPrimary not set - let the updatePointers functions determine it
currentPos: getMouseAbsolute( event.changedTouches[ i ] ),
- currentTime: $.now()
- } );
+ currentTime: time
+ };
+
+ updatePointerMove( tracker, eventInfo, gPoint );
}
- updatePointersMove( tracker, event, gPoints );
-
- $.cancelEvent( event );
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( event );
+ }
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
}
@@ -2274,9 +2242,33 @@
* @inner
*/
function onTouchCancel( tracker, event ) {
- var pointsList = tracker.getActivePointersListByType('touch');
+ var touchCount = event.changedTouches.length,
+ i,
+ gPoint;
- abortContacts( tracker, event, pointsList );
+ //$.console.log('touchcancel ' + (tracker.userData ? tracker.userData.toString() : ''));
+
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointercancel',
+ pointerType: 'touch',
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ for ( i = 0; i < touchCount; i++ ) {
+ gPoint = {
+ id: event.changedTouches[ i ].identifier,
+ type: 'touch'
+ };
+
+ //TODO need to only do this if our element is target?
+ updatePointerCancel( tracker, eventInfo, gPoint );
+ }
+
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
}
@@ -2285,8 +2277,9 @@
* @inner
*/
function onGestureStart( tracker, event ) {
- event.stopPropagation();
- event.preventDefault();
+ if ( !$.eventIsCanceled( event ) ) {
+ event.preventDefault();
+ }
return false;
}
@@ -2296,8 +2289,9 @@
* @inner
*/
function onGestureChange( tracker, event ) {
- event.stopPropagation();
- event.preventDefault();
+ if ( !$.eventIsCanceled( event ) ) {
+ event.preventDefault();
+ }
return false;
}
@@ -2306,22 +2300,28 @@
* @private
* @inner
*/
- function onPointerOver( tracker, event ) {
- var gPoint;
+ function onGotPointerCapture( tracker, event ) {
+ //$.console.log('gotpointercapture ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
- if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {
- return;
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'gotpointercapture',
+ pointerType: getPointerType( event ),
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ if ( event.target === tracker.element ) {
+ //$.console.log('gotpointercapture ' + (tracker.userData ? tracker.userData.toString() : ''));
+ updatePointerCaptured( tracker, {
+ id: event.pointerId,
+ type: getPointerType( event )
+ }, true );
}
- gPoint = {
- id: event.pointerId,
- type: getPointerType( event ),
- isPrimary: event.isPrimary,
- currentPos: getMouseAbsolute( event ),
- currentTime: $.now()
- };
-
- updatePointersEnter( tracker, event, [ gPoint ] );
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
}
@@ -2329,52 +2329,233 @@
* @private
* @inner
*/
+ function onLostPointerCapture( tracker, event ) {
+ //$.console.log('lostpointercapture ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
+
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'lostpointercapture',
+ pointerType: getPointerType( event ),
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ if ( event.target === tracker.element ) {
+ //$.console.log('lostpointercapture ' + (tracker.userData ? tracker.userData.toString() : ''));
+ updatePointerCaptured( tracker, {
+ id: event.pointerId,
+ type: getPointerType( event )
+ }, false );
+ }
+
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
+ }
+
+
+ /**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
+ * @private
+ * @inner
+ */
+ function onPointerEnter( tracker, event ) {
+ //$.console.log('pointerenter ' + (tracker.userData ? tracker.userData.toString() : ''));
+
+ var gPoint = {
+ id: getPointerId( event ),
+ type: getPointerType( event ),
+ isPrimary: getIsPrimary( event ),
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ // pointerenter doesn't bubble and is not cancelable, but we call
+ // preProcessEvent() so it's dispatched to preProcessEventHandler
+ // if necessary
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointerenter',
+ pointerType: gPoint.type,
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ updatePointerEnter( tracker, eventInfo, gPoint );
+ }
+
+
+ /**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
+ * @private
+ * @inner
+ */
+ function onPointerLeave( tracker, event ) {
+ //$.console.log('pointerleave ' + (tracker.userData ? tracker.userData.toString() : ''));
+
+ var gPoint = {
+ id: getPointerId( event ),
+ type: getPointerType( event ),
+ isPrimary: getIsPrimary( event ),
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ // pointerleave doesn't bubble and is not cancelable, but we call
+ // preProcessEvent() so it's dispatched to preProcessEventHandler
+ // if necessary
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointerleave',
+ pointerType: gPoint.type,
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ updatePointerLeave( tracker, eventInfo, gPoint );
+ }
+
+
+ /**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
+ * @private
+ * @inner
+ */
+ function onPointerOver( tracker, event ) {
+ //$.console.log('pointerover ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
+
+ var gPoint = {
+ id: getPointerId( event ),
+ type: getPointerType( event ),
+ isPrimary: getIsPrimary( event ),
+ currentPos: getMouseAbsolute( event ),
+ currentTime: $.now()
+ };
+
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointerover',
+ pointerType: gPoint.type,
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ updatePointerOver( tracker, eventInfo, gPoint );
+
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( event );
+ }
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
+ }
+
+
+ /**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
+ * @private
+ * @inner
+ */
function onPointerOut( tracker, event ) {
- var gPoint;
+ //$.console.log('pointerout ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
- if ( event.currentTarget === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {
- return;
- }
-
- gPoint = {
- id: event.pointerId,
+ var gPoint = {
+ id: getPointerId( event ),
type: getPointerType( event ),
- isPrimary: event.isPrimary,
+ isPrimary: getIsPrimary( event ),
currentPos: getMouseAbsolute( event ),
currentTime: $.now()
};
- updatePointersExit( tracker, event, [ gPoint ] );
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointerout',
+ pointerType: gPoint.type,
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ updatePointerOut( tracker, eventInfo, gPoint );
+
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( event );
+ }
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
}
/**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
* @private
* @inner
*/
function onPointerDown( tracker, event ) {
- var gPoint;
+ //$.console.log('onPointerDown ' + (tracker.userData ? tracker.userData.toString() : ''));
+ // $.console.log('onPointerDown ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + event.target.tagName);
- gPoint = {
- id: event.pointerId,
+ // Most browsers implicitly capture touch pointer events
+ // Note no IE versions have element.hasPointerCapture() so no implicit
+ // pointer capture possible
+ var implicitlyCaptured = ($.MouseTracker.havePointerEvents &&
+ tracker.element.hasPointerCapture &&
+ $.Browser.vendor !== $.BROWSERS.IE) ?
+ tracker.element.hasPointerCapture(event.pointerId) : false;
+ // if (implicitlyCaptured) {
+ // $.console.log('pointerdown implicitlyCaptured ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
+ // } else {
+ // $.console.log('pointerdown not implicitlyCaptured ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
+ // }
+
+ var gPoint = {
+ id: getPointerId( event ),
type: getPointerType( event ),
- isPrimary: event.isPrimary,
+ isPrimary: getIsPrimary( event ),
currentPos: getMouseAbsolute( event ),
currentTime: $.now()
};
- if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) {
- $.stopEvent( event );
- capturePointer( tracker, gPoint.type );
- }
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointerdown',
+ pointerType: gPoint.type,
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
- if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
+ updatePointerDown( tracker, eventInfo, gPoint, event.button );
+
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
$.cancelEvent( event );
}
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
+ if ( eventInfo.shouldCapture && !implicitlyCaptured ) {
+ //$.console.log('pointerdown calling capturePointer() ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
+ capturePointer( tracker, gPoint );
+ } else if ( !eventInfo.shouldCapture && implicitlyCaptured ) {
+ //$.console.log('pointerdown calling releasePointer() ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : ''));
+ releasePointer( tracker, gPoint ); //TODO should we do this? Investigate when implementing bubble handling
+ }
}
/**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
* @private
* @inner
*/
@@ -2384,6 +2565,9 @@
/**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
* This handler is attached to the window object (on the capture phase) to emulate mouse capture.
* onPointerUp is still attached to the tracked element, so stop propagation to avoid processing twice.
*
@@ -2400,27 +2584,56 @@
/**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
* @private
* @inner
*/
function handlePointerUp( tracker, event ) {
var gPoint;
+ //$.console.log('onPointerUp ' + (tracker.userData ? tracker.userData.toString() : ''));
+
gPoint = {
- id: event.pointerId,
+ id: getPointerId( event ),
type: getPointerType( event ),
- isPrimary: event.isPrimary,
+ isPrimary: getIsPrimary( event ),
currentPos: getMouseAbsolute( event ),
currentTime: $.now()
};
- if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) {
- releasePointer( tracker, gPoint.type );
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointerup',
+ pointerType: gPoint.type,
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ updatePointerUp( tracker, eventInfo, gPoint, event.button );
+
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( event );
+ }
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
+
+ // Per spec, pointerup events are supposed to release capture. Not all browser
+ // versions have adhered to the spec, and there's no harm in releasing
+ // explicitly
+ if ( eventInfo.shouldReleaseCapture && event.target === tracker.element ) {
+ //$.stopEvent( event );
+ releasePointer( tracker, gPoint );
}
}
/**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
* @private
* @inner
*/
@@ -2430,6 +2643,9 @@
/**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
* This handler is attached to the window object (on the capture phase) to emulate mouse capture.
* onPointerMove is still attached to the tracked element, so stop propagation to avoid processing twice.
*
@@ -2446,22 +2662,39 @@
/**
+ * Note: Called for both pointer events and legacy mouse events
+ * ($.MouseTracker.havePointerEvents determines which)
+ *
* @private
* @inner
*/
function handlePointerMove( tracker, event ) {
// Pointer changed coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)
- var gPoint;
- gPoint = {
- id: event.pointerId,
+ var gPoint = {
+ id: getPointerId( event ),
type: getPointerType( event ),
- isPrimary: event.isPrimary,
+ isPrimary: getIsPrimary( event ),
currentPos: getMouseAbsolute( event ),
currentTime: $.now()
};
- updatePointersMove( tracker, event, [ gPoint ] );
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointermove',
+ pointerType: gPoint.type,
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ updatePointerMove( tracker, eventInfo, gPoint );
+
+ if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) {
+ $.cancelEvent( event );
+ }
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
}
@@ -2470,14 +2703,27 @@
* @inner
*/
function onPointerCancel( tracker, event ) {
- var gPoint;
+ //$.console.log('pointercancel ' + (tracker.userData ? tracker.userData.toString() : ''));
- gPoint = {
+ var gPoint = {
id: event.pointerId,
type: getPointerType( event )
};
- updatePointersCancel( tracker, event, [ gPoint ] );
+ var eventInfo = {
+ originalEvent: event,
+ eventType: 'pointercancel',
+ pointerType: gPoint.type,
+ isEmulated: false
+ };
+ preProcessEvent( tracker, eventInfo );
+
+ //TODO need to only do this if our element is target?
+ updatePointerCancel( tracker, eventInfo, gPoint );
+
+ if ( eventInfo.stopPropagation ) {
+ $.stopEvent( event );
+ }
}
@@ -2496,16 +2742,6 @@
* @returns {Number} Number of gesture points in pointsList.
*/
function startTrackingPointer( pointsList, gPoint ) {
-
- // If isPrimary is not known for the pointer then set it according to our rules:
- // true if the first pointer in the gesture, otherwise false
- if ( !Object.prototype.hasOwnProperty.call( gPoint, 'isPrimary' ) ) {
- if ( pointsList.getLength() === 0 ) {
- gPoint.isPrimary = true;
- } else {
- gPoint.isPrimary = false;
- }
- }
gPoint.speed = 0;
gPoint.direction = 0;
gPoint.contactPos = gPoint.currentPos;
@@ -2521,29 +2757,26 @@
* @function
* @private
* @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
* @param {OpenSeadragon.MouseTracker.GesturePointList} pointsList
* The GesturePointList to stop tracking the pointer on.
* @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
* Gesture point to stop tracking.
* @returns {Number} Number of gesture points in pointsList.
*/
- function stopTrackingPointer( pointsList, gPoint ) {
- var listLength,
- primaryPoint;
+ function stopTrackingPointer( tracker, pointsList, gPoint ) {
+ var listLength;
- if ( pointsList.getById( gPoint.id ) ) {
- listLength = pointsList.removeById( gPoint.id );
+ var trackedGPoint = pointsList.getById( gPoint.id );
- // If isPrimary is not known for the pointer and we just removed the primary pointer from the list then we need to set another pointer as primary
- if ( !Object.prototype.hasOwnProperty.call( gPoint, 'isPrimary' ) ) {
- primaryPoint = pointsList.getPrimary();
- if ( !primaryPoint ) {
- primaryPoint = pointsList.getByIndex( 0 );
- if ( primaryPoint ) {
- primaryPoint.isPrimary = true;
- }
- }
+ if ( trackedGPoint ) {
+ if ( trackedGPoint.captured ) {
+ releasePointer( tracker, trackedGPoint );
+ pointsList.removeContact();
}
+
+ listLength = pointsList.removeById( gPoint.id );
} else {
listLength = pointsList.getLength();
}
@@ -2553,129 +2786,273 @@
/**
+ * @function
+ * @private
+ * @inner
+ */
+ function getEventProcessDefaults( tracker, eventInfo ) {
+ switch ( eventInfo.eventType ) {
+ case 'pointermove':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = true;
+ eventInfo.preventDefault = false;
+ eventInfo.preventGesture = !tracker.hasGestureHandlers;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'pointerover':
+ case 'pointerout':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = true;
+ eventInfo.preventDefault = false;
+ eventInfo.preventGesture = false;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'pointerdown':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = true;
+ eventInfo.preventDefault = false;//tracker.hasGestureHandlers;
+ eventInfo.preventGesture = !tracker.hasGestureHandlers;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'pointerup':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = true;
+ eventInfo.preventDefault = false;
+ eventInfo.preventGesture = !tracker.hasGestureHandlers;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'wheel':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = true;
+ eventInfo.preventDefault = false;//tracker.hasScrollHandler;
+ eventInfo.preventGesture = !tracker.hasScrollHandler;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'gotpointercapture':
+ case 'lostpointercapture':
+ case 'pointercancel':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = false;
+ eventInfo.preventDefault = false;
+ eventInfo.preventGesture = false;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'click':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = true;
+ eventInfo.preventDefault = !!tracker.clickHandler;
+ eventInfo.preventGesture = false;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'dblclick':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = true;
+ eventInfo.preventDefault = !!tracker.dblClickHandler;
+ eventInfo.preventGesture = false;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'contextmenu':
+ eventInfo.isStopable = true;
+ eventInfo.isCancelable = true;
+ eventInfo.preventDefault = false;//tracker.hasContextMenuHandler;
+ eventInfo.preventGesture = true;//!tracker.hasContextMenuHandler;
+ eventInfo.stopPropagation = false;
+ break;
+ case 'pointerenter':
+ case 'pointerleave':
+ default:
+ eventInfo.isStopable = false;
+ eventInfo.isCancelable = false;
+ eventInfo.preventDefault = false;
+ eventInfo.preventGesture = false;
+ eventInfo.stopPropagation = false;
+ break;
+ }
+ }
+
+
+ /**
+ * Sets up for and calls preProcessEventHandler. Call with the following parameters -
+ * this function will fill in the rest of the preProcessEventHandler event object
+ * properties
+ *
* @function
* @private
* @inner
* @param {OpenSeadragon.MouseTracker} tracker
* A reference to the MouseTracker instance.
- * @param {Object} event
- * A reference to the originating DOM event.
- * @param {Array.} gPoints
- * Gesture points associated with the event.
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * @param {Object} eventInfo.originalEvent
+ * @param {String} eventInfo.eventType
+ * @param {String} eventInfo.pointerType
+ * @param {Boolean} eventInfo.isEmulated
*/
- function updatePointersEnter( tracker, event, gPoints ) {
- var pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
- i,
- gPointCount = gPoints.length,
- curGPoint,
+ function preProcessEvent( tracker, eventInfo ) {
+ eventInfo.eventSource = tracker;
+ eventInfo.eventPhase = eventInfo.originalEvent ?
+ ((typeof eventInfo.originalEvent.eventPhase !== 'undefined') ?
+ eventInfo.originalEvent.eventPhase : 0) : 0;
+ eventInfo.defaultPrevented = $.eventIsCanceled( eventInfo.originalEvent );
+ eventInfo.shouldCapture = false;
+ eventInfo.shouldReleaseCapture = false;
+ eventInfo.userData = tracker.userData;
+
+ getEventProcessDefaults( tracker, eventInfo );
+
+ if ( tracker.preProcessEventHandler ) {
+ tracker.preProcessEventHandler( eventInfo );
+ }
+ }
+
+
+ /**
+ * Sets or resets the captured property on the tracked pointer matching the passed gPoint's id/type
+ *
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {Object} gPoint
+ * An object with id and type properties describing the pointer to update.
+ * @param {Boolean} isCaptured
+ * Value to set the captured property to.
+ */
+ function updatePointerCaptured( tracker, gPoint, isCaptured ) {
+ var pointsList = tracker.getActivePointersListByType( gPoint.type );
+ var updateGPoint = pointsList.getById( gPoint.id );
+
+ if ( updateGPoint ) {
+ if ( isCaptured && !updateGPoint.captured ) {
+ updateGPoint.captured = true;
+ pointsList.captureCount++;
+ } else if ( !isCaptured && updateGPoint.captured ) {
+ updateGPoint.captured = false;
+ pointsList.captureCount--;
+ if ( pointsList.captureCount < 0 ) {
+ pointsList.captureCount = 0;
+ $.console.warn('updatePointerCaptured() - pointsList.captureCount went negative');
+ }
+ }
+ } else {
+ $.console.warn('updatePointerCaptured() called on untracked pointer');
+ }
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * Processing info for originating DOM event.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
+ * Gesture point associated with the event.
+ */
+ function updatePointerEnter( tracker, eventInfo, gPoint ) {
+ var pointsList = tracker.getActivePointersListByType( gPoint.type ),
+ updateGPoint;
+
+ updateGPoint = pointsList.getById( gPoint.id );
+
+ if ( updateGPoint ) {
+ // Already tracking the pointer...update it
+ updateGPoint.insideElement = true;
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = gPoint.currentPos;
+ updateGPoint.currentTime = gPoint.currentTime;
+
+ gPoint = updateGPoint;
+ } else {
+ // Initialize for tracking and add to the tracking list
+ gPoint.captured = false; // Handled by updatePointerCaptured()
+ gPoint.insideElementPressed = false;
+ gPoint.insideElement = true;
+ startTrackingPointer( pointsList, gPoint );
+ }
+
+ // Enter (doesn't bubble and not cancelable)
+ if ( tracker.enterHandler ) {
+ tracker.enterHandler(
+ {
+ eventSource: tracker,
+ pointerType: gPoint.type,
+ position: getPointRelativeToAbsolute( gPoint.currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ pointers: tracker.getActivePointerCount(),
+ insideElementPressed: gPoint.insideElementPressed,
+ buttonDownAny: pointsList.buttons !== 0,
+ isTouchEvent: gPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
+ userData: tracker.userData
+ }
+ );
+ }
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * Processing info for originating DOM event.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
+ * Gesture point associated with the event.
+ */
+ function updatePointerLeave( tracker, eventInfo, gPoint ) {
+ var pointsList = tracker.getActivePointersListByType(gPoint.type),
updateGPoint,
- propagate;
+ dispatchEventObj;
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
- updateGPoint = pointsList.getById( curGPoint.id );
+ updateGPoint = pointsList.getById( gPoint.id );
- if ( updateGPoint ) {
- // Already tracking the pointer...update it
- updateGPoint.insideElement = true;
+ if ( updateGPoint ) {
+ // Already tracking the pointer. If captured then update it, else stop tracking it
+ if ( updateGPoint.captured ) {
+ updateGPoint.insideElement = false;
updateGPoint.lastPos = updateGPoint.currentPos;
updateGPoint.lastTime = updateGPoint.currentTime;
- updateGPoint.currentPos = curGPoint.currentPos;
- updateGPoint.currentTime = curGPoint.currentTime;
-
- curGPoint = updateGPoint;
+ updateGPoint.currentPos = gPoint.currentPos;
+ updateGPoint.currentTime = gPoint.currentTime;
} else {
- // Initialize for tracking and add to the tracking list
- curGPoint.captured = false;
- curGPoint.insideElementPressed = false;
- curGPoint.insideElement = true;
- startTrackingPointer( pointsList, curGPoint );
+ stopTrackingPointer( tracker, pointsList, updateGPoint );
}
- // Enter
- if ( tracker.enterHandler ) {
- propagate = tracker.enterHandler(
- {
- eventSource: tracker,
- 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',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
+ gPoint = updateGPoint;
+ } else {
+ gPoint.captured = false; // Handled by updatePointerCaptured()
+ gPoint.insideElementPressed = false;
}
- }
+ // Leave (doesn't bubble and not cancelable)
+ // Note: exitHandler is deprecated (v2.5.0), replaced by leaveHandler
+ if ( tracker.leaveHandler || tracker.exitHandler ) {
+ dispatchEventObj = {
+ eventSource: tracker,
+ pointerType: gPoint.type,
+ // GitHub PR: https://github.com/openseadragon/openseadragon/pull/1754 (gPoint.currentPos && )
+ position: gPoint.currentPos && getPointRelativeToAbsolute( gPoint.currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ pointers: tracker.getActivePointerCount(),
+ insideElementPressed: gPoint.insideElementPressed,
+ buttonDownAny: pointsList.buttons !== 0,
+ isTouchEvent: gPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
+ userData: tracker.userData
+ };
- /**
- * @function
- * @private
- * @inner
- * @param {OpenSeadragon.MouseTracker} tracker
- * A reference to the MouseTracker instance.
- * @param {Object} event
- * A reference to the originating DOM event.
- * @param {Array.} gPoints
- * Gesture points associated with the event.
- */
- function updatePointersExit( tracker, event, gPoints ) {
- var pointsList = tracker.getActivePointersListByType(gPoints[0].type),
- i,
- gPointCount = gPoints.length,
- curGPoint,
- updateGPoint,
- propagate;
-
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
- updateGPoint = pointsList.getById( curGPoint.id );
-
- if ( updateGPoint ) {
- // Already tracking the pointer. If captured then update it, else stop tracking it
- if ( updateGPoint.captured ) {
- updateGPoint.insideElement = false;
- updateGPoint.lastPos = updateGPoint.currentPos;
- updateGPoint.lastTime = updateGPoint.currentTime;
- updateGPoint.currentPos = curGPoint.currentPos;
- updateGPoint.currentTime = curGPoint.currentTime;
- } else {
- stopTrackingPointer( pointsList, updateGPoint );
- }
-
- curGPoint = updateGPoint;
+ if ( tracker.leaveHandler ) {
+ tracker.leaveHandler( dispatchEventObj );
}
-
- // Exit
+ // Deprecated
if ( tracker.exitHandler ) {
- propagate = tracker.exitHandler(
- {
- eventSource: tracker,
- pointerType: curGPoint.type,
- position: curGPoint.currentPos && getPointRelativeToAbsolute( curGPoint.currentPos, tracker.element ),
- buttons: pointsList.buttons,
- pointers: tracker.getActivePointerCount(),
- insideElementPressed: updateGPoint ? updateGPoint.insideElementPressed : false,
- buttonDownAny: pointsList.buttons !== 0,
- isTouchEvent: curGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
-
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
+ tracker.exitHandler( dispatchEventObj );
}
}
}
@@ -2687,167 +3064,229 @@
* @inner
* @param {OpenSeadragon.MouseTracker} tracker
* A reference to the MouseTracker instance.
- * @param {Object} event
- * A reference to the originating DOM event.
- * @param {Array.} gPoints
- * Gesture points associated with the event.
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * Processing info for originating DOM event.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
+ * Gesture point associated with the event.
+ */
+ function updatePointerOver( tracker, eventInfo, gPoint ) {
+ var pointsList,
+ updateGPoint;
+
+ pointsList = tracker.getActivePointersListByType( gPoint.type );
+
+ updateGPoint = pointsList.getById( gPoint.id );
+
+ if ( updateGPoint ) {
+ gPoint = updateGPoint;
+ } else {
+ gPoint.captured = false;
+ gPoint.insideElementPressed = false;
+ //gPoint.insideElement = true; // Tracked by updatePointerEnter
+ }
+
+ if ( tracker.overHandler ) {
+ // Over
+ tracker.overHandler(
+ {
+ eventSource: tracker,
+ pointerType: gPoint.type,
+ position: getPointRelativeToAbsolute( gPoint.currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ pointers: tracker.getActivePointerCount(),
+ insideElementPressed: gPoint.insideElementPressed,
+ buttonDownAny: pointsList.buttons !== 0,
+ isTouchEvent: gPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ }
+ }
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * Processing info for originating DOM event.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
+ * Gesture point associated with the event.
+ */
+ function updatePointerOut( tracker, eventInfo, gPoint ) {
+ var pointsList,
+ updateGPoint;
+
+ pointsList = tracker.getActivePointersListByType(gPoint.type);
+
+ updateGPoint = pointsList.getById( gPoint.id );
+
+ if ( updateGPoint ) {
+ gPoint = updateGPoint;
+ } else {
+ gPoint.captured = false;
+ gPoint.insideElementPressed = false;
+ //gPoint.insideElement = true; // Tracked by updatePointerEnter
+ }
+
+ if ( tracker.outHandler ) {
+ // Out
+ tracker.outHandler( {
+ eventSource: tracker,
+ pointerType: gPoint.type,
+ position: gPoint.currentPos && getPointRelativeToAbsolute( gPoint.currentPos, tracker.element ),
+ buttons: pointsList.buttons,
+ pointers: tracker.getActivePointerCount(),
+ insideElementPressed: gPoint.insideElementPressed,
+ buttonDownAny: pointsList.buttons !== 0,
+ isTouchEvent: gPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ } );
+ }
+ }
+
+
+ /**
+ * @function
+ * @private
+ * @inner
+ * @param {OpenSeadragon.MouseTracker} tracker
+ * A reference to the MouseTracker instance.
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * Processing info for originating DOM event.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
+ * Gesture point associated with the event.
* @param {Number} buttonChanged
* 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.
- *
- * @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false.
*/
- function updatePointersDown( tracker, event, gPoints, buttonChanged ) {
+ function updatePointerDown( tracker, eventInfo, gPoint, buttonChanged ) {
var delegate = THIS[ tracker.hash ],
- propagate,
- pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
- i,
- gPointCount = gPoints.length,
- curGPoint,
+ pointsList = tracker.getActivePointersListByType( gPoint.type ),
updateGPoint;
- if ( typeof event.buttons !== 'undefined' ) {
- pointsList.buttons = event.buttons;
+ if ( typeof eventInfo.originalEvent.buttons !== 'undefined' ) {
+ pointsList.buttons = eventInfo.originalEvent.buttons;
} else {
- 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;
- }
+ 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;
}
}
- // Some pointers may steal control from another pointer without firing the appropriate release events
- // e.g. Touching a screen while click-dragging with certain mice.
- var otherPointsLists = tracker.getActivePointersListsExceptType(gPoints[ 0 ].type);
- for (i = 0; i < otherPointsLists.length; i++) {
- //If another pointer has contact, simulate the release
- abortContacts(tracker, event, otherPointsLists[i]); // No-op if no active pointer
- }
-
// Only capture and track primary button, pen, and touch contacts
if ( buttonChanged !== 0 ) {
+ eventInfo.shouldCapture = false;
+ eventInfo.shouldReleaseCapture = false;
+
// Aux Press
- if ( tracker.nonPrimaryPressHandler ) {
- propagate = tracker.nonPrimaryPressHandler(
+ if ( tracker.nonPrimaryPressHandler &&
+ !eventInfo.preventGesture &&
+ !eventInfo.defaultPrevented ) {
+ eventInfo.preventDefault = true;
+
+ tracker.nonPrimaryPressHandler(
{
eventSource: tracker,
- pointerType: gPoints[ 0 ].type,
- position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),
+ pointerType: gPoint.type,
+ position: getPointRelativeToAbsolute( gPoint.currentPos, tracker.element ),
button: buttonChanged,
buttons: pointsList.buttons,
- isTouchEvent: gPoints[ 0 ].type === 'touch',
- originalEvent: event,
+ isTouchEvent: gPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
}
- return false;
+ return;
}
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
- updateGPoint = pointsList.getById( curGPoint.id );
+ updateGPoint = pointsList.getById( gPoint.id );
- if ( updateGPoint ) {
- // Already tracking the pointer...update it
- updateGPoint.captured = true;
- updateGPoint.insideElementPressed = true;
- updateGPoint.insideElement = true;
- updateGPoint.contactPos = curGPoint.currentPos;
- updateGPoint.contactTime = curGPoint.currentTime;
- updateGPoint.lastPos = updateGPoint.currentPos;
- updateGPoint.lastTime = updateGPoint.currentTime;
- updateGPoint.currentPos = curGPoint.currentPos;
- updateGPoint.currentTime = curGPoint.currentTime;
+ if ( updateGPoint ) {
+ // Already tracking the pointer...update it
+ //updateGPoint.captured = true; // Handled by updatePointerCaptured()
+ updateGPoint.insideElementPressed = true;
+ updateGPoint.insideElement = true;
+ updateGPoint.contactPos = gPoint.currentPos;
+ updateGPoint.contactTime = gPoint.currentTime;
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = gPoint.currentPos;
+ updateGPoint.currentTime = gPoint.currentTime;
- curGPoint = updateGPoint;
- } else {
- // Initialize for tracking and add to the tracking list (no pointerover or pointermove event occurred before this)
- curGPoint.captured = true;
- curGPoint.insideElementPressed = true;
- curGPoint.insideElement = true;
- startTrackingPointer( pointsList, curGPoint );
- }
+ gPoint = updateGPoint;
+ } else {
+ // Initialize for tracking and add to the tracking list (no pointerover or pointermove event occurred before this)
+ gPoint.captured = false; // Handled by updatePointerCaptured()
+ gPoint.insideElementPressed = true;
+ gPoint.insideElement = true;
+ startTrackingPointer( pointsList, gPoint );
+ }
+
+ if ( !eventInfo.preventGesture && !eventInfo.defaultPrevented ) {
+ eventInfo.shouldCapture = true;
+ eventInfo.shouldReleaseCapture = false;
+ eventInfo.preventDefault = true;
pointsList.addContact();
//$.console.log('contacts++ ', pointsList.contacts);
if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
- $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, curGPoint );
+ $.MouseTracker.gesturePointVelocityTracker.addPoint( tracker, gPoint );
}
if ( pointsList.contacts === 1 ) {
// Press
- if ( tracker.pressHandler ) {
- propagate = tracker.pressHandler(
+ if ( tracker.pressHandler && !eventInfo.preventGesture ) {
+ tracker.pressHandler(
{
eventSource: tracker,
- pointerType: curGPoint.type,
- position: getPointRelativeToAbsolute( curGPoint.contactPos, tracker.element ),
+ pointerType: gPoint.type,
+ position: getPointRelativeToAbsolute( gPoint.contactPos, tracker.element ),
buttons: pointsList.buttons,
- isTouchEvent: curGPoint.type === 'touch',
- originalEvent: event,
+ isTouchEvent: gPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
}
} else if ( pointsList.contacts === 2 ) {
- if ( tracker.pinchHandler && curGPoint.type === 'touch' ) {
+ if ( tracker.pinchHandler && gPoint.type === 'touch' ) {
// Initialize for pinch
delegate.pinchGPoints = pointsList.asArray();
delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
}
}
+ } else {
+ eventInfo.shouldCapture = false;
+ eventInfo.shouldReleaseCapture = false;
}
-
- return true;
}
@@ -2857,262 +3296,126 @@
* @inner
* @param {OpenSeadragon.MouseTracker} tracker
* A reference to the MouseTracker instance.
- * @param {Object} event
- * A reference to the originating DOM event.
- * @param {Array.} gPoints
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * Processing info for originating DOM event.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
* Gesture points associated with the event.
* @param {Number} buttonChanged
* 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.
- *
- * @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false.
*/
- function updatePointersUp( tracker, event, gPoints, buttonChanged ) {
+ function updatePointerUp( tracker, eventInfo, gPoint, buttonChanged ) {
var delegate = THIS[ tracker.hash ],
- pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
- propagate,
+ pointsList = tracker.getActivePointersListByType( gPoint.type ),
releasePoint,
releaseTime,
- i,
- gPointCount = gPoints.length,
- curGPoint,
updateGPoint,
- releaseCapture = false,
wasCaptured = false,
quick;
- if ( typeof event.buttons !== 'undefined' ) {
- pointsList.buttons = event.buttons;
+ if ( typeof eventInfo.originalEvent.buttons !== 'undefined' ) {
+ pointsList.buttons = eventInfo.originalEvent.buttons;
} else {
- 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;
- }
+ 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;
}
}
+ eventInfo.shouldCapture = false;
+
// Only capture and track primary button, pen, and touch contacts
if ( buttonChanged !== 0 ) {
+ eventInfo.shouldReleaseCapture = false;
+
// Aux Release
- if ( tracker.nonPrimaryReleaseHandler ) {
- propagate = tracker.nonPrimaryReleaseHandler(
+ if ( tracker.nonPrimaryReleaseHandler &&
+ !eventInfo.preventGesture &&
+ !eventInfo.defaultPrevented ) {
+ eventInfo.preventDefault = true;
+
+ tracker.nonPrimaryReleaseHandler(
{
eventSource: tracker,
- pointerType: gPoints[ 0 ].type,
- position: getPointRelativeToAbsolute(gPoints[0].currentPos, tracker.element),
+ pointerType: gPoint.type,
+ position: getPointRelativeToAbsolute(gPoint.currentPos, tracker.element),
button: buttonChanged,
buttons: pointsList.buttons,
- isTouchEvent: gPoints[ 0 ].type === 'touch',
- originalEvent: event,
+ isTouchEvent: gPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
}
- // A primary mouse button may have been released while the non-primary button was down
- var otherPointsList = tracker.getActivePointersListByType("mouse");
- // Stop tracking the mouse; see https://github.com/openseadragon/openseadragon/pull/1223
- abortContacts(tracker, event, otherPointsList); // No-op if no active pointer
-
- return false;
+ return;
}
- // OS-specific gestures (e.g. swipe up with four fingers in iPadOS 13)
- if (typeof gPoints[ 0 ].currentPos === "undefined") {
- abortContacts(tracker, event, pointsList);
+ updateGPoint = pointsList.getById( gPoint.id );
- return false;
+ if ( updateGPoint ) {
+ // Update the pointer, stop tracking it if not still in this element
+ if ( updateGPoint.captured ) {
+ //updateGPoint.captured = false; // Handled by updatePointerCaptured()
+ wasCaptured = true;
+ }
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = gPoint.currentPos;
+ updateGPoint.currentTime = gPoint.currentTime;
+ if ( !updateGPoint.insideElement ) {
+ stopTrackingPointer( tracker, pointsList, updateGPoint );
+ }
+
+ releasePoint = updateGPoint.currentPos;
+ releaseTime = updateGPoint.currentTime;
+ } else {
+ // should never get here...we'll start to track pointer anyway
+ $.console.warn('updatePointerUp(): pointerup on untracked gPoint');
+ gPoint.captured = false; // Handled by updatePointerCaptured()
+ gPoint.insideElementPressed = false;
+ gPoint.insideElement = true;
+ startTrackingPointer( pointsList, gPoint );
+
+ updateGPoint = gPoint;
}
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
- updateGPoint = pointsList.getById( curGPoint.id );
- if ( updateGPoint ) {
- // Update the pointer, stop tracking it if not still in this element
- if ( updateGPoint.captured ) {
- updateGPoint.captured = false;
- releaseCapture = true;
- wasCaptured = true;
- }
- updateGPoint.lastPos = updateGPoint.currentPos;
- updateGPoint.lastTime = updateGPoint.currentTime;
- updateGPoint.currentPos = curGPoint.currentPos;
- updateGPoint.currentTime = curGPoint.currentTime;
- if ( !updateGPoint.insideElement ) {
- stopTrackingPointer( pointsList, updateGPoint );
+ if ( !eventInfo.preventGesture && !eventInfo.defaultPrevented ) {
+ if ( wasCaptured ) {
+ // Pointer was activated in our element but could have been removed in any element since events are captured to our element
+
+ eventInfo.shouldReleaseCapture = true;
+ eventInfo.preventDefault = true;
+
+ pointsList.removeContact();
+ //$.console.log('contacts-- ', pointsList.contacts);
+
+ if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
+ $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint );
}
- releasePoint = updateGPoint.currentPos;
- releaseTime = updateGPoint.currentTime;
+ if ( pointsList.contacts === 0 ) {
- if ( wasCaptured ) {
- // Pointer was activated in our element but could have been removed in any element since events are captured to our element
-
- pointsList.removeContact();
- //$.console.log('contacts-- ', pointsList.contacts);
-
- if ( tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
- $.MouseTracker.gesturePointVelocityTracker.removePoint( tracker, updateGPoint );
- }
-
- if ( pointsList.contacts === 0 ) {
-
- // Release (pressed in our element)
- if ( tracker.releaseHandler ) {
- propagate = tracker.releaseHandler(
- {
- eventSource: tracker,
- pointerType: updateGPoint.type,
- position: getPointRelativeToAbsolute( releasePoint, tracker.element ),
- buttons: pointsList.buttons,
- insideElementPressed: updateGPoint.insideElementPressed,
- insideElementReleased: updateGPoint.insideElement,
- isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
-
- // Drag End
- if ( tracker.dragEndHandler && !updateGPoint.currentPos.equals( updateGPoint.contactPos ) ) {
- propagate = tracker.dragEndHandler(
- {
- eventSource: tracker,
- pointerType: updateGPoint.type,
- position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
- speed: updateGPoint.speed,
- direction: updateGPoint.direction,
- shift: event.shiftKey,
- isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
-
- // Click / Double-Click
- if ( ( tracker.clickHandler || tracker.dblClickHandler ) && updateGPoint.insideElement ) {
- quick = releaseTime - updateGPoint.contactTime <= tracker.clickTimeThreshold &&
- updateGPoint.contactPos.distanceTo( releasePoint ) <= tracker.clickDistThreshold;
-
- // Click
- if ( tracker.clickHandler ) {
- propagate = tracker.clickHandler(
- {
- eventSource: tracker,
- pointerType: updateGPoint.type,
- position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
- quick: quick,
- shift: event.shiftKey,
- isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
-
- // Double-Click
- if ( tracker.dblClickHandler && quick ) {
- pointsList.clicks++;
- if ( pointsList.clicks === 1 ) {
- delegate.lastClickPos = releasePoint;
- /*jshint loopfunc:true*/
- delegate.dblClickTimeOut = setTimeout( function() {
- pointsList.clicks = 0;
- }, tracker.dblClickTimeThreshold );
- /*jshint loopfunc:false*/
- } else if ( pointsList.clicks === 2 ) {
- clearTimeout( delegate.dblClickTimeOut );
- pointsList.clicks = 0;
- if ( delegate.lastClickPos.distanceTo( releasePoint ) <= tracker.dblClickDistThreshold ) {
- propagate = tracker.dblClickHandler(
- {
- eventSource: tracker,
- pointerType: updateGPoint.type,
- position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
- shift: event.shiftKey,
- isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
- preventDefaultAction: false,
- userData: tracker.userData
- }
- );
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
- }
- delegate.lastClickPos = null;
- }
- }
- }
- } else if ( pointsList.contacts === 2 ) {
- if ( tracker.pinchHandler && updateGPoint.type === 'touch' ) {
- // Reset for pinch
- delegate.pinchGPoints = pointsList.asArray();
- delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
- delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
- }
- }
- } else {
- // Pointer was activated in another element but removed in our element
-
- // Release (pressed in another element)
+ // Release (pressed in our element)
if ( tracker.releaseHandler ) {
- propagate = tracker.releaseHandler(
+ tracker.releaseHandler(
{
eventSource: tracker,
pointerType: updateGPoint.type,
@@ -3121,20 +3424,117 @@
insideElementPressed: updateGPoint.insideElementPressed,
insideElementReleased: updateGPoint.insideElement,
isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
+ }
+
+ // Drag End
+ if ( tracker.dragEndHandler ) {
+ tracker.dragEndHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
+ speed: updateGPoint.speed,
+ direction: updateGPoint.direction,
+ shift: eventInfo.originalEvent.shiftKey,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ }
+
+ // Click / Double-Click
+ if ( ( tracker.clickHandler || tracker.dblClickHandler ) && updateGPoint.insideElement ) {
+ quick = releaseTime - updateGPoint.contactTime <= tracker.clickTimeThreshold &&
+ updateGPoint.contactPos.distanceTo( releasePoint ) <= tracker.clickDistThreshold;
+
+ // Click
+ if ( tracker.clickHandler ) {
+ tracker.clickHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
+ quick: quick,
+ shift: eventInfo.originalEvent.shiftKey,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ }
+
+ // Double-Click
+ if ( tracker.dblClickHandler && quick ) {
+ pointsList.clicks++;
+ if ( pointsList.clicks === 1 ) {
+ delegate.lastClickPos = releasePoint;
+ /*jshint loopfunc:true*/
+ delegate.dblClickTimeOut = setTimeout( function() {
+ pointsList.clicks = 0;
+ }, tracker.dblClickTimeThreshold );
+ /*jshint loopfunc:false*/
+ } else if ( pointsList.clicks === 2 ) {
+ clearTimeout( delegate.dblClickTimeOut );
+ pointsList.clicks = 0;
+ if ( delegate.lastClickPos.distanceTo( releasePoint ) <= tracker.dblClickDistThreshold ) {
+ tracker.dblClickHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
+ shift: eventInfo.originalEvent.shiftKey,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ }
+ delegate.lastClickPos = null;
+ }
}
}
+ } else if ( pointsList.contacts === 2 ) {
+ if ( tracker.pinchHandler && updateGPoint.type === 'touch' ) {
+ // Reset for pinch
+ delegate.pinchGPoints = pointsList.asArray();
+ delegate.lastPinchDist = delegate.currentPinchDist = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
+ delegate.lastPinchCenter = delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
+ }
+ }
+ } else {
+ // Pointer was activated in another element but removed in our element
+
+ eventInfo.shouldReleaseCapture = false;
+
+ // Release (pressed in another element)
+ if ( tracker.releaseHandler ) {
+ tracker.releaseHandler(
+ {
+ eventSource: tracker,
+ pointerType: updateGPoint.type,
+ position: getPointRelativeToAbsolute( releasePoint, tracker.element ),
+ buttons: pointsList.buttons,
+ insideElementPressed: updateGPoint.insideElementPressed,
+ insideElementReleased: updateGPoint.insideElement,
+ isTouchEvent: updateGPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
+ preventDefaultAction: false,
+ userData: tracker.userData
+ }
+ );
+ eventInfo.preventDefault = true;
}
}
}
-
- return releaseCapture;
}
@@ -3146,101 +3546,88 @@
* @inner
* @param {OpenSeadragon.MouseTracker} tracker
* A reference to the MouseTracker instance.
- * @param {Object} event
- * A reference to the originating DOM event.
- * @param {Array.} gPoints
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * Processing info for originating DOM event.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
* Gesture points associated with the event.
*/
- function updatePointersMove( tracker, event, gPoints ) {
+ function updatePointerMove( tracker, eventInfo, gPoint ) {
var delegate = THIS[ tracker.hash ],
- pointsList = tracker.getActivePointersListByType( gPoints[ 0 ].type ),
- i,
- gPointCount = gPoints.length,
- curGPoint,
+ pointsList = tracker.getActivePointersListByType( gPoint.type ),
updateGPoint,
gPointArray,
- delta,
- propagate;
+ delta;
- if ( typeof event.buttons !== 'undefined' ) {
- pointsList.buttons = event.buttons;
+ if ( typeof eventInfo.originalEvent.buttons !== 'undefined' ) {
+ pointsList.buttons = eventInfo.originalEvent.buttons;
}
- for ( i = 0; i < gPointCount; i++ ) {
- curGPoint = gPoints[ i ];
- updateGPoint = pointsList.getById( curGPoint.id );
+ updateGPoint = pointsList.getById( gPoint.id );
- if ( updateGPoint ) {
- // Already tracking the pointer...update it
- if ( Object.prototype.hasOwnProperty.call( curGPoint, 'isPrimary' ) ) {
- updateGPoint.isPrimary = curGPoint.isPrimary;
- }
- updateGPoint.lastPos = updateGPoint.currentPos;
- updateGPoint.lastTime = updateGPoint.currentTime;
- updateGPoint.currentPos = curGPoint.currentPos;
- updateGPoint.currentTime = curGPoint.currentTime;
- } else {
- // Initialize for tracking and add to the tracking list (no pointerover or pointerdown event occurred before this)
- curGPoint.captured = false;
- curGPoint.insideElementPressed = false;
- curGPoint.insideElement = true;
- startTrackingPointer( pointsList, curGPoint );
- }
+ if ( updateGPoint ) {
+ // Already tracking the pointer...update it
+ updateGPoint.lastPos = updateGPoint.currentPos;
+ updateGPoint.lastTime = updateGPoint.currentTime;
+ updateGPoint.currentPos = gPoint.currentPos;
+ updateGPoint.currentTime = gPoint.currentTime;
+ } else {
+ // Initialize for tracking and add to the tracking list (no pointerover or pointerdown event occurred before this)
+ gPoint.captured = false; // Handled by updatePointerCaptured()
+ gPoint.insideElementPressed = false;
+ gPoint.insideElement = true;
+ startTrackingPointer( pointsList, gPoint );
}
+ eventInfo.shouldCapture = false;
+ eventInfo.shouldReleaseCapture = false;
+
// Stop (mouse only)
- if ( tracker.stopHandler && gPoints[ 0 ].type === 'mouse' ) {
+ if ( tracker.stopHandler && gPoint.type === 'mouse' ) {
clearTimeout( tracker.stopTimeOut );
tracker.stopTimeOut = setTimeout( function() {
- handlePointerStop( tracker, event, gPoints[ 0 ].type );
+ handlePointerStop( tracker, eventInfo.originalEvent, gPoint.type );
}, tracker.stopDelay );
}
if ( pointsList.contacts === 0 ) {
// Move (no contacts: hovering mouse or other hover-capable device)
if ( tracker.moveHandler ) {
- propagate = tracker.moveHandler(
+ tracker.moveHandler(
{
eventSource: tracker,
- pointerType: gPoints[ 0 ].type,
- position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),
+ pointerType: gPoint.type,
+ position: getPointRelativeToAbsolute( gPoint.currentPos, tracker.element ),
buttons: pointsList.buttons,
- isTouchEvent: gPoints[ 0 ].type === 'touch',
- originalEvent: event,
+ isTouchEvent: gPoint.type === 'touch',
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
}
} else if ( pointsList.contacts === 1 ) {
// Move (1 contact)
if ( tracker.moveHandler ) {
updateGPoint = pointsList.asArray()[ 0 ];
- propagate = tracker.moveHandler(
+ tracker.moveHandler(
{
eventSource: tracker,
pointerType: updateGPoint.type,
position: getPointRelativeToAbsolute( updateGPoint.currentPos, tracker.element ),
buttons: pointsList.buttons,
isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
}
// Drag
- if ( tracker.dragHandler ) {
+ if ( tracker.dragHandler && !eventInfo.preventGesture && !eventInfo.defaultPrevented ) {
updateGPoint = pointsList.asArray()[ 0 ];
delta = updateGPoint.currentPos.minus( updateGPoint.lastPos );
- propagate = tracker.dragHandler(
+ tracker.dragHandler(
{
eventSource: tracker,
pointerType: updateGPoint.type,
@@ -3249,47 +3636,43 @@
delta: delta,
speed: updateGPoint.speed,
direction: updateGPoint.direction,
- shift: event.shiftKey,
+ shift: eventInfo.originalEvent.shiftKey,
isTouchEvent: updateGPoint.type === 'touch',
- originalEvent: event,
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
+ eventInfo.preventDefault = true;
}
} else if ( pointsList.contacts === 2 ) {
// Move (2 contacts, use center)
if ( tracker.moveHandler ) {
gPointArray = pointsList.asArray();
- propagate = tracker.moveHandler(
+ tracker.moveHandler(
{
eventSource: tracker,
pointerType: gPointArray[ 0 ].type,
position: getPointRelativeToAbsolute( getCenterPoint( gPointArray[ 0 ].currentPos, gPointArray[ 1 ].currentPos ), tracker.element ),
buttons: pointsList.buttons,
isTouchEvent: gPointArray[ 0 ].type === 'touch',
- originalEvent: event,
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
}
// Pinch
- if ( tracker.pinchHandler && gPoints[ 0 ].type === 'touch' ) {
+ if ( tracker.pinchHandler && gPoint.type === 'touch' &&
+ !eventInfo.preventGesture && !eventInfo.defaultPrevented ) {
delta = delegate.pinchGPoints[ 0 ].currentPos.distanceTo( delegate.pinchGPoints[ 1 ].currentPos );
if ( delta !== delegate.currentPinchDist ) {
delegate.lastPinchDist = delegate.currentPinchDist;
delegate.currentPinchDist = delta;
delegate.lastPinchCenter = delegate.currentPinchCenter;
delegate.currentPinchCenter = getCenterPoint( delegate.pinchGPoints[ 0 ].currentPos, delegate.pinchGPoints[ 1 ].currentPos );
- propagate = tracker.pinchHandler(
+ tracker.pinchHandler(
{
eventSource: tracker,
pointerType: 'touch',
@@ -3298,15 +3681,13 @@
center: getPointRelativeToAbsolute( delegate.currentPinchCenter, tracker.element ),
lastDistance: delegate.lastPinchDist,
distance: delegate.currentPinchDist,
- shift: event.shiftKey,
- originalEvent: event,
+ shift: eventInfo.originalEvent.shiftKey,
+ originalEvent: eventInfo.originalEvent,
preventDefaultAction: false,
userData: tracker.userData
}
);
- if ( propagate === false ) {
- $.cancelEvent( event );
- }
+ eventInfo.preventDefault = true;
}
}
}
@@ -3319,14 +3700,20 @@
* @inner
* @param {OpenSeadragon.MouseTracker} tracker
* A reference to the MouseTracker instance.
- * @param {Object} event
- * A reference to the originating DOM event.
- * @param {Array.} gPoints
+ * @param {OpenSeadragon.MouseTracker.EventProcessInfo} eventInfo
+ * Processing info for originating DOM event.
+ * @param {OpenSeadragon.MouseTracker.GesturePoint} gPoint
* Gesture points associated with the event.
*/
- function updatePointersCancel( tracker, event, gPoints ) {
- updatePointersUp( tracker, event, gPoints, 0 );
- updatePointersExit( tracker, event, gPoints );
+ function updatePointerCancel( tracker, eventInfo, gPoint ) {
+ var pointsList = tracker.getActivePointersListByType( gPoint.type ),
+ updateGPoint;
+
+ updateGPoint = pointsList.getById( gPoint.id );
+
+ if ( updateGPoint ) {
+ stopTrackingPointer( tracker, pointsList, updateGPoint );
+ }
}
@@ -3349,32 +3736,4 @@
}
}
- /**
- * True if inside an iframe, otherwise false.
- * @member {Boolean} isInIframe
- * @private
- * @inner
- */
- var isInIframe = (function() {
- try {
- return window.self !== window.top;
- } catch (e) {
- return true;
- }
- })();
-
- /**
- * @function
- * @private
- * @inner
- * @returns {Boolean} True if the target has access rights to events, otherwise false.
- */
- function canAccessEvents (target) {
- try {
- return target.addEventListener && target.removeEventListener;
- } catch (e) {
- return false;
- }
- }
-
}(OpenSeadragon));
diff --git a/src/navigator.js b/src/navigator.js
index f0bdf452..cbe0780e 100644
--- a/src/navigator.js
+++ b/src/navigator.js
@@ -167,12 +167,16 @@ $.Navigator = function( options ){
style.zIndex = 999999999;
style.cursor = 'default';
}( this.displayRegion.style, this.borderWidth ));
+ $.setElementPointerEventsNone( this.displayRegion );
+ $.setElementTouchActionNone( this.displayRegion );
this.displayRegionContainer = $.makeNeutralElement("div");
this.displayRegionContainer.id = this.element.id + '-displayregioncontainer';
this.displayRegionContainer.className = "displayregioncontainer";
this.displayRegionContainer.style.width = "100%";
this.displayRegionContainer.style.height = "100%";
+ $.setElementPointerEventsNone( this.displayRegionContainer );
+ $.setElementTouchActionNone( this.displayRegionContainer );
viewer.addControl(
this.element,
@@ -221,12 +225,22 @@ $.Navigator = function( options ){
// Remove the base class' (Viewer's) innerTracker and replace it with our own
this.innerTracker.destroy();
this.innerTracker = new $.MouseTracker({
- element: this.element,
+ userData: 'Navigator.innerTracker',
+ element: this.element, //this.canvas,
dragHandler: $.delegate( this, onCanvasDrag ),
clickHandler: $.delegate( this, onCanvasClick ),
releaseHandler: $.delegate( this, onCanvasRelease ),
scrollHandler: $.delegate( this, onCanvasScroll )
});
+ this.outerTracker.userData = 'Navigator.outerTracker';
+
+ // this.innerTracker is attached to this.element...we need to allow pointer
+ // events to pass through this Viewer's canvas/container elements so implicit
+ // pointer capture works on touch devices
+ //TODO an alternative is to attach the new MouseTracker to this.canvas...not
+ // sure why it isn't already (see MouseTracker constructor call above)
+ $.setElementPointerEventsNone( this.canvas );
+ $.setElementPointerEventsNone( this.container );
this.addHandler("reset-size", function() {
if (_this.viewport) {
@@ -526,7 +540,7 @@ function onCanvasDrag( event ) {
* @property {Boolean} shift - True if the shift key was pressed during this event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
- * @property {Boolean} preventDefaultAction - Set to true to prevent default click to zoom behaviour. Default: false.
+ * @property {Boolean} preventDefaultAction - Set to true to prevent default drag to pan behaviour. Default: false.
*/
this.viewer.raiseEvent('navigator-drag', canvasDragEventArgs);
diff --git a/src/openseadragon.js b/src/openseadragon.js
index 1a6eaa7a..9eaf16c6 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -381,7 +381,11 @@
* The "zoom distance" per mouse scroll or touch pinch. Note: Setting this to 1.0 effectively disables the mouse-wheel zoom feature (also see gestureSettings[Mouse|Touch|Pen].scrollToZoom}).
*
* @property {Number} [zoomPerSecond=1.0]
- * The number of seconds to animate a single zoom event over.
+ * Sets the zoom amount per second when zoomIn/zoomOut buttons are pressed and held.
+ * The value is a factor of the current zoom, so 1.0 (the default) disables zooming when the zoomIn/zoomOut buttons
+ * are held. Higher values will increase the rate of zoom when the zoomIn/zoomOut buttons are held. Note that values
+ * < 1.0 will reverse the operation of the zoomIn/zoomOut buttons (zoomIn button will decrease the zoom, zoomOut will
+ * increase the zoom).
*
* @property {Boolean} [showNavigator=false]
* Set to true to make the navigator minimap appear.
@@ -918,9 +922,62 @@ function OpenSeadragon( options ){
};
/**
- * @returns {Number} Return a ratio comparing the device screen's pixel
- * density to the canvas's backing store pixel density, clamped to a
- * minimum of 1. Defaults to 1 if canvas isn't supported by the browser.
+ * True if the browser supports the EventTarget.addEventListener() method
+ * @member {Boolean} supportsAddEventListener
+ * @memberof OpenSeadragon
+ */
+ $.supportsAddEventListener = (function () {
+ return !!(document.documentElement.addEventListener && document.addEventListener);
+ }());
+
+ /**
+ * True if the browser supports the EventTarget.removeEventListener() method
+ * @member {Boolean} supportsRemoveEventListener
+ * @memberof OpenSeadragon
+ */
+ $.supportsRemoveEventListener = (function () {
+ return !!(document.documentElement.removeEventListener && document.removeEventListener);
+ }());
+
+ /**
+ * True if the browser supports the newer EventTarget.addEventListener options argument
+ * @member {Boolean} supportsEventListenerOptions
+ * @memberof OpenSeadragon
+ */
+ $.supportsEventListenerOptions = (function () {
+ var supported = 0;
+
+ if ( $.supportsAddEventListener ) {
+ try {
+ var options = {
+ get capture() {
+ supported++;
+ return false;
+ },
+ get once() {
+ supported++;
+ return false;
+ },
+ get passive() {
+ supported++;
+ return false;
+ }
+ };
+ window.addEventListener("test", null, options);
+ window.removeEventListener("test", null, options);
+ } catch ( e ) {
+ supported = 0;
+ }
+ }
+
+ return supported >= 3;
+ }());
+
+ /**
+ * A ratio comparing the device screen's pixel density to the canvas's backing store pixel density,
+ * clamped to a minimum of 1. Defaults to 1 if canvas isn't supported by the browser.
+ * @member {Number} pixelDensityRatio
+ * @memberof OpenSeadragon
*/
$.getCurrentPixelDensityRatio = function() {
if ( $.supportsCanvas ) {
@@ -947,7 +1004,7 @@ function OpenSeadragon( options ){
/**
* This closure defines all static methods available to the OpenSeadragon
- * namespace. Many, if not most, are taked directly from jQuery for use
+ * namespace. Many, if not most, are taken directly from jQuery for use
* to simplify and reduce common programming patterns. More static methods
* from jQuery may eventually make their way into this though we are
* attempting to avoid an explicit dependency on jQuery only because
@@ -1320,6 +1377,8 @@ function OpenSeadragon( options ){
* @property {Number} SAFARI
* @property {Number} CHROME
* @property {Number} OPERA
+ * @property {Number} EDGE
+ * @property {Number} CHROMEEDGE
*/
BROWSERS: {
UNKNOWN: 0,
@@ -1327,7 +1386,9 @@ function OpenSeadragon( options ){
FIREFOX: 2,
SAFARI: 3,
CHROME: 4,
- OPERA: 5
+ OPERA: 5,
+ EDGE: 6,
+ CHROMEEDGE: 7
},
@@ -1522,29 +1583,6 @@ function OpenSeadragon( options ){
},
- /**
- * Gets the latest event, really only useful internally since its
- * specific to IE behavior.
- * @function
- * @param {Event} [event]
- * @returns {Event}
- * @deprecated For internal use only
- * @private
- */
- getEvent: function( event ) {
- if( event ){
- $.getEvent = function( event ) {
- return event;
- };
- } else {
- $.getEvent = function() {
- return window.event;
- };
- }
- return $.getEvent( event );
- },
-
-
/**
* Gets the position of the mouse on the screen for a given event.
* @function
@@ -1557,7 +1595,6 @@ function OpenSeadragon( options ){
$.getMousePosition = function( event ){
var result = new $.Point();
- event = $.getEvent( event );
result.x = event.pageX;
result.y = event.pageY;
@@ -1567,7 +1604,6 @@ function OpenSeadragon( options ){
$.getMousePosition = function( event ){
var result = new $.Point();
- event = $.getEvent( event );
result.x =
event.clientX +
document.body.scrollLeft +
@@ -1803,51 +1839,16 @@ function OpenSeadragon( options ){
/**
* Ensures an image is loaded correctly to support alpha transparency.
- * Generally only IE has issues doing this correctly for formats like
- * png.
* @function
* @param {String} src
* @returns {Element}
*/
makeTransparentImage: function( src ) {
+ var img = $.makeNeutralElement( "img" );
- $.makeTransparentImage = function( src ){
- var img = $.makeNeutralElement( "img" );
+ img.src = src;
- img.src = src;
-
- return img;
- };
-
- if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 7 ) {
-
- $.makeTransparentImage = function( src ){
- var img = $.makeNeutralElement( "img" ),
- element = null;
-
- element = $.makeNeutralElement("span");
- element.style.display = "inline-block";
-
- img.onload = function() {
- element.style.width = element.style.width || img.width + "px";
- element.style.height = element.style.height || img.height + "px";
-
- img.onload = null;
- img = null; // to prevent memory leaks in IE
- };
-
- img.src = src;
- element.style.filter =
- "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
- src +
- "', sizingMethod='scale')";
-
- return element;
- };
-
- }
-
- return $.makeTransparentImage( src );
+ return img;
},
@@ -1898,6 +1899,19 @@ function OpenSeadragon( options ){
},
+ /**
+ * Sets the specified element's pointer-events style attribute to 'none'.
+ * @function
+ * @param {Element|String} element
+ */
+ setElementPointerEventsNone: function( element ) {
+ element = $.getElement( element );
+ if ( typeof element.style.pointerEvents !== 'undefined' ) {
+ element.style.pointerEvents = 'none';
+ }
+ },
+
+
/**
* Add the specified CSS class to the element if not present.
* @function
@@ -1983,6 +1997,34 @@ function OpenSeadragon( options ){
element.className = newClasses.join(' ');
},
+ /**
+ * Convert passed addEventListener() options to boolean or options object,
+ * depending on browser support.
+ * @function
+ * @param {Boolean|Object} [options] Boolean useCapture, or if [supportsEventListenerOptions]{@link OpenSeadragon.supportsEventListenerOptions}, can be an object
+ * @param {Boolean} [options.capture]
+ * @param {Boolean} [options.passive]
+ * @param {Boolean} [options.once]
+ * @return {String} The protocol (http:, https:, file:, ftp: ...)
+ */
+ normalizeEventListenerOptions: function (options) {
+ var opts;
+ if ( typeof options !== 'undefined' ) {
+ if ( typeof options === 'boolean' ) {
+ // Legacy Boolean useCapture
+ opts = $.supportsEventListenerOptions ? { capture: options } : options;
+ } else {
+ // Options object
+ opts = $.supportsEventListenerOptions ? options :
+ ( ( typeof options.capture !== 'undefined' ) ? options.capture : false );
+ }
+ } else {
+ // No options specified - Legacy optional useCapture argument
+ // (for IE, first supported on version 9, so we'll pass a Boolean)
+ opts = $.supportsEventListenerOptions ? { capture: false } : false;
+ }
+ return opts;
+ },
/**
* Adds an event listener for the given element, eventName and handler.
@@ -1990,16 +2032,20 @@ function OpenSeadragon( options ){
* @param {Element|String} element
* @param {String} eventName
* @param {Function} handler
- * @param {Boolean} [useCapture]
+ * @param {Boolean|Object} [options] Boolean useCapture, or if [supportsEventListenerOptions]{@link OpenSeadragon.supportsEventListenerOptions}, can be an object
+ * @param {Boolean} [options.capture]
+ * @param {Boolean} [options.passive]
+ * @param {Boolean} [options.once]
*/
addEvent: (function () {
- if ( window.addEventListener ) {
- return function ( element, eventName, handler, useCapture ) {
+ if ( $.supportsAddEventListener ) {
+ return function ( element, eventName, handler, options ) {
+ options = $.normalizeEventListenerOptions(options);
element = $.getElement( element );
- element.addEventListener( eventName, handler, useCapture );
+ element.addEventListener( eventName, handler, options );
};
- } else if ( window.attachEvent ) {
- return function ( element, eventName, handler, useCapture ) {
+ } else if ( document.documentElement.attachEvent && document.attachEvent ) {
+ return function ( element, eventName, handler ) {
element = $.getElement( element );
element.attachEvent( 'on' + eventName, handler );
};
@@ -2016,16 +2062,18 @@ function OpenSeadragon( options ){
* @param {Element|String} element
* @param {String} eventName
* @param {Function} handler
- * @param {Boolean} [useCapture]
+ * @param {Boolean|Object} [options] Boolean useCapture, or if [supportsEventListenerOptions]{@link OpenSeadragon.supportsEventListenerOptions}, can be an object
+ * @param {Boolean} [options.capture]
*/
removeEvent: (function () {
- if ( window.removeEventListener ) {
- return function ( element, eventName, handler, useCapture ) {
+ if ( $.supportsRemoveEventListener ) {
+ return function ( element, eventName, handler, options ) {
+ options = $.normalizeEventListenerOptions(options);
element = $.getElement( element );
- element.removeEventListener( eventName, handler, useCapture );
+ element.removeEventListener( eventName, handler, options );
};
- } else if ( window.detachEvent ) {
- return function( element, eventName, handler, useCapture ) {
+ } else if ( document.documentElement.detachEvent && document.detachEvent ) {
+ return function( element, eventName, handler ) {
element = $.getElement( element );
element.detachEvent( 'on' + eventName, handler );
};
@@ -2042,49 +2090,28 @@ function OpenSeadragon( options ){
* @param {Event} [event]
*/
cancelEvent: function( event ) {
- event = $.getEvent( event );
-
- if ( event.preventDefault ) {
- $.cancelEvent = function( event ){
- // W3C for preventing default
- event.preventDefault();
- };
- } else {
- $.cancelEvent = function( event ){
- event = $.getEvent( event );
- // legacy for preventing default
- event.cancel = true;
- // IE for preventing default
- event.returnValue = false;
- };
- }
- $.cancelEvent( event );
+ event.preventDefault();
},
/**
- * Stops the propagation of the event up the DOM.
+ * Returns true if {@link OpenSeadragon.cancelEvent|cancelEvent} has been called on
+ * the event, otherwise returns false.
+ * @function
+ * @param {Event} [event]
+ */
+ eventIsCanceled: function( event ) {
+ return event.defaultPrevented;
+ },
+
+
+ /**
+ * Stops the propagation of the event through the DOM in the capturing and bubbling phases.
* @function
* @param {Event} [event]
*/
stopEvent: function( event ) {
- event = $.getEvent( event );
-
- if ( event.stopPropagation ) {
- // W3C for stopping propagation
- $.stopEvent = function( event ){
- event.stopPropagation();
- };
- } else {
- // IE for stopping propagation
- $.stopEvent = function( event ){
- event = $.getEvent( event );
- event.cancelBubble = true;
- };
-
- }
-
- $.stopEvent( event );
+ event.stopPropagation();
},
@@ -2273,62 +2300,12 @@ function OpenSeadragon( options ){
request.send(null);
} catch (e) {
- var msg = e.message;
-
- /*
- IE < 10 does not support CORS and an XHR request to a different origin will fail as soon
- as send() is called. This is particularly easy to miss during development and appear in
- production if you use a CDN or domain sharding and the security policy is likely to break
- exception handlers since any attempt to access a property of the request object will
- raise an access denied TypeError inside the catch block.
-
- To be friendlier, we'll check for this specific error and add a documentation pointer
- to point developers in the right direction. We test the exception number because IE's
- error messages are localized.
- */
- var oldIE = $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 10;
- if ( oldIE && typeof ( e.number ) !== "undefined" && e.number === -2147024891 ) {
- msg += "\nSee http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx#xdomain";
- }
-
- $.console.log( "%s while making AJAX request: %s", e.name, msg );
+ $.console.log( "%s while making AJAX request: %s", e.name, e.message );
request.onreadystatechange = function(){};
- if (window.XDomainRequest) { // IE9 or IE8 might as well try to use XDomainRequest
- var xdr = new window.XDomainRequest();
- if (xdr) {
- xdr.onload = function (e) {
- if ( $.isFunction( onSuccess ) ) {
- onSuccess({ // Faking an xhr object
- responseText: xdr.responseText,
- status: 200, // XDomainRequest doesn't support status codes, so we just fake one! :/
- statusText: 'OK'
- });
- }
- };
- xdr.onerror = function (e) {
- if ($.isFunction(onError)) {
- onError({ // Faking an xhr object
- responseText: xdr.responseText,
- status: 444, // 444 No Response
- statusText: 'An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser.'
- });
- }
- };
- try {
- xdr.open('GET', url);
- xdr.send();
- } catch (e2) {
- if ( $.isFunction( onError ) ) {
- onError( request, e );
- }
- }
- }
- } else {
- if ( $.isFunction( onError ) ) {
- onError( request, e );
- }
+ if ( $.isFunction( onError ) ) {
+ onError( request, e );
}
}
@@ -2467,16 +2444,7 @@ function OpenSeadragon( options ){
* @returns {Object}
*/
parseJSON: function(string) {
- if (window.JSON && window.JSON.parse) {
- $.parseJSON = window.JSON.parse;
- } else {
- // Should only be used by IE8 in non standards mode
- $.parseJSON = function(string) {
- /*jshint evil:true*/
- //eslint-disable-next-line no-eval
- return eval('(' + string + ')');
- };
- }
+ $.parseJSON = window.JSON.parse;
return $.parseJSON(string);
},
@@ -2574,7 +2542,17 @@ function OpenSeadragon( options ){
break;
case "Netscape":
if (window.addEventListener) {
- if ( ua.indexOf( "Firefox" ) >= 0 ) {
+ if ( ua.indexOf( "Edge" ) >= 0 ) {
+ $.Browser.vendor = $.BROWSERS.EDGE;
+ $.Browser.version = parseFloat(
+ ua.substring( ua.indexOf( "Edge" ) + 5 )
+ );
+ } else if ( ua.indexOf( "Edg" ) >= 0 ) {
+ $.Browser.vendor = $.BROWSERS.CHROMEEDGE;
+ $.Browser.version = parseFloat(
+ ua.substring( ua.indexOf( "Edg" ) + 4 )
+ );
+ } else if ( ua.indexOf( "Firefox" ) >= 0 ) {
$.Browser.vendor = $.BROWSERS.FIREFOX;
$.Browser.version = parseFloat(
ua.substring( ua.indexOf( "Firefox" ) + 8 )
@@ -2628,21 +2606,15 @@ function OpenSeadragon( options ){
//determine if this browser supports image alpha transparency
$.Browser.alpha = !(
- (
- $.Browser.vendor === $.BROWSERS.IE &&
- $.Browser.version < 9
- ) || (
- $.Browser.vendor === $.BROWSERS.CHROME &&
- $.Browser.version < 2
- )
+ $.Browser.vendor === $.BROWSERS.CHROME && $.Browser.version < 2
);
//determine if this browser supports element.style.opacity
- $.Browser.opacity = !(
- $.Browser.vendor === $.BROWSERS.IE &&
- $.Browser.version < 9
- );
+ $.Browser.opacity = true;
+ if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 11 ) {
+ $.console.error('Internet Explorer versions < 11 are not supported by OpenSeadragon');
+ }
})();
diff --git a/src/referencestrip.js b/src/referencestrip.js
index 31340e43..ee609057 100644
--- a/src/referencestrip.js
+++ b/src/referencestrip.js
@@ -85,14 +85,7 @@ $.ReferenceStrip = function ( options ) {
scroll: $.DEFAULT_SETTINGS.referenceStripScroll,
clickTimeThreshold: $.DEFAULT_SETTINGS.clickTimeThreshold
}, options, {
- //required overrides
- element: this.element,
- //These need to be overridden to prevent recursion since
- //the navigator is a viewer and a viewer has a navigator
- showNavigator: false,
- mouseNavEnabled: false,
- showNavigationControl: false,
- showSequenceControl: false
+ element: this.element
} );
$.extend( this, options );
@@ -119,12 +112,14 @@ $.ReferenceStrip = function ( options ) {
$.setElementOpacity( this.element, 0.8 );
this.viewer = viewer;
- this.innerTracker = new $.MouseTracker( {
+ this.tracker = new $.MouseTracker( {
+ userData: 'ReferenceStrip.tracker',
element: this.element,
+ clickHandler: $.delegate( this, onStripClick ),
dragHandler: $.delegate( this, onStripDrag ),
scrollHandler: $.delegate( this, onStripScroll ),
enterHandler: $.delegate( this, onStripEnter ),
- exitHandler: $.delegate( this, onStripExit ),
+ leaveHandler: $.delegate( this, onStripLeave ),
keyDownHandler: $.delegate( this, onKeyDown ),
keyHandler: $.delegate( this, onKeyPress )
} );
@@ -189,34 +184,12 @@ $.ReferenceStrip = function ( options ) {
element.style.width = _this.panelWidth + 'px';
element.style.height = _this.panelHeight + 'px';
element.style.display = 'inline';
- element.style.float = 'left'; //Webkit
+ element.style['float'] = 'left'; //Webkit
element.style.cssFloat = 'left'; //Firefox
element.style.styleFloat = 'left'; //IE
element.style.padding = '2px';
$.setElementTouchActionNone( element );
-
- element.innerTracker = new $.MouseTracker( {
- element: element,
- clickTimeThreshold: this.clickTimeThreshold,
- clickDistThreshold: this.clickDistThreshold,
- pressHandler: function ( event ) {
- event.eventSource.dragging = $.now();
- },
- releaseHandler: function ( event ) {
- var tracker = event.eventSource,
- id = tracker.element.id,
- page = Number( id.split( '-' )[2] ),
- now = $.now();
-
- if ( event.insideElementPressed &&
- event.insideElementReleased &&
- tracker.dragging &&
- ( now - tracker.dragging ) < tracker.clickTimeThreshold ) {
- tracker.dragging = null;
- viewer.goToPage( page );
- }
- }
- } );
+ $.setElementPointerEventsNone( element );
this.element.appendChild( element );
@@ -230,7 +203,8 @@ $.ReferenceStrip = function ( options ) {
};
-$.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.ReferenceStrip.prototype */{
+/** @lends OpenSeadragon.ReferenceStrip.prototype */
+$.ReferenceStrip.prototype = {
/**
* @function
@@ -277,7 +251,7 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
}
this.currentPage = page;
- onStripEnter.call( this, { eventSource: this.innerTracker } );
+ onStripEnter.call( this, { eventSource: this.tracker } );
}
},
@@ -292,7 +266,6 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
return false;
},
- // Overrides Viewer.destroy
destroy: function() {
if (this.miniViewers) {
for (var key in this.miniViewers) {
@@ -300,14 +273,34 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
}
}
+ this.tracker.destroy();
+
if (this.element) {
this.element.parentNode.removeChild(this.element);
}
}
-} );
+};
+/**
+ * @private
+ * @inner
+ * @function
+ */
+function onStripClick( event ) {
+ if ( event.quick ) {
+ var page;
+
+ if ( 'horizontal' === this.scroll ) {
+ page = Math.floor(event.position.x / this.panelWidth);
+ } else {
+ page = Math.floor(event.position.y / this.panelHeight);
+ }
+
+ this.viewer.goToPage( page );
+ }
+}
/**
@@ -317,13 +310,14 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
*/
function onStripDrag( event ) {
- var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),
+ this.dragging = true;
+ if ( this.element ) {
+ var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),
offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ),
scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),
scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),
viewerSize = $.getElementSize( this.viewer.canvas );
- this.dragging = true;
- if ( this.element ) {
+
if ( 'horizontal' === this.scroll ) {
if ( -event.delta.x > 0 ) {
//forward
@@ -366,12 +360,13 @@ function onStripDrag( event ) {
* @function
*/
function onStripScroll( event ) {
- var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),
+ if ( this.element ) {
+ var offsetLeft = Number( this.element.style.marginLeft.replace( 'px', '' ) ),
offsetTop = Number( this.element.style.marginTop.replace( 'px', '' ) ),
scrollWidth = Number( this.element.style.width.replace( 'px', '' ) ),
scrollHeight = Number( this.element.style.height.replace( 'px', '' ) ),
viewerSize = $.getElementSize( this.viewer.canvas );
- if ( this.element ) {
+
if ( 'horizontal' === this.scroll ) {
if ( event.scroll > 0 ) {
//forward
@@ -412,7 +407,6 @@ function loadPanels( strip, viewerSize, scroll ) {
activePanelsStart,
activePanelsEnd,
miniViewer,
- style,
i,
element;
if ( 'horizontal' === strip.scroll ) {
@@ -454,34 +448,14 @@ function loadPanels( strip, viewerSize, scroll ) {
ajaxHeaders: strip.viewer.ajaxHeaders,
useCanvas: strip.useCanvas
} );
-
- miniViewer.displayRegion = $.makeNeutralElement( "div" );
- miniViewer.displayRegion.id = element.id + '-displayregion';
- miniViewer.displayRegion.className = 'displayregion';
-
- style = miniViewer.displayRegion.style;
- style.position = 'relative';
- style.top = '0px';
- style.left = '0px';
- style.fontSize = '0px';
- style.overflow = 'hidden';
- style.float = 'left'; //Webkit
- style.cssFloat = 'left'; //Firefox
- style.styleFloat = 'left'; //IE
- style.zIndex = 999999999;
- style.cursor = 'default';
- 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,
- startDisabled: true
- } );
-
- element.getElementsByTagName( 'div' )[0].appendChild(
- miniViewer.displayRegion
- );
+ // Allow pointer events to pass through miniViewer's canvas/container
+ // elements so implicit pointer capture works on touch devices
+ $.setElementPointerEventsNone( miniViewer.canvas );
+ $.setElementPointerEventsNone( miniViewer.container );
+ // We'll use event delegation from the reference strip element instead of
+ // handling events on every miniViewer
+ miniViewer.innerTracker.setTracking( false );
+ miniViewer.outerTracker.setTracking( false );
strip.miniViewers[element.id] = miniViewer;
@@ -524,7 +498,7 @@ function onStripEnter( event ) {
* @inner
* @function
*/
-function onStripExit( event ) {
+function onStripLeave( event ) {
var element = event.eventSource.element;
if ( 'horizontal' === this.scroll ) {
diff --git a/src/viewer.js b/src/viewer.js
index 397b4257..d6bf83f3 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -267,6 +267,7 @@ $.Viewer = function( options ) {
style.top = "0px";
style.textAlign = "left"; // needed to protect against
}( this.container.style ));
+ $.setElementTouchActionNone( this.container );
this.container.insertBefore( this.canvas, this.container.firstChild );
this.element.appendChild( this.container );
@@ -280,12 +281,14 @@ $.Viewer = function( options ) {
this.docOverflow = document.documentElement.style.overflow;
this.innerTracker = new $.MouseTracker({
+ userData: 'Viewer.innerTracker',
element: this.canvas,
startDisabled: !this.mouseNavEnabled,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
dblClickTimeThreshold: this.dblClickTimeThreshold,
dblClickDistThreshold: this.dblClickDistThreshold,
+ contextMenuHandler: $.delegate( this, onCanvasContextMenu ),
keyDownHandler: $.delegate( this, onCanvasKeyDown ),
keyHandler: $.delegate( this, onCanvasKeyPress ),
clickHandler: $.delegate( this, onCanvasClick ),
@@ -293,7 +296,7 @@ $.Viewer = function( options ) {
dragHandler: $.delegate( this, onCanvasDrag ),
dragEndHandler: $.delegate( this, onCanvasDragEnd ),
enterHandler: $.delegate( this, onCanvasEnter ),
- exitHandler: $.delegate( this, onCanvasExit ),
+ leaveHandler: $.delegate( this, onCanvasLeave ),
pressHandler: $.delegate( this, onCanvasPress ),
releaseHandler: $.delegate( this, onCanvasRelease ),
nonPrimaryPressHandler: $.delegate( this, onCanvasNonPrimaryPress ),
@@ -303,6 +306,7 @@ $.Viewer = function( options ) {
});
this.outerTracker = new $.MouseTracker({
+ userData: 'Viewer.outerTracker',
element: this.container,
startDisabled: !this.mouseNavEnabled,
clickTimeThreshold: this.clickTimeThreshold,
@@ -310,7 +314,7 @@ $.Viewer = function( options ) {
dblClickTimeThreshold: this.dblClickTimeThreshold,
dblClickDistThreshold: this.dblClickDistThreshold,
enterHandler: $.delegate( this, onContainerEnter ),
- exitHandler: $.delegate( this, onContainerExit )
+ leaveHandler: $.delegate( this, onContainerLeave )
});
if( this.toolbar ){
@@ -403,20 +407,22 @@ $.Viewer = function( options ) {
// Overlay container
this.overlaysContainer = $.makeNeutralElement( "div" );
+ $.setElementPointerEventsNone( this.overlaysContainer );
+ $.setElementTouchActionNone( this.overlaysContainer );
this.canvas.appendChild( this.overlaysContainer );
// Now that we have a drawer, see if it supports rotate. If not we need to remove the rotate buttons
if (!this.drawer.canRotate()) {
// Disable/remove the rotate left/right buttons since they aren't supported
if (this.rotateLeft) {
- i = this.buttons.buttons.indexOf(this.rotateLeft);
- this.buttons.buttons.splice(i, 1);
- this.buttons.element.removeChild(this.rotateLeft.element);
+ i = this.buttonGroup.buttons.indexOf(this.rotateLeft);
+ this.buttonGroup.buttons.splice(i, 1);
+ this.buttonGroup.element.removeChild(this.rotateLeft.element);
}
if (this.rotateRight) {
- i = this.buttons.buttons.indexOf(this.rotateRight);
- this.buttons.buttons.splice(i, 1);
- this.buttons.element.removeChild(this.rotateRight.element);
+ i = this.buttonGroup.buttons.indexOf(this.rotateRight);
+ this.buttonGroup.buttons.splice(i, 1);
+ this.buttonGroup.element.removeChild(this.rotateRight.element);
}
}
@@ -777,8 +783,12 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
this.removeAllHandlers();
- if (this.buttons) {
- this.buttons.destroy();
+ if (this.buttonGroup) {
+ this.buttonGroup.destroy();
+ } else if (this.customButtons) {
+ while (this.customButtons.length) {
+ this.customButtons.pop().destroy();
+ }
}
if (this.paging) {
@@ -1102,7 +1112,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
THIS[ this.hash ].fullPage = false;
// mouse will likely be outside now
- $.delegate( this, onContainerExit )( { } );
+ $.delegate( this, onContainerLeave )( { } );
}
@@ -1866,13 +1876,13 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
}
if ( useGroup ) {
- this.buttons = new $.ButtonGroup({
+ this.buttonGroup = new $.ButtonGroup({
buttons: buttons,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold
});
- this.navControl = this.buttons.element;
+ this.navControl = this.buttonGroup.element;
this.addHandler( 'open', $.delegate( this, lightUp ) );
if( this.toolbar ){
@@ -1886,6 +1896,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
{anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT}
);
}
+ } else {
+ this.customButtons = buttons;
}
}
@@ -2550,6 +2562,26 @@ function onBlur(){
}
+function onCanvasContextMenu( event ) {
+ /**
+ * Raised when a contextmenu event occurs in the {@link OpenSeadragon.Viewer#canvas} element.
+ *
+ * @event canvas-contextmenu
+ * @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 {Object} originalEvent - The original DOM event.
+ * @property {?Object} userData - Arbitrary subscriber-defined object.
+ */
+ this.raiseEvent( 'canvas-contextmenu', {
+ tracker: event.eventSource,
+ position: event.position,
+ originalEvent: event.originalEvent
+ });
+}
+
function onCanvasKeyDown( event ) {
var canvasKeyDownEventArgs = {
originalEvent: event.originalEvent,
@@ -2799,6 +2831,7 @@ function onCanvasDrag( event ) {
var canvasDragEventArgs = {
tracker: event.eventSource,
+ pointerType: event.pointerType,
position: event.position,
delta: event.delta,
speed: event.speed,
@@ -2816,13 +2849,14 @@ function onCanvasDrag( event ) {
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
+ * @property {String} pointerType - "mouse", "touch", "pen", etc.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
* @property {OpenSeadragon.Point} delta - The x,y components of the difference between start drag and end drag.
* @property {Number} speed - Current computed speed, in pixels per second.
* @property {Number} direction - Current computed direction, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.
* @property {Boolean} shift - True if the shift key was pressed during this event.
* @property {Object} originalEvent - The original DOM event.
- * @property {Boolean} preventDefaultAction - Set to true to prevent default drag behaviour. Default: false.
+ * @property {Boolean} preventDefaultAction - Set to true to prevent default drag to pan behaviour. Default: false.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'canvas-drag', canvasDragEventArgs);
@@ -2895,6 +2929,7 @@ function onCanvasDragEnd( event ) {
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
+ * @property {String} pointerType - "mouse", "touch", "pen", etc.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
* @property {Number} speed - Speed at the end of a drag gesture, in pixels per second.
* @property {Number} direction - Direction at the end of a drag gesture, expressed as an angle counterclockwise relative to the positive X axis (-pi to pi, in radians). Only valid if speed > 0.
@@ -2904,6 +2939,7 @@ function onCanvasDragEnd( event ) {
*/
this.raiseEvent('canvas-drag-end', {
tracker: event.eventSource,
+ pointerType: event.pointerType,
position: event.position,
speed: event.speed,
direction: event.direction,
@@ -2942,12 +2978,7 @@ function onCanvasEnter( event ) {
});
}
-function onCanvasExit( event ) {
-
- if (window.location !== window.parent.location){
- $.MouseTracker.resetAllMouseTrackers();
- }
-
+function onCanvasLeave( event ) {
/**
* Raised when a pointer leaves the {@link OpenSeadragon.Viewer#canvas} element.
*
@@ -3126,6 +3157,7 @@ function onCanvasPinch( event ) {
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
+ * @property {String} pointerType - "mouse", "touch", "pen", etc.
* @property {Array.} gesturePoints - Gesture points associated with the gesture. Velocity data can be found here.
* @property {OpenSeadragon.Point} lastCenter - The previous center point of the two pinch contact points relative to the tracked element.
* @property {OpenSeadragon.Point} center - The center point of the two pinch contact points relative to the tracked element.
@@ -3137,6 +3169,7 @@ function onCanvasPinch( event ) {
*/
this.raiseEvent('canvas-pinch', {
tracker: event.eventSource,
+ pointerType: event.pointerType,
gesturePoints: event.gesturePoints,
lastCenter: event.lastCenter,
center: event.center,
@@ -3225,6 +3258,7 @@ function onContainerEnter( event ) {
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
+ * @property {String} pointerType - "mouse", "touch", "pen", etc.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
* @property {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.
@@ -3235,6 +3269,7 @@ function onContainerEnter( event ) {
*/
this.raiseEvent( 'container-enter', {
tracker: event.eventSource,
+ pointerType: event.pointerType,
position: event.position,
buttons: event.buttons,
pointers: event.pointers,
@@ -3244,7 +3279,7 @@ function onContainerEnter( event ) {
});
}
-function onContainerExit( event ) {
+function onContainerLeave( event ) {
if ( event.pointers < 1 ) {
THIS[ this.hash ].mouseInside = false;
if ( !THIS[ this.hash ].animating ) {
@@ -3259,6 +3294,7 @@ function onContainerExit( event ) {
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
+ * @property {String} pointerType - "mouse", "touch", "pen", etc.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
* @property {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.
@@ -3269,6 +3305,7 @@ function onContainerExit( event ) {
*/
this.raiseEvent( 'container-exit', {
tracker: event.eventSource,
+ pointerType: event.pointerType,
position: event.position,
buttons: event.buttons,
pointers: event.pointers,
@@ -3499,8 +3536,10 @@ function doSingleZoomOut() {
function lightUp() {
- this.buttons.emulateEnter();
- this.buttons.emulateExit();
+ if (this.buttonGroup) {
+ this.buttonGroup.emulateEnter();
+ this.buttonGroup.emulateLeave();
+ }
}
@@ -3519,8 +3558,8 @@ function onFullScreen() {
this.setFullScreen( !this.isFullPage() );
}
// correct for no mouseout event on change
- if ( this.buttons ) {
- this.buttons.emulateExit();
+ if ( this.buttonGroup ) {
+ this.buttonGroup.emulateLeave();
}
this.fullPageButton.element.focus();
if ( this.viewport ) {
diff --git a/test/helpers/legacy.mouse.shim.js b/test/helpers/legacy.mouse.shim.js
index 3609ed85..19374147 100644
--- a/test/helpers/legacy.mouse.shim.js
+++ b/test/helpers/legacy.mouse.shim.js
@@ -6,20 +6,22 @@
$.MouseTracker.subscribeEvents = [ "click", "dblclick", "keypress", "focus", "blur", $.MouseTracker.wheelEventName ];
- if( $.MouseTracker.wheelEventName == "DOMMouseScroll" ) {
+ if( $.MouseTracker.wheelEventName === "DOMMouseScroll" ) {
// Older Firefox
$.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" );
}
$.MouseTracker.havePointerEvents = false;
- if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
- $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave" );
- $.MouseTracker.haveMouseEnter = true;
- } else {
- $.MouseTracker.subscribeEvents.push( "mouseover", "mouseout" );
- $.MouseTracker.haveMouseEnter = false;
+ $.MouseTracker.subscribeEvents.push( "mouseenter", "mouseleave", "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" );
+ $.MouseTracker.mousePointerId = "legacy-mouse";
+ // Legacy mouse events capture support (IE/Firefox only?)
+ $.MouseTracker.havePointerCapture = (function () {
+ var divElement = document.createElement( 'div' );
+ return $.isFunction( divElement.setCapture ) && $.isFunction( divElement.releaseCapture );
+ }());
+ if ( $.MouseTracker.havePointerCapture ) {
+ $.MouseTracker.subscribeEvents.push( "losecapture" );
}
- $.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/)
@@ -32,8 +34,5 @@
// Subscribe to these to prevent default gesture handling
$.MouseTracker.subscribeEvents.push( "gesturestart", "gesturechange" );
}
- $.MouseTracker.mousePointerId = "legacy-mouse";
- $.MouseTracker.maxTouchPoints = 10;
-
}(OpenSeadragon));
diff --git a/test/helpers/test.js b/test/helpers/test.js
index 8e7685d8..60931bba 100644
--- a/test/helpers/test.js
+++ b/test/helpers/test.js
@@ -37,7 +37,7 @@
};
$canvas
- .simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseenter' : 'mouseover', event )
+ .simulate( 'mouseenter', event )
.simulate( 'mousedown', event );
for ( var i = 0; i < args.dragCount; i++ ) {
event.clientX += args.dragDx;
@@ -47,7 +47,7 @@
}
$canvas
.simulate( 'mouseup', event )
- .simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', event );
+ .simulate( 'mouseleave', event );
},
// ----------
diff --git a/test/modules/controls.js b/test/modules/controls.js
index 57d827c9..0e6bdf7c 100644
--- a/test/modules/controls.js
+++ b/test/modules/controls.js
@@ -53,9 +53,9 @@
assert.ok(viewer.showZoomControl, 'showZoomControl should be on');
assert.ok(!!viewer.zoomInButton, "zoomIn button should not be null");
assert.ok(!!viewer.zoomOutButton, "zoomOut button should not be null");
- assert.notEqual(viewer.buttons.buttons.indexOf(viewer.zoomInButton), -1,
+ assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.zoomInButton), -1,
"The zoomIn button should be present");
- assert.notEqual(viewer.buttons.buttons.indexOf(viewer.zoomOutButton), -1,
+ assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.zoomOutButton), -1,
"The zoomOut button should be present");
var oldZoom = viewer.viewport.getZoom();
@@ -108,7 +108,7 @@
viewer.removeHandler('open', openHandler);
assert.ok(viewer.showHomeControl, 'showHomeControl should be on');
assert.ok(!!viewer.homeButton, "Home button should not be null");
- assert.notEqual(viewer.buttons.buttons.indexOf(viewer.homeButton), -1,
+ assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.homeButton), -1,
"The home button should be present");
viewer.viewport.zoomBy(1.1);
@@ -167,7 +167,7 @@
viewer.removeHandler('open', openHandler);
assert.ok(viewer.showHomeControl, 'showFullPageControl should be on');
assert.ok(!!viewer.fullPageButton, "FullPage button should not be null");
- assert.notEqual(viewer.buttons.buttons.indexOf(viewer.fullPageButton), -1,
+ assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.fullPageButton), -1,
"The full page button should be present");
assert.ok(!viewer.isFullPage(), "OSD should not be in full page.");
@@ -223,9 +223,9 @@
assert.ok(viewer.drawer, 'Drawer exists');
assert.ok(viewer.drawer.canRotate(), 'drawer.canRotate needs to be true');
assert.ok(viewer.showRotationControl, 'showRotationControl should be true');
- assert.notEqual(viewer.buttons.buttons.indexOf(viewer.rotateLeftButton), -1,
+ assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.rotateLeftButton), -1,
"rotateLeft should be found");
- assert.notEqual(viewer.buttons.buttons.indexOf(viewer.rotateRightButton), -1,
+ assert.notEqual(viewer.buttonGroup.buttons.indexOf(viewer.rotateRightButton), -1,
"rotateRight should be found");
// Now simulate the left/right button clicks.
diff --git a/test/modules/events.js b/test/modules/events.js
index 849e86f9..d07a3eea 100644
--- a/test/modules/events.js
+++ b/test/modules/events.js
@@ -32,7 +32,7 @@
offset = $canvas.offset(),
tracker = viewer.innerTracker,
origEnterHandler,
- origExitHandler,
+ origLeaveHandler,
origPressHandler,
origReleaseHandler,
origNonPrimaryPressHandler,
@@ -43,7 +43,7 @@
origDragHandler,
origDragEndHandler,
enterCount,
- exitCount,
+ leaveCount,
pressCount,
releaseCount,
rightPressCount,
@@ -71,11 +71,11 @@
return true;
}
};
- origExitHandler = tracker.exitHandler;
- tracker.exitHandler = function ( event ) {
- exitCount++;
- if (origExitHandler) {
- return origExitHandler( event );
+ origLeaveHandler = tracker.leaveHandler;
+ tracker.leaveHandler = function ( event ) {
+ leaveCount++;
+ if (origLeaveHandler) {
+ return origLeaveHandler( event );
} else {
return true;
}
@@ -182,7 +182,7 @@
var unhookViewerHandlers = function () {
tracker.enterHandler = origEnterHandler;
- tracker.exitHandler = origExitHandler;
+ tracker.leaveHandler = origLeaveHandler;
tracker.pressHandler = origPressHandler;
tracker.releaseHandler = origReleaseHandler;
tracker.moveHandler = origMoveHandler;
@@ -195,21 +195,21 @@
var simulateEnter = function (x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
- $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseenter' : 'mouseover', simEvent );
+ $canvas.simulate( 'mouseenter', simEvent );
};
var simulateLeave = function (x, y) {
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
simEvent.relatedTarget = document.body;
- $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent );
+ $canvas.simulate( 'mouseleave', simEvent );
};
//var simulateLeaveFrame = function (x, y) {
// simEvent.clientX = offset.left + x;
// simEvent.clientY = offset.top + y;
// simEvent.relatedTarget = document.getElementsByTagName("html")[0];
- // $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent );
+ // $canvas.simulate( 'mouseleave', simEvent );
//};
var simulateDown = function (x, y) {
@@ -256,7 +256,7 @@
clientY: offset.top
};
enterCount = 0;
- exitCount = 0;
+ leaveCount = 0;
pressCount = 0;
releaseCount = 0;
rightPressCount = 0;
@@ -280,8 +280,8 @@
if ('enterCount' in expected) {
assert.equal( enterCount, expected.enterCount, expected.description + 'enterHandler event count matches expected (' + expected.enterCount + ')' );
}
- if ('exitCount' in expected) {
- assert.equal( exitCount, expected.exitCount, expected.description + 'exitHandler event count matches expected (' + expected.exitCount + ')' );
+ if ('leaveCount' in expected) {
+ assert.equal( leaveCount, expected.leaveCount, expected.description + 'leaveHandler event count matches expected (' + expected.leaveCount + ')' );
}
if ('pressCount' in expected) {
assert.equal( pressCount, expected.pressCount, expected.description + 'pressHandler event count matches expected (' + expected.pressCount + ')' );
@@ -355,7 +355,7 @@
assessGestureExpectations({
description: 'enter-move-release (release in tracked element, press in unknown element): ',
enterCount: 1,
- exitCount: 0,
+ leaveCount: 0,
pressCount: 0,
releaseCount: 1,
rightPressCount: 0,
@@ -375,16 +375,16 @@
});
simulateLeave(-1, -1); // flush tracked pointer
- // enter-move-exit (fly-over)
+ // enter-move-leave (fly-over)
resetForAssessment();
simulateEnter(0, 0);
simulateMove(1, 1, 10);
simulateMove(-1, -1, 10);
simulateLeave(-1, -1);
assessGestureExpectations({
- description: 'enter-move-exit (fly-over): ',
+ description: 'enter-move-leave (fly-over): ',
enterCount: 1,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 0,
releaseCount: 0,
rightPressCount: 0,
@@ -403,15 +403,15 @@
//quickClick: false
});
- // move-exit (fly-over, no enter event)
+ // move-leave (fly-over, no enter event)
resetForAssessment();
simulateMove(1, 1, 10);
simulateMove(-1, -1, 10);
simulateLeave(-1, -1);
assessGestureExpectations({
- description: 'move-exit (fly-over, no enter event): ',
+ description: 'move-leave (fly-over, no enter event): ',
enterCount: 0,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 0,
releaseCount: 0,
rightPressCount: 0,
@@ -430,7 +430,7 @@
//quickClick: false
});
- // enter-press-release-press-release-exit (primary/left double click)
+ // enter-press-release-press-release-leave (primary/left double click)
resetForAssessment();
simulateEnter(0, 0);
simulateDown(0, 0);
@@ -439,9 +439,9 @@
simulateUp(0, 0);
simulateLeave(-1, -1);
assessGestureExpectations({
- description: 'enter-press-release-press-release-exit (primary/left double click): ',
+ description: 'enter-press-release-press-release-leave (primary/left double click): ',
enterCount: 1,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 2,
releaseCount: 2,
rightPressCount: 0,
@@ -452,7 +452,7 @@
clickCount: 2,
dblClickCount: 1,
dragCount: 0,
- dragEndCount: 0,
+ dragEndCount: 2, // v2.5.0+ drag-end event now fired even if pointer didn't move (#1459)
insideElementPressed: true,
insideElementReleased: true,
contacts: 0,
@@ -460,16 +460,16 @@
//quickClick: true
});
- // enter-press-release-exit (primary/left click)
+ // enter-press-release-leave (primary/left click)
resetForAssessment();
simulateEnter(0, 0);
simulateDown(0, 0);
simulateUp(0, 0);
simulateLeave(-1, -1);
assessGestureExpectations({
- description: 'enter-press-release-exit (primary/left click): ',
+ description: 'enter-press-release-leave (primary/left click): ',
enterCount: 1,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 1,
releaseCount: 1,
rightPressCount: 0,
@@ -480,7 +480,7 @@
clickCount: 1,
dblClickCount: 0,
dragCount: 0,
- dragEndCount: 0,
+ dragEndCount: 1, // v2.5.0+ drag-end event now fired even if pointer didn't move (#1459)
insideElementPressed: true,
insideElementReleased: true,
contacts: 0,
@@ -488,16 +488,16 @@
quickClick: true
});
- // enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click)
+ // enter-nonprimarypress-nonprimaryrelease-leave (secondary/right click)
resetForAssessment();
simulateEnter(0, 0);
simulateNonPrimaryDown(0, 0, 2);
simulateNonPrimaryUp(0, 0, 2);
simulateLeave(-1, -1);
assessGestureExpectations({
- description: 'enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click): ',
+ description: 'enter-nonprimarypress-nonprimaryrelease-leave (secondary/right click): ',
enterCount: 1,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 0,
releaseCount: 0,
rightPressCount: 1,
@@ -516,16 +516,16 @@
//quickClick: true
});
- // enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click)
+ // enter-nonprimarypress-nonprimaryrelease-leave (aux/middle click)
resetForAssessment();
simulateEnter(0, 0);
simulateNonPrimaryDown(0, 0, 1);
simulateNonPrimaryUp(0, 0, 1);
simulateLeave(-1, -1);
assessGestureExpectations({
- description: 'enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click): ',
+ description: 'enter-nonprimarypress-nonprimaryrelease-leave (aux/middle click): ',
enterCount: 1,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 0,
releaseCount: 0,
rightPressCount: 0,
@@ -544,7 +544,7 @@
//quickClick: true
});
- // enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element)
+ // enter-nonprimarypress-move-nonprimaryrelease-move-leave (secondary/right button drag, release in tracked element)
resetForAssessment();
simulateEnter(0, 0);
simulateNonPrimaryDown(0, 0, 2);
@@ -553,9 +553,9 @@
simulateMove(-1, -1, 100);
simulateLeave(-1, -1);
assessGestureExpectations({
- description: 'enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element): ',
+ description: 'enter-nonprimarypress-move-nonprimaryrelease-move-leave (secondary/right button drag, release in tracked element): ',
enterCount: 1,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 0,
releaseCount: 0,
rightPressCount: 1,
@@ -574,7 +574,7 @@
//quickClick: false
});
- // enter-press-move-release-move-exit (drag, release in tracked element)
+ // enter-press-move-release-move-leave (drag, release in tracked element)
resetForAssessment();
simulateEnter(0, 0);
simulateDown(0, 0);
@@ -583,9 +583,9 @@
simulateMove(-1, -1, 100);
simulateLeave(-1, -1);
assessGestureExpectations({
- description: 'enter-press-move-release-move-exit (drag, release in tracked element): ',
+ description: 'enter-press-move-release-move-leave (drag, release in tracked element): ',
enterCount: 1,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 1,
releaseCount: 1,
rightPressCount: 0,
@@ -604,7 +604,7 @@
quickClick: false
});
- // enter-press-move-exit-move-release (drag, release outside tracked element)
+ // enter-press-move-leave-move-release (drag, release outside tracked element)
resetForAssessment();
simulateEnter(0, 0);
simulateDown(0, 0);
@@ -614,9 +614,9 @@
simulateMove(-1, -1, 5);
simulateUp(-5, -5);
assessGestureExpectations({
- description: 'enter-press-move-exit-move-release (drag, release outside tracked element): ',
+ description: 'enter-press-move-leave-move-release (drag, release outside tracked element): ',
enterCount: 1,
- exitCount: 1,
+ leaveCount: 1,
pressCount: 1,
releaseCount: 1,
rightPressCount: 0,
@@ -635,7 +635,7 @@
quickClick: false
});
- //// enter-press-move-exit-move-release-outside (drag, release outside iframe)
+ //// enter-press-move-leave-move-release-outside (drag, release outside iframe)
//resetForAssessment();
//simulateEnter(0, 0);
//simulateDown(0, 0);
@@ -644,9 +644,9 @@
//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,
+ // description: 'enter-press-move-leave-move-release-outside (drag, release outside iframe): ',
+ // enterCount: 1,
+ // leaveCount: 1,
// pressCount: 1,
// releaseCount: 1,
// rightPressCount: 0,
@@ -953,7 +953,7 @@
dragEndHandler: onMouseTrackerDragEnd,
releaseHandler: onMouseTrackerRelease,
clickHandler: onMouseTrackerClick,
- exitHandler: onMouseTrackerExit
+ leaveHandler: onMouseTrackerLeave
} );
var event = {
@@ -1050,7 +1050,7 @@
checkOriginalEventReceived( event );
};
- var onMouseTrackerExit = function ( event ) {
+ var onMouseTrackerLeave = function ( event ) {
checkOriginalEventReceived( event );
mouseTracker.destroy();
diff --git a/test/modules/navigator.js b/test/modules/navigator.js
index e7f5f327..e55c5400 100644
--- a/test/modules/navigator.js
+++ b/test/modules/navigator.js
@@ -216,19 +216,34 @@
clientY: offset.top + locationY
};
$canvas
- .simulate(OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseenter' : 'mouseover', event)
+ .simulate('mouseenter', event)
.simulate('mousedown', event)
.simulate('mouseup', event);
};
var simulateNavigatorDrag = function (viewer, distanceX, distanceY) {
- var $canvas = $(viewer.element).find('.displayregion'),
- event = {
- dx: Math.floor(distanceX),
- dy: Math.floor(distanceY)
- };
- $canvas
- .simulate('drag', event);
+ var $canvas = $(viewer.element).find('.openseadragon-canvas'),
+ offset = $canvas.offset(),
+ event = {};
+
+ event.clientX = offset.left + 1;
+ event.clientY = offset.top + 1;
+ $canvas.simulate( 'mouseenter', event );
+
+ event.button = 0;
+ $canvas.simulate( 'mousedown', event );
+
+ event.clientX += distanceX;
+ event.clientY += distanceY;
+ $canvas.simulate( 'mousemove', event );
+
+ event.button = 0;
+ $canvas.simulate( 'mouseup', event );
+
+ event.clientX = offset.left - 1;
+ event.clientY = offset.top - 1;
+ event.relatedTarget = document.body;
+ $canvas.simulate( 'mouseleave', event );
};
var dragNavigatorBackToCenter = function () {