Merge branch 'master' into collections

This commit is contained in:
Ian Gilman 2015-01-13 14:11:52 -08:00
commit 17b8f356ed
5 changed files with 626 additions and 139 deletions

View File

@ -43,7 +43,9 @@ OPENSEADRAGON CHANGELOG
1.2.1: (in progress) 1.2.1: (in progress)
* Added preserveOverlays option (#561) * Added preserveOverlays option (#561)
* Fixed: DZI tilesource was broken (#563) * Fixed: DZI tilesource was broken on IE8/IE9 (#563)
* Exposed secondary pointer button (middle, right, etc.) events from MouseTracker and through viewer (#479)
* MouseTracker - Improved IE 8 compatibility (#562)
1.2.0: 1.2.0:

View File

@ -72,8 +72,12 @@
* An optional handler for pointer exit. * An optional handler for pointer exit.
* @param {OpenSeadragon.EventHandler} [options.pressHandler=null] * @param {OpenSeadragon.EventHandler} [options.pressHandler=null]
* An optional handler for pointer press. * An optional handler for pointer press.
* @param {OpenSeadragon.EventHandler} [options.nonPrimaryPressHandler=null]
* An optional handler for pointer non-primary button press.
* @param {OpenSeadragon.EventHandler} [options.releaseHandler=null] * @param {OpenSeadragon.EventHandler} [options.releaseHandler=null]
* An optional handler for pointer release. * An optional handler for pointer release.
* @param {OpenSeadragon.EventHandler} [options.nonPrimaryReleaseHandler=null]
* An optional handler for pointer non-primary button release.
* @param {OpenSeadragon.EventHandler} [options.moveHandler=null] * @param {OpenSeadragon.EventHandler} [options.moveHandler=null]
* An optional handler for pointer move. * An optional handler for pointer move.
* @param {OpenSeadragon.EventHandler} [options.scrollHandler=null] * @param {OpenSeadragon.EventHandler} [options.scrollHandler=null]
@ -150,7 +154,9 @@
this.enterHandler = options.enterHandler || null; this.enterHandler = options.enterHandler || null;
this.exitHandler = options.exitHandler || null; this.exitHandler = options.exitHandler || null;
this.pressHandler = options.pressHandler || null; this.pressHandler = options.pressHandler || null;
this.nonPrimaryPressHandler = options.nonPrimaryPressHandler || null;
this.releaseHandler = options.releaseHandler || null; this.releaseHandler = options.releaseHandler || null;
this.nonPrimaryReleaseHandler = options.nonPrimaryReleaseHandler || null;
this.moveHandler = options.moveHandler || null; this.moveHandler = options.moveHandler || null;
this.scrollHandler = options.scrollHandler || null; this.scrollHandler = options.scrollHandler || null;
this.clickHandler = options.clickHandler || null; this.clickHandler = options.clickHandler || null;
@ -183,6 +189,8 @@
DOMMouseScroll: function ( event ) { onMouseWheel( _this, event ); }, DOMMouseScroll: function ( event ) { onMouseWheel( _this, event ); },
MozMousePixelScroll: 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 ); }, mouseover: function ( event ) { onMouseOver( _this, event ); },
mouseout: function ( event ) { onMouseOut( _this, event ); }, mouseout: function ( event ) { onMouseOut( _this, event ); },
mousedown: function ( event ) { onMouseDown( _this, event ); }, mousedown: function ( event ) { onMouseDown( _this, event ); },
@ -390,6 +398,34 @@
*/ */
pressHandler: function () { }, pressHandler: function () { },
/**
* Implement or assign implementation to these handlers during or after
* calling the constructor.
* @function
* @param {Object} event
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
* "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
* @param {Number} event.button
* Button which caused the event.
* -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
* @param {Number} event.buttons
* Current buttons pressed.
* Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.
* @param {Boolean} event.isTouchEvent
* True if the original event is a touch event, otherwise false. <span style="color:red;">Deprecated. Use pointerType and/or originalEvent instead.</span>
* @param {Object} event.originalEvent
* The original event object.
* @param {Boolean} event.preventDefaultAction
* Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.
* @param {Object} event.userData
* Arbitrary user-defined object.
*/
nonPrimaryPressHandler: function () { },
/** /**
* Implement or assign implementation to these handlers during or after * Implement or assign implementation to these handlers during or after
* calling the constructor. * calling the constructor.
@ -420,6 +456,34 @@
*/ */
releaseHandler: function () { }, releaseHandler: function () { },
/**
* Implement or assign implementation to these handlers during or after
* calling the constructor.
* @function
* @param {Object} event
* @param {OpenSeadragon.MouseTracker} event.eventSource
* A reference to the tracker instance.
* @param {String} event.pointerType
* "mouse", "touch", "pen", etc.
* @param {OpenSeadragon.Point} event.position
* The position of the event relative to the tracked element.
* @param {Number} event.button
* Button which caused the event.
* -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
* @param {Number} event.buttons
* Current buttons pressed.
* Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.
* @param {Boolean} event.isTouchEvent
* True if the original event is a touch event, otherwise false. <span style="color:red;">Deprecated. Use pointerType and/or originalEvent instead.</span>
* @param {Object} event.originalEvent
* The original event object.
* @param {Boolean} event.preventDefaultAction
* Set to true to prevent the tracker subscriber from performing its default action (subscriber implementation dependent). Default: false.
* @param {Object} event.userData
* Arbitrary user-defined object.
*/
nonPrimaryReleaseHandler: function () { },
/** /**
* Implement or assign implementation to these handlers during or after * Implement or assign implementation to these handlers during or after
* calling the constructor. * calling the constructor.
@ -816,6 +880,7 @@
if ( window.PointerEvent ) { if ( window.PointerEvent ) {
// IE11 and other W3C Pointer Event implementations (see http://www.w3.org/TR/pointerevents) // 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.subscribeEvents.push( "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel" );
$.MouseTracker.unprefixedPointerEvents = true; $.MouseTracker.unprefixedPointerEvents = true;
if( navigator.maxTouchPoints ) { if( navigator.maxTouchPoints ) {
@ -827,6 +892,7 @@
$.MouseTracker.haveMouseEnter = false; $.MouseTracker.haveMouseEnter = false;
} else if ( window.MSPointerEvent ) { } else if ( window.MSPointerEvent ) {
// IE10 // IE10
$.MouseTracker.havePointerEvents = true;
$.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" ); $.MouseTracker.subscribeEvents.push( "MSPointerOver", "MSPointerOut", "MSPointerDown", "MSPointerUp", "MSPointerMove", "MSPointerCancel" );
$.MouseTracker.unprefixedPointerEvents = false; $.MouseTracker.unprefixedPointerEvents = false;
if( navigator.msMaxTouchPoints ) { if( navigator.msMaxTouchPoints ) {
@ -838,8 +904,15 @@
$.MouseTracker.haveMouseEnter = false; $.MouseTracker.haveMouseEnter = false;
} else { } else {
// Legacy W3C mouse events // Legacy W3C mouse events
$.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" ); $.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.haveMouseEnter = false;
}
$.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" );
if ( 'ontouchstart' in window ) { if ( 'ontouchstart' in window ) {
// iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505) // iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505)
$.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" );
@ -1151,7 +1224,14 @@
function getCaptureEventParams( tracker, pointerType ) { function getCaptureEventParams( tracker, pointerType ) {
var delegate = THIS[ tracker.hash ]; var delegate = THIS[ tracker.hash ];
if ( pointerType === 'mouse' ) { if ( pointerType === 'pointerevent' ) {
return {
upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp',
upHandler: delegate.pointerupcaptured,
moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove',
moveHandler: delegate.pointermovecaptured
};
} else if ( pointerType === 'mouse' ) {
return { return {
upName: 'mouseup', upName: 'mouseup',
upHandler: delegate.mouseupcaptured, upHandler: delegate.mouseupcaptured,
@ -1166,12 +1246,7 @@
moveHandler: delegate.touchmovecaptured moveHandler: delegate.touchmovecaptured
}; };
} else { } else {
return { throw new Error( "MouseTracker.getCaptureEventParams: Unknown pointer type." );
upName: $.MouseTracker.unprefixedPointerEvents ? 'pointerup' : 'MSPointerUp',
upHandler: delegate.pointerupcaptured,
moveName: $.MouseTracker.unprefixedPointerEvents ? 'pointermove' : 'MSPointerMove',
moveHandler: delegate.pointermovecaptured
};
} }
} }
@ -1181,14 +1256,17 @@
* @inner * @inner
*/ */
function capturePointer( tracker, pointerType ) { function capturePointer( tracker, pointerType ) {
var delegate = THIS[ tracker.hash ], var pointsList = tracker.getActivePointersListByType( pointerType ),
pointsList = tracker.getActivePointersListByType( pointerType ), eventParams;
eventParams = getCaptureEventParams( tracker, pointerType );
pointsList.captureCount++; pointsList.captureCount++;
if ( pointsList.captureCount === 1 ) { if ( pointsList.captureCount === 1 ) {
// We emulate mouse capture by hanging listeners on the window object. 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) // (Note we listen on the capture phase so the captured handlers will get called first)
$.addEvent( $.addEvent(
$.MouseTracker.captureElement, $.MouseTracker.captureElement,
@ -1204,6 +1282,7 @@
); );
} }
} }
}
/** /**
@ -1212,14 +1291,17 @@
* @inner * @inner
*/ */
function releasePointer( tracker, pointerType ) { function releasePointer( tracker, pointerType ) {
var delegate = THIS[ tracker.hash ], var pointsList = tracker.getActivePointersListByType( pointerType ),
pointsList = tracker.getActivePointersListByType( pointerType ), eventParams;
eventParams = getCaptureEventParams( tracker, pointerType );
pointsList.captureCount--; pointsList.captureCount--;
if ( pointsList.captureCount === 0 ) { if ( pointsList.captureCount === 0 ) {
// We emulate mouse capture by hanging listeners on the window object. 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) // (Note we listen on the capture phase so the captured handlers will get called first)
$.removeEvent( $.removeEvent(
$.MouseTracker.captureElement, $.MouseTracker.captureElement,
@ -1235,6 +1317,7 @@
); );
} }
} }
}
/** /**
@ -1506,20 +1589,40 @@
} }
/**
* Only used on IE 8
*
* @private
* @inner
*/
function onMouseEnter( tracker, event ) {
event = $.getEvent( event );
handleMouseEnter( tracker, event );
}
/** /**
* @private * @private
* @inner * @inner
*/ */
function onMouseOver( tracker, event ) { function onMouseOver( tracker, event ) {
var gPoint;
event = $.getEvent( event ); event = $.getEvent( event );
if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {
return; return;
} }
gPoint = { handleMouseEnter( tracker, event );
}
/**
* @private
* @inner
*/
function handleMouseEnter( tracker, event ) {
var gPoint = {
id: $.MouseTracker.mousePointerId, id: $.MouseTracker.mousePointerId,
type: 'mouse', type: 'mouse',
isPrimary: true, isPrimary: true,
@ -1531,20 +1634,40 @@
} }
/**
* Only used on IE 8
*
* @private
* @inner
*/
function onMouseLeave( tracker, event ) {
event = $.getEvent( event );
handleMouseExit( tracker, event );
}
/** /**
* @private * @private
* @inner * @inner
*/ */
function onMouseOut( tracker, event ) { function onMouseOut( tracker, event ) {
var gPoint;
event = $.getEvent( event ); event = $.getEvent( event );
if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) { if ( this === event.relatedTarget || isParentChild( event.currentTarget, event.relatedTarget ) ) {
return; return;
} }
gPoint = { handleMouseExit( tracker, event );
}
/**
* @private
* @inner
*/
function handleMouseExit( tracker, event ) {
var gPoint = {
id: $.MouseTracker.mousePointerId, id: $.MouseTracker.mousePointerId,
type: 'mouse', type: 'mouse',
isPrimary: true, isPrimary: true,
@ -1556,6 +1679,31 @@
} }
/**
* Returns a W3C DOM level 3 standard button value given an event.button property:
* -1 == none, 0 == primary/left, 1 == middle, 2 == secondary/right, 3 == X1/back, 4 == X2/forward, 5 == eraser (pen)
* @private
* @inner
*/
function getStandardizedButton( button ) {
if ( $.Browser.vendor === $.BROWSERS.IE && $.Browser.version < 9 ) {
// On IE 8, 0 == none, 1 == left, 2 == right, 3 == left and right, 4 == middle, 5 == left and middle, 6 == right and middle, 7 == all three
// TODO: Support chorded (multiple) button presses on IE 8?
if ( button === 1 ) {
return 0;
} else if ( button === 2 ) {
return 2;
} else if ( button === 4 ) {
return 1;
} else {
return -1;
}
} else {
return button;
}
}
/** /**
* @private * @private
* @inner * @inner
@ -1573,7 +1721,7 @@
currentTime: $.now() currentTime: $.now()
}; };
if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { if ( updatePointersDown( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {
$.stopEvent( event ); $.stopEvent( event );
capturePointer( tracker, 'mouse' ); capturePointer( tracker, 'mouse' );
} }
@ -1622,11 +1770,12 @@
currentTime: $.now() currentTime: $.now()
}; };
if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { if ( updatePointersUp( tracker, event, [ gPoint ], getStandardizedButton( event.button ) ) ) {
releasePointer( tracker, 'mouse' ); releasePointer( tracker, 'mouse' );
} }
} }
/** /**
* @private * @private
* @inner * @inner
@ -1960,7 +2109,7 @@
if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) { if ( updatePointersDown( tracker, event, [ gPoint ], event.button ) ) {
$.stopEvent( event ); $.stopEvent( event );
capturePointer( tracker, 'pointer' ); capturePointer( tracker, gPoint.type );
} }
if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) { if ( tracker.clickHandler || tracker.dblClickHandler || tracker.pressHandler || tracker.dragHandler || tracker.dragEndHandler || tracker.pinchHandler ) {
@ -2010,7 +2159,7 @@
}; };
if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) { if ( updatePointersUp( tracker, event, [ gPoint ], event.button ) ) {
releasePointer( tracker, 'pointer' ); releasePointer( tracker, gPoint.type );
} }
} }
@ -2286,7 +2435,7 @@
* @param {Array.<OpenSeadragon.MouseTracker.GesturePoint>} gPoints * @param {Array.<OpenSeadragon.MouseTracker.GesturePoint>} gPoints
* Gesture points associated with the event. * Gesture points associated with the event.
* @param {Number} buttonChanged * @param {Number} buttonChanged
* The button involved in the event: -1: none, 0: primary, 1: aux, 2: secondary, 3: X1, 4: X2, 5: pen eraser. * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
* Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, * 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. * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.
* *
@ -2303,6 +2452,27 @@
if ( typeof event.buttons !== 'undefined' ) { if ( typeof event.buttons !== 'undefined' ) {
pointsList.buttons = event.buttons; pointsList.buttons = event.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 { } else {
if ( buttonChanged === 0 ) { if ( buttonChanged === 0 ) {
// Primary // Primary
@ -2324,10 +2494,30 @@
pointsList.buttons |= 32; pointsList.buttons |= 32;
} }
} }
}
// Only capture and track primary button, pen, and touch contacts // Only capture and track primary button, pen, and touch contacts
//if ( buttonChanged !== 0 ) { if ( buttonChanged !== 0 ) {
if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the commented line above // Aux Press
if ( tracker.nonPrimaryPressHandler ) {
propagate = tracker.nonPrimaryPressHandler(
{
eventSource: tracker,
pointerType: gPoints[ 0 ].type,
position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),
button: buttonChanged,
buttons: pointsList.buttons,
isTouchEvent: gPoints[ 0 ].type === 'touch',
originalEvent: event,
preventDefaultAction: false,
userData: tracker.userData
}
);
if ( propagate === false ) {
$.cancelEvent( event );
}
}
return false; return false;
} }
@ -2407,7 +2597,7 @@
* @param {Array.<OpenSeadragon.MouseTracker.GesturePoint>} gPoints * @param {Array.<OpenSeadragon.MouseTracker.GesturePoint>} gPoints
* Gesture points associated with the event. * Gesture points associated with the event.
* @param {Number} buttonChanged * @param {Number} buttonChanged
* The button involved in the event: -1: none, 0: primary, 1: aux, 2: secondary, 3: X1, 4: X2, 5: pen eraser. * The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
* Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model, * 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. * only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.
* *
@ -2430,6 +2620,27 @@
if ( typeof event.buttons !== 'undefined' ) { if ( typeof event.buttons !== 'undefined' ) {
pointsList.buttons = event.buttons; pointsList.buttons = event.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 { } else {
if ( buttonChanged === 0 ) { if ( buttonChanged === 0 ) {
// Primary // Primary
@ -2451,10 +2662,30 @@
pointsList.buttons ^= ~32; pointsList.buttons ^= ~32;
} }
} }
}
// Only capture and track primary button, pen, and touch contacts // Only capture and track primary button, pen, and touch contacts
//if ( buttonChanged !== 0 ) { if ( buttonChanged !== 0 ) {
if ( buttonChanged !== 0 && buttonChanged !== 1 ) { //TODO Remove this IE8 compatibility and use the commented line above // Aux Release
if ( tracker.nonPrimaryReleaseHandler ) {
propagate = tracker.nonPrimaryReleaseHandler(
{
eventSource: tracker,
pointerType: gPoints[ 0 ].type,
position: getPointRelativeToAbsolute( gPoints[ 0 ].currentPos, tracker.element ),
button: buttonChanged,
buttons: pointsList.buttons,
isTouchEvent: gPoints[ 0 ].type === 'touch',
originalEvent: event,
preventDefaultAction: false,
userData: tracker.userData
}
);
if ( propagate === false ) {
$.cancelEvent( event );
}
}
return false; return false;
} }

View File

@ -352,6 +352,8 @@ $.Viewer = function( options ) {
dragHandler: $.delegate( this, onCanvasDrag ), dragHandler: $.delegate( this, onCanvasDrag ),
dragEndHandler: $.delegate( this, onCanvasDragEnd ), dragEndHandler: $.delegate( this, onCanvasDragEnd ),
releaseHandler: $.delegate( this, onCanvasRelease ), releaseHandler: $.delegate( this, onCanvasRelease ),
nonPrimaryPressHandler: $.delegate( this, onCanvasNonPrimaryPress ),
nonPrimaryReleaseHandler: $.delegate( this, onCanvasNonPrimaryRelease ),
scrollHandler: $.delegate( this, onCanvasScroll ), scrollHandler: $.delegate( this, onCanvasScroll ),
pinchHandler: $.delegate( this, onCanvasPinch ) pinchHandler: $.delegate( this, onCanvasPinch )
}).setTracking( this.mouseNavEnabled ? true : false ); // default state }).setTracking( this.mouseNavEnabled ? true : false ); // default state
@ -2419,7 +2421,7 @@ function onCanvasDragEnd( event ) {
function onCanvasRelease( event ) { function onCanvasRelease( event ) {
/** /**
* Raised when the mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element. * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#canvas} element.
* *
* @event canvas-release * @event canvas-release
* @memberof OpenSeadragon.Viewer * @memberof OpenSeadragon.Viewer
@ -2441,6 +2443,62 @@ function onCanvasRelease( event ) {
}); });
} }
function onCanvasNonPrimaryPress( event ) {
/**
* Raised when any non-primary pointer button is pressed on the {@link OpenSeadragon.Viewer#canvas} element.
*
* @event canvas-nonprimary-press
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
* @property {String} pointerType - "mouse", "touch", "pen", etc.
* @property {Number} button - Button which caused the event.
* -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
* @property {Number} buttons - Current buttons pressed.
* Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'canvas-nonprimary-press', {
tracker: event.eventSource,
position: event.position,
pointerType: event.pointerType,
button: event.button,
buttons: event.buttons,
originalEvent: event.originalEvent
});
}
function onCanvasNonPrimaryRelease( event ) {
/**
* Raised when any non-primary pointer button is released on the {@link OpenSeadragon.Viewer#canvas} element.
*
* @event canvas-nonprimary-release
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
* @property {String} pointerType - "mouse", "touch", "pen", etc.
* @property {Number} button - Button which caused the event.
* -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
* @property {Number} buttons - Current buttons pressed.
* Combination of bit flags 0: none, 1: primary (or touch contact), 2: secondary, 4: aux (often middle), 8: X1 (often back), 16: X2 (often forward), 32: pen eraser.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'canvas-nonprimary-release', {
tracker: event.eventSource,
position: event.position,
pointerType: event.pointerType,
button: event.button,
buttons: event.buttons,
originalEvent: event.originalEvent
});
}
function onCanvasPinch( event ) { function onCanvasPinch( event ) {
var gestureSettings, var gestureSettings,
centerPt, centerPt,
@ -2590,7 +2648,7 @@ function onContainerRelease( event ) {
} }
} }
/** /**
* Raised when the mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#container} element. * Raised when the primary mouse button is released or touch ends on the {@link OpenSeadragon.Viewer#container} element.
* *
* @event container-release * @event container-release
* @memberof OpenSeadragon.Viewer * @memberof OpenSeadragon.Viewer

View File

@ -11,8 +11,15 @@
$.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" ); $.MouseTracker.subscribeEvents.push( "MozMousePixelScroll" );
} }
$.MouseTracker.subscribeEvents.push( "mouseover", "mouseout", "mousedown", "mouseup", "mousemove" ); $.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.haveMouseEnter = false;
}
$.MouseTracker.subscribeEvents.push( "mousedown", "mouseup", "mousemove" );
if ( 'ontouchstart' in window ) { if ( 'ontouchstart' in window ) {
// iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505) // iOS, Android, and other W3c Touch Event implementations (see http://www.w3.org/TR/2011/WD-touch-events-20110505)
$.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" ); $.MouseTracker.subscribeEvents.push( "touchstart", "touchend", "touchmove", "touchcancel" );
@ -33,4 +40,5 @@
$.MouseTracker.mousePointerId = "legacy-mouse"; $.MouseTracker.mousePointerId = "legacy-mouse";
$.MouseTracker.maxTouchPoints = 10; $.MouseTracker.maxTouchPoints = 10;
}(OpenSeadragon)); }(OpenSeadragon));

View File

@ -35,6 +35,8 @@
origExitHandler, origExitHandler,
origPressHandler, origPressHandler,
origReleaseHandler, origReleaseHandler,
origNonPrimaryPressHandler,
origNonPrimaryReleaseHandler,
origMoveHandler, origMoveHandler,
origClickHandler, origClickHandler,
origDblClickHandler, origDblClickHandler,
@ -44,6 +46,10 @@
exitCount, exitCount,
pressCount, pressCount,
releaseCount, releaseCount,
rightPressCount,
rightReleaseCount,
middlePressCount,
middleReleaseCount,
moveCount, moveCount,
clickCount, clickCount,
dblClickCount, dblClickCount,
@ -94,6 +100,36 @@
return true; return true;
} }
}; };
origNonPrimaryPressHandler = tracker.nonPrimaryPressHandler;
tracker.nonPrimaryPressHandler = function ( event ) {
if (event.button === 0) {
pressCount++;
} else if (event.button === 1) {
middlePressCount++;
} else if (event.button === 2) {
rightPressCount++;
}
if (origNonPrimaryPressHandler) {
return origNonPrimaryPressHandler( event );
} else {
return true;
}
};
origNonPrimaryReleaseHandler = tracker.nonPrimaryReleaseHandler;
tracker.nonPrimaryReleaseHandler = function ( event ) {
if (event.button === 0) {
releaseCount++;
} else if (event.button === 1) {
middleReleaseCount++;
} else if (event.button === 2) {
rightReleaseCount++;
}
if (origNonPrimaryReleaseHandler) {
return origNonPrimaryReleaseHandler( event );
} else {
return true;
}
};
origMoveHandler = tracker.moveHandler; origMoveHandler = tracker.moveHandler;
tracker.moveHandler = function ( event ) { tracker.moveHandler = function ( event ) {
moveCount++; moveCount++;
@ -165,23 +201,40 @@
var simulateLeave = function (x, y) { var simulateLeave = function (x, y) {
simEvent.clientX = offset.left + x; simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y; simEvent.clientY = offset.top + y;
// simEvent.relatedTarget = document.body; simEvent.relatedTarget = document.body;
// $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent );
//}; };
//var simulateLeaveFrame = function (x, y) { //var simulateLeaveFrame = function (x, y) {
// simEvent.clientX = offset.left + x; // simEvent.clientX = offset.left + x;
// simEvent.clientY = offset.top + y; // simEvent.clientY = offset.top + y;
// simEvent.relatedTarget = document.getElementsByTagName("html")[0]; // simEvent.relatedTarget = document.getElementsByTagName("html")[0];
$canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent ); // $canvas.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', simEvent );
}; //};
var simulateDown = function (x, y) { var simulateDown = function (x, y) {
simEvent.button = 0;
simEvent.clientX = offset.left + x; simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y; simEvent.clientY = offset.top + y;
$canvas.simulate( 'mousedown', simEvent ); $canvas.simulate( 'mousedown', simEvent );
}; };
var simulateUp = function (x, y) { var simulateUp = function (x, y) {
simEvent.button = 0;
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mouseup', simEvent );
};
var simulateNonPrimaryDown = function (x, y, button) {
simEvent.button = button;
simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y;
$canvas.simulate( 'mousedown', simEvent );
};
var simulateNonPrimaryUp = function (x, y, button) {
simEvent.button = button;
simEvent.clientX = offset.left + x; simEvent.clientX = offset.left + x;
simEvent.clientY = offset.top + y; simEvent.clientY = offset.top + y;
$canvas.simulate( 'mouseup', simEvent ); $canvas.simulate( 'mouseup', simEvent );
@ -198,6 +251,7 @@
var resetForAssessment = function () { var resetForAssessment = function () {
simEvent = { simEvent = {
button: 0,
clientX: offset.left, clientX: offset.left,
clientY: offset.top clientY: offset.top
}; };
@ -205,6 +259,10 @@
exitCount = 0; exitCount = 0;
pressCount = 0; pressCount = 0;
releaseCount = 0; releaseCount = 0;
rightPressCount = 0;
rightReleaseCount = 0;
middlePressCount = 0;
middleReleaseCount = 0;
moveCount = 0; moveCount = 0;
clickCount = 0; clickCount = 0;
dblClickCount = 0; dblClickCount = 0;
@ -231,6 +289,18 @@
if ('releaseCount' in expected) { if ('releaseCount' in expected) {
equal( releaseCount, expected.releaseCount, expected.description + 'releaseHandler event count matches expected (' + expected.releaseCount + ')' ); equal( releaseCount, expected.releaseCount, expected.description + 'releaseHandler event count matches expected (' + expected.releaseCount + ')' );
} }
if ('rightPressCount' in expected) {
equal( rightPressCount, expected.rightPressCount, expected.description + 'nonPrimaryPressHandler event count (secondary/right button) matches expected (' + expected.rightPressCount + ')' );
}
if ('rightReleaseCount' in expected) {
equal( rightReleaseCount, expected.rightReleaseCount, expected.description + 'nonPrimaryReleaseHandler event count (secondary/right button) matches expected (' + expected.rightReleaseCount + ')' );
}
if ('middlePressCount' in expected) {
equal( middlePressCount, expected.middlePressCount, expected.description + 'nonPrimaryPressHandler event count (aux/middle button) matches expected (' + expected.middlePressCount + ')' );
}
if ('middleReleaseCount' in expected) {
equal( middleReleaseCount, expected.middleReleaseCount, expected.description + 'nonPrimaryReleaseHandler event count (aux/middle button) matches expected (' + expected.middleReleaseCount + ')' );
}
if ('moveCount' in expected) { if ('moveCount' in expected) {
equal( moveCount, expected.moveCount, expected.description + 'moveHandler event count matches expected (' + expected.moveCount + ')' ); equal( moveCount, expected.moveCount, expected.description + 'moveHandler event count matches expected (' + expected.moveCount + ')' );
} }
@ -290,6 +360,10 @@
exitCount: 0, exitCount: 0,
pressCount: 0, pressCount: 0,
releaseCount: 1, releaseCount: 1,
rightPressCount: 0,
rightReleaseCount: 0,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 20, moveCount: 20,
clickCount: 0, clickCount: 0,
dblClickCount: 0, dblClickCount: 0,
@ -315,6 +389,10 @@
exitCount: 1, exitCount: 1,
pressCount: 0, pressCount: 0,
releaseCount: 0, releaseCount: 0,
rightPressCount: 0,
rightReleaseCount: 0,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 20, moveCount: 20,
clickCount: 0, clickCount: 0,
dblClickCount: 0, dblClickCount: 0,
@ -338,6 +416,10 @@
exitCount: 1, exitCount: 1,
pressCount: 0, pressCount: 0,
releaseCount: 0, releaseCount: 0,
rightPressCount: 0,
rightReleaseCount: 0,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 20, moveCount: 20,
clickCount: 0, clickCount: 0,
dblClickCount: 0, dblClickCount: 0,
@ -350,7 +432,7 @@
//quickClick: false //quickClick: false
}); });
// enter-press-release-press-release-exit (double click) // enter-press-release-press-release-exit (primary/left double click)
resetForAssessment(); resetForAssessment();
simulateEnter(0, 0); simulateEnter(0, 0);
simulateDown(0, 0); simulateDown(0, 0);
@ -359,11 +441,15 @@
simulateUp(0, 0); simulateUp(0, 0);
simulateLeave(-1, -1); simulateLeave(-1, -1);
assessGestureExpectations({ assessGestureExpectations({
description: 'enter-press-release-press-release-exit (double click): ', description: 'enter-press-release-press-release-exit (primary/left double click): ',
enterCount: 1, enterCount: 1,
exitCount: 1, exitCount: 1,
pressCount: 2, pressCount: 2,
releaseCount: 2, releaseCount: 2,
rightPressCount: 0,
rightReleaseCount: 0,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 0, moveCount: 0,
clickCount: 2, clickCount: 2,
dblClickCount: 1, dblClickCount: 1,
@ -376,18 +462,22 @@
//quickClick: true //quickClick: true
}); });
// enter-press-release-exit (click) // enter-press-release-exit (primary/left click)
resetForAssessment(); resetForAssessment();
simulateEnter(0, 0); simulateEnter(0, 0);
simulateDown(0, 0); simulateDown(0, 0);
simulateUp(0, 0); simulateUp(0, 0);
simulateLeave(-1, -1); simulateLeave(-1, -1);
assessGestureExpectations({ assessGestureExpectations({
description: 'enter-press-release-exit (click): ', description: 'enter-press-release-exit (primary/left click): ',
enterCount: 1, enterCount: 1,
exitCount: 1, exitCount: 1,
pressCount: 1, pressCount: 1,
releaseCount: 1, releaseCount: 1,
rightPressCount: 0,
rightReleaseCount: 0,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 0, moveCount: 0,
clickCount: 1, clickCount: 1,
dblClickCount: 0, dblClickCount: 0,
@ -400,6 +490,92 @@
quickClick: true quickClick: true
}); });
// enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click)
resetForAssessment();
simulateEnter(0, 0);
simulateNonPrimaryDown(0, 0, 2);
simulateNonPrimaryUp(0, 0, 2);
simulateLeave(-1, -1);
assessGestureExpectations({
description: 'enter-nonprimarypress-nonprimaryrelease-exit (secondary/right click): ',
enterCount: 1,
exitCount: 1,
pressCount: 0,
releaseCount: 0,
rightPressCount: 1,
rightReleaseCount: 1,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 0,
clickCount: 0,
dblClickCount: 0,
dragCount: 0,
dragEndCount: 0,
//insideElementPressed: true,
//insideElementReleased: true,
contacts: 0,
trackedPointers: 0,
//quickClick: true
});
// enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click)
resetForAssessment();
simulateEnter(0, 0);
simulateNonPrimaryDown(0, 0, 1);
simulateNonPrimaryUp(0, 0, 1);
simulateLeave(-1, -1);
assessGestureExpectations({
description: 'enter-nonprimarypress-nonprimaryrelease-exit (aux/middle click): ',
enterCount: 1,
exitCount: 1,
pressCount: 0,
releaseCount: 0,
rightPressCount: 0,
rightReleaseCount: 0,
middlePressCount: 1,
middleReleaseCount: 1,
moveCount: 0,
clickCount: 0,
dblClickCount: 0,
dragCount: 0,
dragEndCount: 0,
//insideElementPressed: true,
//insideElementReleased: true,
contacts: 0,
trackedPointers: 0,
//quickClick: true
});
// enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element)
resetForAssessment();
simulateEnter(0, 0);
simulateNonPrimaryDown(0, 0, 2);
simulateMove(1, 1, 100);
simulateNonPrimaryUp(10, 10, 2);
simulateMove(-1, -1, 100);
simulateLeave(-1, -1);
assessGestureExpectations({
description: 'enter-nonprimarypress-move-nonprimaryrelease-move-exit (secondary/right button drag, release in tracked element): ',
enterCount: 1,
exitCount: 1,
pressCount: 0,
releaseCount: 0,
rightPressCount: 1,
rightReleaseCount: 1,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 200,
clickCount: 0,
dblClickCount: 0,
dragCount: 0,
dragEndCount: 0,
//insideElementPressed: true,
//insideElementReleased: true,
contacts: 0,
trackedPointers: 0,
//quickClick: false
});
// enter-press-move-release-move-exit (drag, release in tracked element) // enter-press-move-release-move-exit (drag, release in tracked element)
resetForAssessment(); resetForAssessment();
simulateEnter(0, 0); simulateEnter(0, 0);
@ -414,6 +590,10 @@
exitCount: 1, exitCount: 1,
pressCount: 1, pressCount: 1,
releaseCount: 1, releaseCount: 1,
rightPressCount: 0,
rightReleaseCount: 0,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 200, moveCount: 200,
clickCount: 1, clickCount: 1,
dblClickCount: 0, dblClickCount: 0,
@ -441,6 +621,10 @@
exitCount: 1, exitCount: 1,
pressCount: 1, pressCount: 1,
releaseCount: 1, releaseCount: 1,
rightPressCount: 0,
rightReleaseCount: 0,
middlePressCount: 0,
middleReleaseCount: 0,
moveCount: 15, moveCount: 15,
clickCount: 0, clickCount: 0,
dblClickCount: 0, dblClickCount: 0,
@ -453,7 +637,6 @@
quickClick: false quickClick: false
}); });
//// enter-press-move-exit-move-release-outside (drag, release outside iframe) //// enter-press-move-exit-move-release-outside (drag, release outside iframe)
//resetForAssessment(); //resetForAssessment();
//simulateEnter(0, 0); //simulateEnter(0, 0);
@ -468,6 +651,10 @@
// exitCount: 1, // exitCount: 1,
// pressCount: 1, // pressCount: 1,
// releaseCount: 1, // releaseCount: 1,
// rightPressCount: 0,
// rightReleaseCount: 0,
// middlePressCount: 0,
// middleReleaseCount: 0,
// moveCount: 10, // moveCount: 10,
// clickCount: 0, // clickCount: 0,
// dblClickCount: 0, // dblClickCount: 0,
@ -479,6 +666,7 @@
// trackedPointers: 0, // trackedPointers: 0,
// quickClick: false // quickClick: false
//}); //});
unhookViewerHandlers(); unhookViewerHandlers();
viewer.close(); viewer.close();