igniteui-angular-sovn
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
184 lines (167 loc) • 6.12 kB
text/typescript
import { Inject, Injectable, NgZone } from "@angular/core";
import { ɵgetDOM as getDOM } from "@angular/platform-browser";
import { DOCUMENT } from "@angular/common";
import { PlatformUtil } from "./utils";
const EVENT_SUFFIX = "precise";
/**
* Touch gestures manager based on Hammer.js
* Use with caution, this will track references for single manager per element. Very TBD. Much TODO.
*
* @hidden
*/
export class HammerGesturesManager {
/**
* Event option defaults for each recognizer, see http://hammerjs.github.io/api/ for API listing.
*/
protected hammerOptions: HammerOptions = {};
private platformBrowser: boolean;
private _hammerManagers: Array<{
element: EventTarget;
manager: HammerManager;
}> = [];
constructor(
private _zone: NgZone,
private doc: any,
private platformUtil: PlatformUtil
) {
this.platformBrowser = this.platformUtil.isBrowser;
if (this.platformBrowser) {
this.hammerOptions = {
// D.P. #447 Force TouchInput due to PointerEventInput bug (https://github.com/hammerjs/hammer.js/issues/1065)
// see https://github.com/IgniteUI/igniteui-angular-sovn/issues/447#issuecomment-324601803
inputClass: Hammer.TouchInput,
recognizers: [
[Hammer.Pan, { threshold: 0 }],
[Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL }],
[Hammer.Tap],
[Hammer.Tap, { event: "doubletap", taps: 2 }, ["tap"]],
],
};
}
}
public supports(eventName: string): boolean {
return eventName.toLowerCase().endsWith("." + EVENT_SUFFIX);
}
/**
* Add listener extended with options for Hammer.js. Will use defaults if none are provided.
* Modeling after other event plugins for easy future modifications.
*/
public addEventListener(
element: HTMLElement,
eventName: string,
eventHandler: (eventObj) => void,
options: HammerOptions = null
): () => void {
if (!this.platformBrowser) {
return;
}
// Creating the manager bind events, must be done outside of angular
return this._zone.runOutsideAngular(() => {
let mc: HammerManager = this.getManagerForElement(element);
if (mc === null) {
// new Hammer is a shortcut for Manager with defaults
mc = new Hammer(
element,
Object.assign(this.hammerOptions, options)
);
this.addManagerForElement(element, mc);
}
const handler = (eventObj) =>
this._zone.run(() => eventHandler(eventObj));
mc.on(eventName, handler);
return () => mc.off(eventName, handler);
});
}
/**
* Add listener extended with options for Hammer.js. Will use defaults if none are provided.
* Modeling after other event plugins for easy future modifications.
*
* @param target Can be one of either window, body or document(fallback default).
*/
public addGlobalEventListener(
target: string,
eventName: string,
eventHandler: (eventObj) => void
): () => void {
if (!this.platformBrowser) {
return;
}
const element = this.getGlobalEventTarget(target);
// Creating the manager bind events, must be done outside of angular
return this.addEventListener(
element as HTMLElement,
eventName,
eventHandler
);
}
/**
* Exposes [Dom]Adapter.getGlobalEventTarget to get global event targets.
* Supported: window, document, body. Defaults to document for invalid args.
*
* @param target Target name
*/
public getGlobalEventTarget(target: string): EventTarget {
return getDOM().getGlobalEventTarget(this.doc, target);
}
/**
* Set HammerManager options.
*
* @param element The DOM element used to create the manager on.
*
* ### Example
*
* ```ts
* manager.setManagerOption(myElem, "pan", { pointers: 1 });
* ```
*/
public setManagerOption(element: EventTarget, event: string, options: any) {
const manager = this.getManagerForElement(element);
manager.get(event).set(options);
}
/**
* Add an element and manager map to the internal collection.
*
* @param element The DOM element used to create the manager on.
*/
public addManagerForElement(element: EventTarget, manager: HammerManager) {
this._hammerManagers.push({ element, manager });
}
/**
* Get HammerManager for the element or null
*
* @param element The DOM element used to create the manager on.
*/
public getManagerForElement(element: EventTarget): HammerManager {
const result = this._hammerManagers.filter(
(value) => value.element === element
);
return result.length ? result[0].manager : null;
}
/**
* Destroys the HammerManager for the element, removing event listeners in the process.
*
* @param element The DOM element used to create the manager on.
*/
public removeManagerForElement(element: HTMLElement) {
let index: number = null;
for (let i = 0; i < this._hammerManagers.length; i++) {
if (element === this._hammerManagers[i].element) {
index = i;
break;
}
}
if (index !== null) {
const item = this._hammerManagers.splice(index, 1)[0];
// destroy also
item.manager.destroy();
}
}
/** Destroys all internally tracked HammerManagers, removing event listeners in the process. */
public destroy() {
for (const item of this._hammerManagers) {
item.manager.destroy();
}
this._hammerManagers = [];
}
}