@21epub/epub-thirdparty
Version:
epub-thirdparty
100 lines (99 loc) • 4.35 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as dom from './dom.js';
import { IframeUtils } from './iframe.js';
import { StandardMouseEvent } from './mouseEvent.js';
import { DisposableStore } from '../common/lifecycle.js';
import { isIOS } from '../common/platform.js';
export function standardMouseMoveMerger(lastEvent, currentEvent) {
let ev = new StandardMouseEvent(currentEvent);
ev.preventDefault();
return {
leftButton: ev.leftButton,
buttons: ev.buttons,
posx: ev.posx,
posy: ev.posy
};
}
export class GlobalMouseMoveMonitor {
constructor() {
this._hooks = new DisposableStore();
this._mouseMoveEventMerger = null;
this._mouseMoveCallback = null;
this._onStopCallback = null;
}
dispose() {
this.stopMonitoring(false);
this._hooks.dispose();
}
stopMonitoring(invokeStopCallback, browserEvent) {
if (!this.isMonitoring()) {
// Not monitoring
return;
}
// Unhook
this._hooks.clear();
this._mouseMoveEventMerger = null;
this._mouseMoveCallback = null;
const onStopCallback = this._onStopCallback;
this._onStopCallback = null;
if (invokeStopCallback && onStopCallback) {
onStopCallback(browserEvent);
}
}
isMonitoring() {
return !!this._mouseMoveEventMerger;
}
startMonitoring(initialElement, initialButtons, mouseMoveEventMerger, mouseMoveCallback, onStopCallback) {
if (this.isMonitoring()) {
// I am already hooked
return;
}
this._mouseMoveEventMerger = mouseMoveEventMerger;
this._mouseMoveCallback = mouseMoveCallback;
this._onStopCallback = onStopCallback;
const windowChain = IframeUtils.getSameOriginWindowChain();
const mouseMove = isIOS ? 'pointermove' : 'mousemove'; // Safari sends wrong event, workaround for #122653
const mouseUp = 'mouseup';
const listenTo = windowChain.map(element => element.window.document);
const shadowRoot = dom.getShadowRoot(initialElement);
if (shadowRoot) {
listenTo.unshift(shadowRoot);
}
for (const element of listenTo) {
this._hooks.add(dom.addDisposableThrottledListener(element, mouseMove, (data) => {
if (data.buttons !== initialButtons) {
// Buttons state has changed in the meantime
this.stopMonitoring(true);
return;
}
this._mouseMoveCallback(data);
}, (lastEvent, currentEvent) => this._mouseMoveEventMerger(lastEvent, currentEvent)));
this._hooks.add(dom.addDisposableListener(element, mouseUp, (e) => this.stopMonitoring(true)));
}
if (IframeUtils.hasDifferentOriginAncestor()) {
let lastSameOriginAncestor = windowChain[windowChain.length - 1];
// We might miss a mouse up if it happens outside the iframe
// This one is for Chrome
this._hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseout', (browserEvent) => {
let e = new StandardMouseEvent(browserEvent);
if (e.target.tagName.toLowerCase() === 'html') {
this.stopMonitoring(true);
}
}));
// This one is for FF
this._hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseover', (browserEvent) => {
let e = new StandardMouseEvent(browserEvent);
if (e.target.tagName.toLowerCase() === 'html') {
this.stopMonitoring(true);
}
}));
// This one is for IE
this._hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document.body, 'mouseleave', (browserEvent) => {
this.stopMonitoring(true);
}));
}
}
}