From c38188927ef73a98ae90fe6bb7e16b64d0c32ff9 Mon Sep 17 00:00:00 2001 From: Mark Salsbery <> Date: Wed, 10 Mar 2021 13:45:15 -0800 Subject: [PATCH 1/8] Added preventDefault option to MouseTracker.contextMenuHandler and Viewer 'canvas-contextmenu' event args --- changelog.txt | 1 + src/mousetracker.js | 32 ++++++++++++++++++-------------- src/viewer.js | 16 +++++++++++----- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1c325eba..b1f80fda 100644 --- a/changelog.txt +++ b/changelog.txt @@ -36,6 +36,7 @@ OPENSEADRAGON CHANGELOG * Added additional documentation for the zoomPerSecond viewer option (#1872 @msalsbery) * MouseTracker: Per #1863, dropped support for Internet Explorer < 11 (#1872 @msalsbery) * Fixed simulated drag events in navigator tests (#1949 @msalsbery) +* Added preventDefault option to MouseTracker.contextMenuHandler and Viewer 'canvas-contextmenu' event args (# @msalsbery) 2.4.2: diff --git a/src/mousetracker.js b/src/mousetracker.js index 4aefd249..1c268ee2 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -280,7 +280,6 @@ 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."); @@ -402,6 +401,8 @@ * The position of the event relative to the tracked element. * @param {Object} event.originalEvent * The original event object. + * @param {Boolean} event.preventDefault + * Set to true to prevent the default user-agent's handling of the contextmenu event. * @param {Object} event.userData * Arbitrary user-defined object. */ @@ -1942,6 +1943,8 @@ function onContextMenu( tracker, event ) { //$.console.log('contextmenu ' + (tracker.userData ? tracker.userData.toString() : '') + ' ' + (event.target === tracker.element ? 'tracker.element' : '')); + var eventArgs = null; + var eventInfo = { originalEvent: event, eventType: 'contextmenu', @@ -1952,17 +1955,18 @@ // ContextMenu if ( tracker.contextMenuHandler && !eventInfo.preventGesture && !eventInfo.defaultPrevented ) { - tracker.contextMenuHandler( - { - eventSource: tracker, - position: getPointRelativeToAbsolute( getMouseAbsolute( event ), tracker.element ), - originalEvent: eventInfo.originalEvent, - userData: tracker.userData - } - ); + eventArgs = { + eventSource: tracker, + position: getPointRelativeToAbsolute( getMouseAbsolute( event ), tracker.element ), + originalEvent: eventInfo.originalEvent, + preventDefault: eventInfo.preventDefault || eventInfo.defaultPrevented, + userData: tracker.userData + }; + + tracker.contextMenuHandler( eventArgs ); } - if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) { + if ( ( eventArgs && eventArgs.preventDefault ) || ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) ) { $.cancelEvent( event ); } if ( eventInfo.stopPropagation ) { @@ -2810,7 +2814,7 @@ case 'pointerdown': eventInfo.isStopable = true; eventInfo.isCancelable = true; - eventInfo.preventDefault = false;//tracker.hasGestureHandlers; + eventInfo.preventDefault = false; // updatePointerDown() may set true (tracker.hasGestureHandlers) eventInfo.preventGesture = !tracker.hasGestureHandlers; eventInfo.stopPropagation = false; break; @@ -2824,7 +2828,7 @@ case 'wheel': eventInfo.isStopable = true; eventInfo.isCancelable = true; - eventInfo.preventDefault = false;//tracker.hasScrollHandler; + eventInfo.preventDefault = false; // handleWheelEvent() may set true (tracker.hasScrollHandler) eventInfo.preventGesture = !tracker.hasScrollHandler; eventInfo.stopPropagation = false; break; @@ -2854,8 +2858,8 @@ case 'contextmenu': eventInfo.isStopable = true; eventInfo.isCancelable = true; - eventInfo.preventDefault = false;//tracker.hasContextMenuHandler; - eventInfo.preventGesture = true;//!tracker.hasContextMenuHandler; + eventInfo.preventDefault = false; + eventInfo.preventGesture = false; eventInfo.stopPropagation = false; break; case 'pointerenter': diff --git a/src/viewer.js b/src/viewer.js index db1e8a23..21d6f469 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2546,6 +2546,13 @@ function onBlur(){ } function onCanvasContextMenu( event ) { + var eventArgs = { + tracker: event.eventSource, + position: event.position, + originalEvent: event.originalEvent, + preventDefault: event.preventDefault + }; + /** * Raised when a contextmenu event occurs in the {@link OpenSeadragon.Viewer#canvas} element. * @@ -2556,13 +2563,12 @@ function onCanvasContextMenu( 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 {Boolean} preventDefault - Set to true to prevent the default user-agent's handling of the contextmenu event. * @property {?Object} userData - Arbitrary subscriber-defined object. */ - this.raiseEvent( 'canvas-contextmenu', { - tracker: event.eventSource, - position: event.position, - originalEvent: event.originalEvent - }); + this.raiseEvent( 'canvas-contextmenu', eventArgs ); + + event.preventDefault = eventArgs.preventDefault; } function onCanvasKeyDown( event ) { From 2bbfa970638c409c9e359d85ff8e8478992ab696 Mon Sep 17 00:00:00 2001 From: Mark Salsbery <> Date: Wed, 10 Mar 2021 14:53:33 -0800 Subject: [PATCH 2/8] MouseTracker preProcessEvent on key, focus, blur events --- src/mousetracker.js | 136 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 105 insertions(+), 31 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 1c268ee2..17723216 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -1211,7 +1211,7 @@ * @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". + * "keydown", "keyup", "keypress", "focus", "blur", "contextmenu", "gotpointercapture", "lostpointercapture", "pointerenter", "pointerleave", "pointerover", "pointerout", "pointerdown", "pointerup", "pointermove", "pointercancel", "wheel", "click", "dblclick". * @property {String} pointerType * "mouse", "touch", "pen", etc. * @property {Boolean} isEmulated @@ -1812,9 +1812,16 @@ */ function onKeyDown( tracker, event ) { //$.console.log( "keydown %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); - var propagate; - if ( tracker.keyDownHandler ) { - propagate = tracker.keyDownHandler( + var eventInfo = { + originalEvent: event, + eventType: 'keydown', + pointerType: '', + isEmulated: false + }; + preProcessEvent( tracker, eventInfo ); + + if ( tracker.keyDownHandler && !eventInfo.preventGesture && !eventInfo.defaultPrevented ) { + tracker.keyDownHandler( { eventSource: tracker, keyCode: event.keyCode ? event.keyCode : event.charCode, @@ -1827,9 +1834,13 @@ userData: tracker.userData } ); - if ( !propagate ) { - $.cancelEvent( event ); - } + } + + if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) { + $.cancelEvent( event ); + } + if ( eventInfo.stopPropagation ) { + $.stopEvent( event ); } } @@ -1840,9 +1851,17 @@ */ function onKeyUp( tracker, event ) { //$.console.log( "keyup %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); - var propagate; - if ( tracker.keyUpHandler ) { - propagate = tracker.keyUpHandler( + + var eventInfo = { + originalEvent: event, + eventType: 'keyup', + pointerType: '', + isEmulated: false + }; + preProcessEvent( tracker, eventInfo ); + + if ( tracker.keyUpHandler && !eventInfo.preventGesture && !eventInfo.defaultPrevented ) { + tracker.keyUpHandler( { eventSource: tracker, keyCode: event.keyCode ? event.keyCode : event.charCode, @@ -1855,9 +1874,13 @@ userData: tracker.userData } ); - if ( !propagate ) { - $.cancelEvent( event ); - } + } + + if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) { + $.cancelEvent( event ); + } + if ( eventInfo.stopPropagation ) { + $.stopEvent( event ); } } @@ -1868,9 +1891,17 @@ */ function onKeyPress( tracker, event ) { //$.console.log( "keypress %s %s %s %s %s", event.keyCode, event.charCode, event.ctrlKey, event.shiftKey, event.altKey ); - var propagate; - if ( tracker.keyHandler ) { - propagate = tracker.keyHandler( + + var eventInfo = { + originalEvent: event, + eventType: 'keypress', + pointerType: '', + isEmulated: false + }; + preProcessEvent( tracker, eventInfo ); + + if ( tracker.keyHandler && !eventInfo.preventGesture && !eventInfo.defaultPrevented ) { + tracker.keyHandler( { eventSource: tracker, keyCode: event.keyCode ? event.keyCode : event.charCode, @@ -1883,9 +1914,13 @@ userData: tracker.userData } ); - if ( !propagate ) { - $.cancelEvent( event ); - } + } + + if ( eventInfo.preventDefault && !eventInfo.defaultPrevented ) { + $.cancelEvent( event ); + } + if ( eventInfo.stopPropagation ) { + $.stopEvent( event ); } } @@ -1896,9 +1931,20 @@ */ function onFocus( tracker, event ) { //console.log( "focus %s", event ); - var propagate; - if ( tracker.focusHandler ) { - propagate = tracker.focusHandler( + + // focus doesn't bubble and is not cancelable, but we call + // preProcessEvent() so it's dispatched to preProcessEventHandler + // if necessary + var eventInfo = { + originalEvent: event, + eventType: 'focus', + pointerType: '', + isEmulated: false + }; + preProcessEvent( tracker, eventInfo ); + + if ( tracker.focusHandler && !eventInfo.preventGesture ) { + tracker.focusHandler( { eventSource: tracker, originalEvent: event, @@ -1906,9 +1952,6 @@ userData: tracker.userData } ); - if ( propagate === false ) { - $.cancelEvent( event ); - } } } @@ -1919,9 +1962,20 @@ */ function onBlur( tracker, event ) { //console.log( "blur %s", event ); - var propagate; - if ( tracker.blurHandler ) { - propagate = tracker.blurHandler( + + // blur doesn't bubble and is not cancelable, but we call + // preProcessEvent() so it's dispatched to preProcessEventHandler + // if necessary + var eventInfo = { + originalEvent: event, + eventType: 'blur', + pointerType: '', + isEmulated: false + }; + preProcessEvent( tracker, eventInfo ); + + if ( tracker.blurHandler && !eventInfo.preventGesture ) { + tracker.blurHandler( { eventSource: tracker, originalEvent: event, @@ -1929,9 +1983,6 @@ userData: tracker.userData } ); - if ( propagate === false ) { - $.cancelEvent( event ); - } } } @@ -2862,6 +2913,29 @@ eventInfo.preventGesture = false; eventInfo.stopPropagation = false; break; + case 'keydown': + eventInfo.isStopable = true; + eventInfo.isCancelable = true; + eventInfo.preventDefault = !!tracker.keyDownHandler; + eventInfo.preventGesture = false; + eventInfo.stopPropagation = false; + break; + case 'keyup': + eventInfo.isStopable = true; + eventInfo.isCancelable = true; + eventInfo.preventDefault = !!tracker.keyUpHandler; + eventInfo.preventGesture = false; + eventInfo.stopPropagation = false; + break; + case 'keypress': + eventInfo.isStopable = true; + eventInfo.isCancelable = true; + eventInfo.preventDefault = !!tracker.keyHandler; + eventInfo.preventGesture = false; + eventInfo.stopPropagation = false; + break; + case 'focus': + case 'blur': case 'pointerenter': case 'pointerleave': default: From d7d7fda4afba993c3033aaef1b4ccfbdfd29661b Mon Sep 17 00:00:00 2001 From: Mark Salsbery <> Date: Wed, 10 Mar 2021 15:58:27 -0800 Subject: [PATCH 3/8] Fixed bug preventing keypress events from firing on MouseTrackers with onKeyDown handlers --- src/mousetracker.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 17723216..6542b4a8 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -2914,16 +2914,10 @@ eventInfo.stopPropagation = false; break; case 'keydown': - eventInfo.isStopable = true; - eventInfo.isCancelable = true; - eventInfo.preventDefault = !!tracker.keyDownHandler; - eventInfo.preventGesture = false; - eventInfo.stopPropagation = false; - break; case 'keyup': eventInfo.isStopable = true; eventInfo.isCancelable = true; - eventInfo.preventDefault = !!tracker.keyUpHandler; + eventInfo.preventDefault = false; eventInfo.preventGesture = false; eventInfo.stopPropagation = false; break; From f16a7308b4740872b844d544466a248476ff3ee8 Mon Sep 17 00:00:00 2001 From: Mark Salsbery <> Date: Wed, 10 Mar 2021 16:05:22 -0800 Subject: [PATCH 4/8] changelog update --- changelog.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index b1f80fda..5fc3c902 100644 --- a/changelog.txt +++ b/changelog.txt @@ -36,7 +36,8 @@ OPENSEADRAGON CHANGELOG * Added additional documentation for the zoomPerSecond viewer option (#1872 @msalsbery) * MouseTracker: Per #1863, dropped support for Internet Explorer < 11 (#1872 @msalsbery) * Fixed simulated drag events in navigator tests (#1949 @msalsbery) -* Added preventDefault option to MouseTracker.contextMenuHandler and Viewer 'canvas-contextmenu' event args (# @msalsbery) +* Added preventDefault option to MouseTracker.contextMenuHandler and Viewer 'canvas-contextmenu' event args (#1951 @msalsbery) +* MouseTracker: Added preProcessEventHandler for keydown, keyup, keypress, focus, blur Events (#1951 @msalsbery) 2.4.2: From 3b2d5e640c0772a07309e72b4ecb60d1778b8bcd Mon Sep 17 00:00:00 2001 From: Mark Salsbery <> Date: Wed, 10 Mar 2021 16:10:28 -0800 Subject: [PATCH 5/8] removed some redundant code --- src/mousetracker.js | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 6542b4a8..7f710c78 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -2856,6 +2856,9 @@ break; case 'pointerover': case 'pointerout': + case 'contextmenu': + case 'keydown': + case 'keyup': eventInfo.isStopable = true; eventInfo.isCancelable = true; eventInfo.preventDefault = false; @@ -2906,21 +2909,6 @@ eventInfo.preventGesture = false; eventInfo.stopPropagation = false; break; - case 'contextmenu': - eventInfo.isStopable = true; - eventInfo.isCancelable = true; - eventInfo.preventDefault = false; - eventInfo.preventGesture = false; - eventInfo.stopPropagation = false; - break; - case 'keydown': - case 'keyup': - eventInfo.isStopable = true; - eventInfo.isCancelable = true; - eventInfo.preventDefault = false; - eventInfo.preventGesture = false; - eventInfo.stopPropagation = false; - break; case 'keypress': eventInfo.isStopable = true; eventInfo.isCancelable = true; From bed6cfa853677283443c040d7b071f2b98169af0 Mon Sep 17 00:00:00 2001 From: Mark Salsbery <> Date: Wed, 10 Mar 2021 17:18:17 -0800 Subject: [PATCH 6/8] Removed a bit more IE<11 code --- changelog.txt | 2 +- src/imagetilesource.js | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/changelog.txt b/changelog.txt index d08aaf53..7e0a34df 100644 --- a/changelog.txt +++ b/changelog.txt @@ -34,7 +34,7 @@ OPENSEADRAGON CHANGELOG * 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) +* MouseTracker: Per #1863, dropped support for Internet Explorer < 11 (#1872 @msalsbery) (#1950 @rmontroy) (#1951 @msalsbery) * Fixed simulated drag events in navigator tests (#1949 @msalsbery) * Added preventDefault option to MouseTracker.contextMenuHandler and Viewer 'canvas-contextmenu' event args (#1951 @msalsbery) * MouseTracker: Added preProcessEventHandler for keydown, keyup, keypress, focus, blur Events (#1951 @msalsbery) diff --git a/src/imagetilesource.js b/src/imagetilesource.js index da1c201b..25f67988 100644 --- a/src/imagetilesource.js +++ b/src/imagetilesource.js @@ -114,9 +114,8 @@ } $.addEvent(image, 'load', function () { - /* IE8 fix since it has no naturalWidth and naturalHeight */ - _this.width = Object.prototype.hasOwnProperty.call(image, 'naturalWidth') ? image.naturalWidth : image.width; - _this.height = Object.prototype.hasOwnProperty.call(image, 'naturalHeight') ? image.naturalHeight : image.height; + _this.width = image.naturalWidth; + _this.height = image.naturalHeight; _this.aspectRatio = _this.width / _this.height; _this.dimensions = new $.Point(_this.width, _this.height); _this._tileWidth = _this.width; @@ -210,9 +209,8 @@ _buildLevels: function () { var levels = [{ url: this._image.src, - /* IE8 fix since it has no naturalWidth and naturalHeight */ - width: Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width, - height: Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height + width: this._image.naturalWidth, + height: this._image.naturalHeight }]; if (!this.buildPyramid || !$.supportsCanvas || !this.useCanvas) { @@ -221,9 +219,8 @@ return levels; } - /* IE8 fix since it has no naturalWidth and naturalHeight */ - var currentWidth = Object.prototype.hasOwnProperty.call(this._image, 'naturalWidth') ? this._image.naturalWidth : this._image.width; - var currentHeight = Object.prototype.hasOwnProperty.call(this._image, 'naturalHeight') ? this._image.naturalHeight : this._image.height; + var currentWidth = this._image.naturalWidth; + var currentHeight = this._image.naturalHeight; var bigCanvas = document.createElement("canvas"); From 83788cbb758b246d695ff80916a53d5141539af4 Mon Sep 17 00:00:00 2001 From: Mark Salsbery <> Date: Thu, 11 Mar 2021 16:07:24 -0800 Subject: [PATCH 7/8] key down/up event disposition defaults --- src/mousetracker.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/mousetracker.js b/src/mousetracker.js index 7f710c78..b14a32e3 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -2857,8 +2857,6 @@ case 'pointerover': case 'pointerout': case 'contextmenu': - case 'keydown': - case 'keyup': eventInfo.isStopable = true; eventInfo.isCancelable = true; eventInfo.preventDefault = false; @@ -2909,6 +2907,20 @@ eventInfo.preventGesture = false; eventInfo.stopPropagation = false; break; + case 'keydown': + eventInfo.isStopable = true; + eventInfo.isCancelable = true; + eventInfo.preventDefault = !!tracker.keyDownHandler; + eventInfo.preventGesture = false; + eventInfo.stopPropagation = false; + break; + case 'keyup': + eventInfo.isStopable = true; + eventInfo.isCancelable = true; + eventInfo.preventDefault = !!tracker.keyUpHandler; + eventInfo.preventGesture = false; + eventInfo.stopPropagation = false; + break; case 'keypress': eventInfo.isStopable = true; eventInfo.isCancelable = true; From d4eaefbae1637477c2b9195157ba4a3f6c5209f7 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 12 Mar 2021 11:19:29 -0800 Subject: [PATCH 8/8] Changelog refinement --- changelog.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 38fcc2d4..42533bfb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,7 +3,7 @@ OPENSEADRAGON CHANGELOG 2.5.0: (In progress) -* BREAKING CHANGE: Dropped support for older browsers (IE < 11) (#1949 @msalsbery) +* BREAKING CHANGE: Dropped support for older browsers (IE < 11) (#1872 #1949 @msalsbery, #1950 @rmontroy) * 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) @@ -34,7 +34,6 @@ OPENSEADRAGON CHANGELOG * 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: