spiegel-keyman/web/source/osk/layouts/mouseDragOperation.ts

171 lines
No EOL
4.5 KiB
TypeScript

/// <reference path="../inputEventCoordinate.ts" />
namespace com.keyman.osk.layouts {
type MouseHandler = (this: GlobalEventHandlers, ev: MouseEvent) => any;
/**
* Used to store the page's original mouse handlers and properties
* when temporarily overridden by OSK moving or resizing handlers due
* to user interaction.
*/
class MouseStartSnapshot {
private readonly _VPreviousMouseMove: MouseHandler;
private readonly _VPreviousMouseUp: MouseHandler;
private readonly _VPreviousCursor: string;
private readonly _VPreviousMouseButton: number;
constructor(e: MouseEvent) {
this._VPreviousMouseMove = document.onmousemove;
this._VPreviousMouseUp = document.onmouseup;
this._VPreviousCursor = document.body.style.cursor;
this._VPreviousMouseButton = (typeof(e.which)=='undefined' ? e.button : e.which);
}
restore() {
document.onmousemove = this._VPreviousMouseMove;
document.onmouseup = this._VPreviousMouseUp;
if(document.body.style.cursor) {
document.body.style.cursor = this._VPreviousCursor;
}
}
matchesCausingClick(e: MouseEvent): boolean {
return this._VPreviousMouseButton == (typeof(e.which)=='undefined' ? e.button : e.which);
}
}
export abstract class MouseDragOperation {
private _enabled: boolean;
private _startCoord: InputEventCoordinate;
private _mouseStartSnapshot: MouseStartSnapshot;
private startHandler: (e: MouseEvent) => void;
private cursorType: string;
public constructor(cursorType?: string) {
this.startHandler = this._VMoveMouseDown.bind(this);
this.cursorType = cursorType;
}
/**
* Denotes whether or not this object should handle incoming events.
*/
public get enabled(): boolean {
return this._enabled;
}
public set enabled(flag: boolean) {
this._enabled = flag;
}
/**
* Denotes whether or not this object is currently handling an ongoing drag event.
*/
public get isActive(): boolean {
return !!this._mouseStartSnapshot;
}
public get mouseDownHandler(): (e: MouseEvent) => void {
return this.startHandler;
}
/**
* Function _VMoveMouseDown
* Scope Private
* @param {Object} e event
* Description Process mouse down on OSK
*/
private _VMoveMouseDown(e: MouseEvent) {
if(!e) {
return true;
}
if(!this._enabled) {
return true;
}
if(!this._mouseStartSnapshot) { // I1472 - Dragging off edge of browser window causes muckup
this._mouseStartSnapshot = new MouseStartSnapshot(e);
}
this._startCoord = InputEventCoordinate.fromEvent(e);
document.onmousemove = this._VMoveMouseMove.bind(this);
document.onmouseup = this._VMoveMouseUp.bind(this);
if(document.body.style.cursor) {
document.body.style.cursor = this.cursorType;
}
e.preventDefault();
e.cancelBubble = true;
this.onDragStart();
return false;
}
protected abstract onDragStart();
/**
* Process mouse drag on OSK
*
* @param {Object} e event
*/
private _VMoveMouseMove(e: MouseEvent) {
if(!e) {
return true;
}
if(!this.enabled) {
return true;
}
e.preventDefault();
e.cancelBubble = true;
if(!this._mouseStartSnapshot.matchesCausingClick(e)) { // I1472 - Dragging off edge of browser window causes muckup
return this._VMoveMouseUp(e);
} else {
const coord = InputEventCoordinate.fromEvent(e);
const deltaX = coord.x - this._startCoord.x;
const deltaY = coord.y - this._startCoord.y;
this.onDragMove(deltaX, deltaY);
return false;
}
}
/**
*
* @param deltaX The total horizontal distance moved, in pixels, since the start of the drag
* @param deltaY The total vertical distance moved, in pixels, since the start of the drag
*/
protected abstract onDragMove(deltaX: number, deltaY: number);
/**
* Function _VMoveMouseUp
* Scope Private
* @param {Object} e event
* Description Process mouse up during movement of KMW OSK UI
*/
private _VMoveMouseUp(e: MouseEvent) {
if(!e) {
return true;
}
this._mouseStartSnapshot.restore();
this._mouseStartSnapshot = null;
e.preventDefault();
e.cancelBubble = true;
this.onDragRelease();
return false;
}
protected abstract onDragRelease();
}
}