From b62b8f01d7c4b85ed4e11a394afb37825931a9ff Mon Sep 17 00:00:00 2001 From: Oscar Lorentzon Date: Sat, 13 Mar 2021 00:04:15 +0100 Subject: [PATCH] fix: handle mouse up not fired outside of window --- spec/helper/EventHelper.ts | 44 +++++++++++++++++++++----------------- src/viewer/MouseService.ts | 36 ++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/spec/helper/EventHelper.ts b/spec/helper/EventHelper.ts index 733cdaf51..6a1d6659e 100644 --- a/spec/helper/EventHelper.ts +++ b/spec/helper/EventHelper.ts @@ -3,27 +3,31 @@ export class EventHelper { return new KeyboardEvent(typeArg, eventInitDict); } - public static createMouseEvent(eventType: string, params: MouseEventInit, target?: EventTarget): MouseEvent { - const mouseEvent: MouseEvent = document.createEvent("MouseEvent"); - - mouseEvent.initMouseEvent( + public static createMouseEvent( + eventType: string, + params: MouseEventInit, + target?: EventTarget): MouseEvent { + return new MouseEvent( eventType, - params.bubbles !== undefined ? params.bubbles : true, - params.cancelable !== undefined ? params.cancelable : true, - window, - params.detail !== undefined ? params.detail : 0, - params.screenX !== undefined ? params.screenX : 0, - params.screenY !== undefined ? params.screenY : 0, - params.clientX !== undefined ? params.clientX : 0, - params.clientY !== undefined ? params.clientY : 0, - !!params.ctrlKey, - !!params.altKey, - !!params.shiftKey, - !!params.metaKey, - params.button !== undefined ? params.button : 0, - !!target ? target : document.createElement("div")); - - return mouseEvent; + { + bubbles: params.bubbles !== undefined ? + params.bubbles : true, + cancelable: params.cancelable !== undefined ? + params.cancelable : true, + detail: params.detail !== undefined ? params.detail : 0, + screenX: params.screenX !== undefined ? params.screenX : 0, + screenY: params.screenY !== undefined ? params.screenY : 0, + clientX: params.clientX !== undefined ? params.clientX : 0, + clientY: params.clientY !== undefined ? params.clientY : 0, + ctrlKey: !!params.ctrlKey, + altKey: !!params.altKey, + shiftKey: !!params.shiftKey, + metaKey: !!params.metaKey, + button: params.button !== undefined ? params.button : 0, + buttons: params.buttons !== undefined ? params.button : 1, + relatedTarget: !!target ? + target : document.createElement("div"), + }); } public static createTouchEvent(eventType: string, shiftKey?: boolean): TouchEvent { diff --git a/src/viewer/MouseService.ts b/src/viewer/MouseService.ts index 89422a511..b8d111938 100644 --- a/src/viewer/MouseService.ts +++ b/src/viewer/MouseService.ts @@ -30,13 +30,22 @@ import { IMouseClaim } from "./interfaces/IMouseClaim"; import { IMouseDeferPixels } from "./interfaces/IMouseDeferPixels"; import { SubscriptionHolder } from "../utils/SubscriptionHolder"; +type Button = 0 | 2; + +// MouseEvent.button +const LEFT_BUTTON: Button = 0; +const RIGHT_BUTTON: Button = 2; + +// MouseEvent.buttons +const BUTTONS_MAP = { + [LEFT_BUTTON]: 1, + [RIGHT_BUTTON]: 2 +}; + interface FirefoxBrowser { InstallTrigger: undefined; } -const LEFT_BUTTON = 0; -const RIGHT_BUTTON = 2; - export class MouseService { private _activeSubject$: BehaviorSubject; private _active$: Observable; @@ -86,6 +95,7 @@ export class MouseService { private _wheelOwner$: Observable; private _windowBlur$: Observable; + private _subscriptions: SubscriptionHolder = new SubscriptionHolder(); constructor( @@ -218,6 +228,11 @@ export class MouseService { const dragStop$: Observable = observableMerge( this._windowBlur$, + this._documentMouseMove$.pipe( + filter( + (e: MouseEvent): boolean => { + return this._buttonReleased(e, LEFT_BUTTON); + })), this._documentMouseUp$.pipe( filter( (e: MouseEvent): boolean => { @@ -247,6 +262,11 @@ export class MouseService { const rightDragStop$: Observable = observableMerge( this._windowBlur$, + this._documentMouseMove$.pipe( + filter( + (e: MouseEvent): boolean => { + return this._buttonReleased(e, RIGHT_BUTTON); + })), this._documentMouseUp$.pipe( filter( (e: MouseEvent): boolean => { @@ -611,4 +631,14 @@ export class MouseService { } return event.button; } + + private _buttonReleased(e: MouseEvent, button: Button): boolean { + // Right button `mouseup` is not fired in + // Chrome on Mac outside the window or iframe. If + // the button is no longer pressed during move + // it may have been released and drag stop + // should be emitted. + const flag = BUTTONS_MAP[button]; + return e.buttons === undefined || (e.buttons & flag) !== flag; + } }