diff --git a/EndGate/EndGate.Core.JS/Input/Mouse/MouseHandler.js b/EndGate/EndGate.Core.JS/Input/Mouse/MouseHandler.js index 6e107387..9918e9a1 100644 --- a/EndGate/EndGate.Core.JS/Input/Mouse/MouseHandler.js +++ b/EndGate/EndGate.Core.JS/Input/Mouse/MouseHandler.js @@ -2,6 +2,7 @@ var EndGate; (function (EndGate) { /// /// + /// /// /// /// @@ -18,6 +19,7 @@ var EndGate; function MouseHandler(target) { var _this = this; this._target = target; + this._disposed = false; this._onClick = new EndGate.EventHandler1(); this._onDoubleClick = new EndGate.EventHandler1(); @@ -153,29 +155,72 @@ var EndGate; configurable: true }); + /** + * Disposes the MouseHandler and unbinds all bound events. + */ + MouseHandler.prototype.Dispose = function () { + if (!this._disposed) { + this._disposed = true; + + this._onClick.Dispose(); + this._onDoubleClick.Dispose(); + this._onDown.Dispose(); + this._onMove.Dispose(); + this._onScroll.Dispose(); + this._onUp.Dispose(); + + this.Unwire(); + + this._target = null; + } else { + throw new Error("MouseHandler cannot be disposed more than once"); + } + }; + MouseHandler.prototype.Wire = function () { var _this = this; - this._target.addEventListener("click", this._target.oncontextmenu = this.BuildEvent(this._onClick, this.BuildMouseClickEvent), false); - this._target.addEventListener("dblclick", this.BuildEvent(this._onDoubleClick, this.BuildMouseClickEvent), false); - this._target.addEventListener("mousedown", this.BuildEvent(this._onDown, this.BuildMouseClickEvent), false); - this._target.addEventListener("mouseup", this.BuildEvent(this._onUp, this.BuildMouseClickEvent), false); - this._target.addEventListener("mousemove", this.BuildEvent(this._onMove, this.BuildMouseEvent), false); + this._clickWire = this._contextMenuWire = this.BuildEvent(this._onClick, this.BuildMouseClickEvent); + this._dblClickWire = this.BuildEvent(this._onDoubleClick, this.BuildMouseClickEvent); + this._mouseDownWire = this.BuildEvent(this._onDown, this.BuildMouseClickEvent); + this._mouseUpWire = this.BuildEvent(this._onUp, this.BuildMouseClickEvent); + this._mouseMoveWire = this.BuildEvent(this._onMove, this.BuildMouseEvent); if ((/MSIE/i.test(navigator.userAgent))) { - this._target.addEventListener("wheel", this.BuildEvent(this._onScroll, function (e) { + this._mouseWheelWireName = "wheel"; + this._mouseWheelWire = this.BuildEvent(this._onScroll, function (e) { e.wheelDeltaX = -e.deltaX; e.wheelDeltaY = -e.deltaY; return _this.BuildMouseScrollEvent(e); - }), false); + }); } else if ((/Firefox/i.test(navigator.userAgent))) { - this._target.addEventListener("DOMMouseScroll", this.BuildEvent(this._onScroll, function (e) { + this._mouseWheelWireName = "DOMMouseScroll"; + this._mouseWheelWire = this.BuildEvent(this._onScroll, function (e) { e.wheelDeltaX = e.axis === 1 ? -e.detail : 0; e.wheelDeltaY = e.axis === 2 ? -e.detail : 0; return _this.BuildMouseScrollEvent(e); - }), false); + }); } else { - this._target.addEventListener("mousewheel", this.BuildEvent(this._onScroll, this.BuildMouseScrollEvent), false); + this._mouseWheelWireName = "mousewheel"; + this._mouseWheelWire = this.BuildEvent(this._onScroll, this.BuildMouseScrollEvent); } + + this._target.addEventListener("click", this._clickWire, false); + this._target.addEventListener("contextmenu", this._contextMenuWire, false); + this._target.addEventListener("dblclick", this._dblClickWire, false); + this._target.addEventListener("mousedown", this._mouseDownWire, false); + this._target.addEventListener("mouseup", this._mouseUpWire, false); + this._target.addEventListener("mousemove", this._mouseMoveWire, false); + this._target.addEventListener(this._mouseWheelWireName, this._mouseWheelWire, false); + }; + + MouseHandler.prototype.Unwire = function () { + this._target.removeEventListener("click", this._clickWire, false); + this._target.removeEventListener("contextmenu", this._contextMenuWire, false); + this._target.removeEventListener("dblclick", this._dblClickWire, false); + this._target.removeEventListener("mousedown", this._mouseDownWire, false); + this._target.removeEventListener("mouseup", this._mouseUpWire, false); + this._target.removeEventListener("mousemove", this._mouseMoveWire, false); + this._target.removeEventListener(this._mouseWheelWireName, this._mouseWheelWire, false); }; MouseHandler.prototype.BuildEvent = function (eventHandler, mouseEventBuilder, returnValue) { diff --git a/EndGate/EndGate.Core.JS/Input/Mouse/MouseHandler.ts b/EndGate/EndGate.Core.JS/Input/Mouse/MouseHandler.ts index 5058e4a4..a2cd9ef7 100644 --- a/EndGate/EndGate.Core.JS/Input/Mouse/MouseHandler.ts +++ b/EndGate/EndGate.Core.JS/Input/Mouse/MouseHandler.ts @@ -1,5 +1,6 @@ /// /// +/// /// /// /// @@ -10,7 +11,7 @@ module EndGate.Input { /** * Defines a handler that will monitor mouse events over a specified area and will execute appropriate functions based on the events. */ - export class MouseHandler { + export class MouseHandler implements IDisposable { // Used to determine mouse buttons without using extra conditional statements, performance enhancer private static MouseButtonArray = [null, _.MouseButton.Left, _.MouseButton.Middle, _.MouseButton.Right]; @@ -30,12 +31,24 @@ module EndGate.Input { private _target: HTMLElement; + // For disposing + private _contextMenuWire: (e: MouseEvent) => void; + private _clickWire: (e: MouseEvent) => void; + private _dblClickWire: (e: MouseEvent) => void; + private _mouseDownWire: (e: MouseEvent) => void; + private _mouseUpWire: (e: MouseEvent) => void; + private _mouseMoveWire: (e: MouseEvent) => void; + private _mouseWheelWireName: string; + private _mouseWheelWire: (e: MouseEvent) => void; + private _disposed: boolean; + /** * Creates a new instance of the MouseHandler object. * @param target The object to monitor mouse events for. */ constructor(target: HTMLElement) { this._target = target; + this._disposed = false; this._onClick = new EventHandler1(); this._onDoubleClick = new EventHandler1(); @@ -46,7 +59,7 @@ module EndGate.Input { // Generic flags to check mouse state this._leftIsDown = false; - this._middleIsDown= false; + this._middleIsDown = false; this._rightIsDown = false; this.Wire(); @@ -132,32 +145,76 @@ module EndGate.Input { return this._onScroll; } + /** + * Disposes the MouseHandler and unbinds all bound events. + */ + public Dispose(): void { + if (!this._disposed) { + this._disposed = true; + + this._onClick.Dispose(); + this._onDoubleClick.Dispose(); + this._onDown.Dispose(); + this._onMove.Dispose(); + this._onScroll.Dispose(); + this._onUp.Dispose(); + + this.Unwire(); + + this._target = null; + } + else { + throw new Error("MouseHandler cannot be disposed more than once"); + } + } + private Wire(): void { - this._target.addEventListener("click",this._target.oncontextmenu = this.BuildEvent(this._onClick, this.BuildMouseClickEvent),false); - this._target.addEventListener("dblclick", this.BuildEvent(this._onDoubleClick, this.BuildMouseClickEvent), false); - this._target.addEventListener("mousedown", this.BuildEvent(this._onDown, this.BuildMouseClickEvent), false); - this._target.addEventListener("mouseup", this.BuildEvent(this._onUp, this.BuildMouseClickEvent), false); - this._target.addEventListener("mousemove", this.BuildEvent(this._onMove, this.BuildMouseEvent), false); + this._clickWire = this._contextMenuWire = this.BuildEvent(this._onClick, this.BuildMouseClickEvent); + this._dblClickWire = this.BuildEvent(this._onDoubleClick, this.BuildMouseClickEvent); + this._mouseDownWire = this.BuildEvent(this._onDown, this.BuildMouseClickEvent); + this._mouseUpWire = this.BuildEvent(this._onUp, this.BuildMouseClickEvent) + this._mouseMoveWire = this.BuildEvent(this._onMove, this.BuildMouseEvent); // OnScroll, in order to detect horizontal scrolling need to hack a bit (browser sniffing) // if we were just doing vertical scrolling we could settle with the else statement in this block if ((/MSIE/i.test(navigator.userAgent))) { - this._target.addEventListener("wheel", this.BuildEvent(this._onScroll, (e: any) => { + this._mouseWheelWireName = "wheel"; + this._mouseWheelWire = this.BuildEvent(this._onScroll, (e: any) => { e.wheelDeltaX = -e.deltaX; e.wheelDeltaY = -e.deltaY; return this.BuildMouseScrollEvent(e); - }), false); + }); } else if ((/Firefox/i.test(navigator.userAgent))) { - this._target.addEventListener("DOMMouseScroll", this.BuildEvent(this._onScroll, (e: any) => { + this._mouseWheelWireName = "DOMMouseScroll"; + this._mouseWheelWire = this.BuildEvent(this._onScroll, (e: any) => { e.wheelDeltaX = e.axis === 1 ? -e.detail : 0; e.wheelDeltaY = e.axis === 2 ? -e.detail : 0; return this.BuildMouseScrollEvent(e); - }), false); + }); } else { - this._target.addEventListener("mousewheel", this.BuildEvent(this._onScroll, this.BuildMouseScrollEvent), false); + this._mouseWheelWireName = "mousewheel"; + this._mouseWheelWire = this.BuildEvent(this._onScroll, this.BuildMouseScrollEvent); } + + this._target.addEventListener("click", this._clickWire, false); + this._target.addEventListener("contextmenu", this._contextMenuWire, false); + this._target.addEventListener("dblclick", this._dblClickWire, false); + this._target.addEventListener("mousedown", this._mouseDownWire, false); + this._target.addEventListener("mouseup", this._mouseUpWire, false); + this._target.addEventListener("mousemove", this._mouseMoveWire, false); + this._target.addEventListener(this._mouseWheelWireName, this._mouseWheelWire, false); + } + + private Unwire(): void { + this._target.removeEventListener("click", this._clickWire, false); + this._target.removeEventListener("contextmenu", this._contextMenuWire, false); + this._target.removeEventListener("dblclick", this._dblClickWire, false); + this._target.removeEventListener("mousedown", this._mouseDownWire, false); + this._target.removeEventListener("mouseup", this._mouseUpWire, false); + this._target.removeEventListener("mousemove", this._mouseMoveWire, false); + this._target.removeEventListener(this._mouseWheelWireName, this._mouseWheelWire, false); } private BuildEvent(eventHandler: EventHandler1, mouseEventBuilder: (mouseEvent: MouseEvent) => IMouseEvent, returnValue: boolean = false): (e: MouseEvent) => void { @@ -195,7 +252,7 @@ module EndGate.Input { return new Vector2d( event.offsetX ? (event.offsetX) : event.pageX - this._target.offsetLeft, event.offsetY ? (event.offsetY) : event.pageY - this._target.offsetTop - ); + ); } private GetMouseButton(event: MouseEvent): string { @@ -206,7 +263,7 @@ module EndGate.Input { return _.MouseButton.Right; } - private GetMouseScrollDierction(event: any): Vector2d{ + private GetMouseScrollDierction(event: any): Vector2d { return new Vector2d(-Math.max(-1, Math.min(1, event.wheelDeltaX)), -Math.max(-1, Math.min(1, event.wheelDeltaY))); } }