Socket
Socket
Sign inDemoInstall

@ribajs/extras

Package Overview
Dependencies
Maintainers
1
Versions
59
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ribajs/extras - npm Package Compare versions

Comparing version 1.9.0-alpha.0 to 1.9.0-alpha.1

src/binders/sync-element-property.binder.ts

2

lib/binders/data-scroll-position-y.binder.d.ts

@@ -1,2 +0,2 @@

import { Binder } from '@ribajs/core';
import { Binder } from "@ribajs/core";
/**

@@ -3,0 +3,0 @@ * rv-data-scroll-position

@@ -17,67 +17,82 @@ "use strict";

exports.dataScrollPositionYBinder = {
name: 'data-scroll-position-y',
customData: {},
bind() {
if (!this.customData) {
this.customData = {};
name: "data-scroll-position-y",
customData: {},
bind() {
if (!this.customData) {
this.customData = {};
}
this.customData.onScroll = () => {
if (this.customData.elementSelector === "window") {
const element = this.customData.watchScrollOnElement;
if (element.scrollY <= 0 + this.customData.offsetTop) {
this.el.dataset.scrollPositionY = "top";
} else if (
element.innerHeight +
element.pageYOffset +
this.customData.offsetBottom >=
document.body.offsetHeight
) {
this.el.dataset.scrollPositionY = "bottom";
} else {
this.el.dataset.scrollPositionY = "scrolled";
}
this.customData.onScroll = () => {
if (this.customData.elementSelector === 'window') {
const element = this.customData.watchScrollOnElement;
if (element.scrollY <= 0 + this.customData.offsetTop) {
this.el.dataset.scrollPositionY = 'top';
}
else if ((element.innerHeight + element.pageYOffset + this.customData.offsetBottom) >= document.body.offsetHeight) {
this.el.dataset.scrollPositionY = 'bottom';
}
else {
this.el.dataset.scrollPositionY = 'scrolled';
}
}
else {
const element = this.customData.watchScrollOnElement;
if (element.scrollTop <= 0 + this.customData.offsetTop) {
this.el.dataset.scrollPositionY = 'top';
}
else if ((element.scrollTop + this.customData.offsetBottom) >= element.scrollHeight - element.clientHeight) {
this.el.dataset.scrollPositionY = 'bottom';
}
else {
this.el.dataset.scrollPositionY = 'scrolled';
}
}
};
},
routine(el, elementSelector = 'window') {
// Remove old scroll event
if (this.customData.watchScrollOnElement) {
this.customData.watchScrollOnElement.removeEventListener('scroll', core_1.Utils.debounce.bind(this, this.customData.onScroll.bind(this)));
} else {
const element = this.customData.watchScrollOnElement;
if (element.scrollTop <= 0 + this.customData.offsetTop) {
this.el.dataset.scrollPositionY = "top";
} else if (
element.scrollTop + this.customData.offsetBottom >=
element.scrollHeight - element.clientHeight
) {
this.el.dataset.scrollPositionY = "bottom";
} else {
this.el.dataset.scrollPositionY = "scrolled";
}
// Set new element to watch for the scroll event
if (elementSelector === 'window') {
this.customData.watchScrollOnElement = window;
}
else if (elementSelector === 'this') {
this.customData.watchScrollOnElement = this.el;
}
else {
this.customData.watchScrollOnElement = document.querySelector(elementSelector);
}
// Watch new element for scroll event
if (this.customData.watchScrollOnElement) {
// console.debug('addEventListener', this.customData.watchScrollOnElement);
this.customData.watchScrollOnElement.addEventListener('scroll', core_1.Utils.debounce(this.customData.onScroll.bind(this)), { passive: true });
}
this.customData.offsetTop = Number(this.el.dataset.offsetTop) || DEFAULT_OFFSET;
this.customData.offsetBottom = Number(this.el.dataset.offsetBottom) || DEFAULT_OFFSET;
this.customData.elementSelector = elementSelector;
// inital scroll position
this.customData.onScroll();
},
unbind() {
// Remove old scroll event
if (this.customData.watchScrollOnElement) {
this.customData.watchScrollOnElement.removeEventListener('scroll', core_1.Utils.debounce(this.customData.onScroll.bind(this)));
}
},
}
};
},
routine(el, elementSelector = "window") {
// Remove old scroll event
if (this.customData.watchScrollOnElement) {
this.customData.watchScrollOnElement.removeEventListener(
"scroll",
core_1.Utils.debounce.bind(this, this.customData.onScroll.bind(this))
);
}
// Set new element to watch for the scroll event
if (elementSelector === "window") {
this.customData.watchScrollOnElement = window;
} else if (elementSelector === "this") {
this.customData.watchScrollOnElement = this.el;
} else {
this.customData.watchScrollOnElement = document.querySelector(
elementSelector
);
}
// Watch new element for scroll event
if (this.customData.watchScrollOnElement) {
// console.debug('addEventListener', this.customData.watchScrollOnElement);
this.customData.watchScrollOnElement.addEventListener(
"scroll",
core_1.Utils.debounce(this.customData.onScroll.bind(this)),
{ passive: true }
);
}
this.customData.offsetTop =
Number(this.el.dataset.offsetTop) || DEFAULT_OFFSET;
this.customData.offsetBottom =
Number(this.el.dataset.offsetBottom) || DEFAULT_OFFSET;
this.customData.elementSelector = elementSelector;
// inital scroll position
this.customData.onScroll();
},
unbind() {
// Remove old scroll event
if (this.customData.watchScrollOnElement) {
this.customData.watchScrollOnElement.removeEventListener(
"scroll",
core_1.Utils.debounce(this.customData.onScroll.bind(this))
);
}
},
};

@@ -1,4 +0,4 @@

export { dataScrollPositionYBinder } from './data-scroll-position-y.binder';
export { touchEventsBinder } from './touch-events.binder';
export { autoscrollBinder } from './scrollbar-autoscroll.binder';
export { scrollbarDraggableBinder } from './scrollbar-draggable.binder';
export { dataScrollPositionYBinder } from "./data-scroll-position-y.binder";
export { touchEventsBinder } from "./touch-events.binder";
export { autoscrollBinder } from "./scrollbar-autoscroll.binder";
export { scrollbarDraggableBinder } from "./scrollbar-draggable.binder";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var data_scroll_position_y_binder_1 = require("./data-scroll-position-y.binder");
exports.dataScrollPositionYBinder = data_scroll_position_y_binder_1.dataScrollPositionYBinder;
exports.dataScrollPositionYBinder =
data_scroll_position_y_binder_1.dataScrollPositionYBinder;
var touch_events_binder_1 = require("./touch-events.binder");

@@ -10,2 +11,3 @@ exports.touchEventsBinder = touch_events_binder_1.touchEventsBinder;

var scrollbar_draggable_binder_1 = require("./scrollbar-draggable.binder");
exports.scrollbarDraggableBinder = scrollbar_draggable_binder_1.scrollbarDraggableBinder;
exports.scrollbarDraggableBinder =
scrollbar_draggable_binder_1.scrollbarDraggableBinder;

@@ -1,2 +0,2 @@

import { Binder, eventHandlerFunction } from '@ribajs/core';
import { Binder, eventHandlerFunction } from "@ribajs/core";
/**

@@ -3,0 +3,0 @@ * Binds an event handler on the element.

@@ -8,40 +8,39 @@ "use strict";

exports.onEventBinder = {
name: 'on-*',
function: true,
priority: 1000,
bind(el) {
if (!this.customData) {
this.customData = {
handler: null,
};
}
},
unbind(el) {
if (this.customData.handler) {
if (this.args === null) {
throw new Error('args is null');
}
const eventName = this.args[0];
jquery_module_1.JQuery(el).off(eventName, this.customData.handler);
}
},
routine(el, value) {
if (this.args === null) {
throw new Error('args is null');
}
const eventName = this.args[0];
if (this.customData.handler) {
jquery_module_1.JQuery(el).off(eventName, this.customData.handler);
}
this.customData.handler = this.eventHandler(value, el);
try {
jquery_module_1.JQuery(el).on(eventName, (this.customData.handler));
}
catch (error) {
console.warn(error);
jquery_module_1.JQuery(el).on(eventName, (event) => {
this.customData.handler(event);
});
}
},
name: "on-*",
function: true,
priority: 1000,
bind(el) {
if (!this.customData) {
this.customData = {
handler: null,
};
}
},
unbind(el) {
if (this.customData.handler) {
if (this.args === null) {
throw new Error("args is null");
}
const eventName = this.args[0];
jquery_module_1.JQuery(el).off(eventName, this.customData.handler);
}
},
routine(el, value) {
if (this.args === null) {
throw new Error("args is null");
}
const eventName = this.args[0];
if (this.customData.handler) {
jquery_module_1.JQuery(el).off(eventName, this.customData.handler);
}
this.customData.handler = this.eventHandler(value, el);
try {
jquery_module_1.JQuery(el).on(eventName, this.customData.handler);
} catch (error) {
console.warn(error);
jquery_module_1.JQuery(el).on(eventName, (event) => {
this.customData.handler(event);
});
}
},
};

@@ -6,50 +6,53 @@ "use strict";

const riba = new core_1.Riba();
riba.module.binder.regists([on_event_binder_1.onEventBinder, core_1.valueBinder]);
describe('riba.binders', () => {
let element;
let fragment;
let model = {};
const blurAll = () => {
const tmp = document.createElement('input');
fragment.appendChild(tmp);
tmp.focus();
fragment.removeChild(tmp);
};
beforeEach(() => {
fragment = document.createDocumentFragment();
element = document.createElement('input');
element.setAttribute('type', 'text');
fragment.appendChild(element);
model = {};
riba.module.binder.regists([
on_event_binder_1.onEventBinder,
core_1.valueBinder,
]);
describe("riba.binders", () => {
let element;
let fragment;
let model = {};
const blurAll = () => {
const tmp = document.createElement("input");
fragment.appendChild(tmp);
tmp.focus();
fragment.removeChild(tmp);
};
beforeEach(() => {
fragment = document.createDocumentFragment();
element = document.createElement("input");
element.setAttribute("type", "text");
fragment.appendChild(element);
model = {};
});
describe("on-*", () => {
it("on-click: Watch's the click event", () => {
element.className = "foobar remove-me";
model.onClick = jest.fn();
element.setAttribute("rv-on-click", "onClick");
riba.bind(fragment, model);
// Simulates the click
element.click();
expect(model.onClick).toHaveBeenCalled();
});
describe('on-*', () => {
it('on-click: Watch\'s the click event', () => {
element.className = 'foobar remove-me';
model.onClick = jest.fn();
element.setAttribute('rv-on-click', 'onClick');
riba.bind(fragment, model);
// Simulates the click
element.click();
expect(model.onClick).toHaveBeenCalled();
});
it('on-change: Watch\'s the change event', () => {
element.className = 'foobar remove-me';
model.onChange = jest.fn();
model.onFocus = jest.fn();
model.onFocusout = jest.fn();
model.value = 'test';
element.setAttribute('rv-on-change', 'onChange');
element.setAttribute('rv-on-focus', 'onFocus');
element.setAttribute('rv-on-blur', 'onFocusout');
element.setAttribute('rv-value', 'value');
riba.bind(fragment, model);
// Trigger the change event
element.focus();
model.value = 'this should trigger the change event!';
blurAll(); // Focus out all focused elements
expect(model.onChange).toHaveBeenCalled();
expect(model.onFocus).toHaveBeenCalled();
expect(model.onFocusout).toHaveBeenCalled();
});
it("on-change: Watch's the change event", () => {
element.className = "foobar remove-me";
model.onChange = jest.fn();
model.onFocus = jest.fn();
model.onFocusout = jest.fn();
model.value = "test";
element.setAttribute("rv-on-change", "onChange");
element.setAttribute("rv-on-focus", "onFocus");
element.setAttribute("rv-on-blur", "onFocusout");
element.setAttribute("rv-value", "value");
riba.bind(fragment, model);
// Trigger the change event
element.focus();
model.value = "this should trigger the change event!";
blurAll(); // Focus out all focused elements
expect(model.onChange).toHaveBeenCalled();
expect(model.onFocus).toHaveBeenCalled();
expect(model.onFocusout).toHaveBeenCalled();
});
});
});

@@ -1,3 +0,3 @@

import { Binder } from '@ribajs/core';
import { AutoscrollOptions } from '../services/autoscroll.service';
import { Binder } from "@ribajs/core";
import { AutoscrollOptions } from "../services/autoscroll.service";
/**

@@ -4,0 +4,0 @@ * Slideout click event to toggle the slideout

@@ -9,26 +9,28 @@ "use strict";

exports.autoscrollBinder = {
name: 'autoscroll',
routine(el, options) {
this.customData = this.customData || {};
if (options && options.width && core_1.Utils.isString(options.width)) {
if (options.width === '100vw') {
el.style.width = options.width;
}
else {
el.style.width = options.width;
}
}
el.classList.add(`rv-autoscroll-${options.angle}`);
setTimeout(() => {
if (this.customData.autoscroll) {
this.customData.autoscroll.removeEventListeners();
}
this.customData.autoscroll = new autoscroll_service_1.Autoscroll(el, options);
}, 1000);
},
unbind() {
if (this.customData.autoscroll) {
this.customData.autoscroll.removeEventListeners();
}
},
name: "autoscroll",
routine(el, options) {
this.customData = this.customData || {};
if (options && options.width && core_1.Utils.isString(options.width)) {
if (options.width === "100vw") {
el.style.width = options.width;
} else {
el.style.width = options.width;
}
}
el.classList.add(`rv-autoscroll-${options.angle}`);
setTimeout(() => {
if (this.customData.autoscroll) {
this.customData.autoscroll.removeEventListeners();
}
this.customData.autoscroll = new autoscroll_service_1.Autoscroll(
el,
options
);
}, 1000);
},
unbind() {
if (this.customData.autoscroll) {
this.customData.autoscroll.removeEventListeners();
}
},
};

@@ -1,3 +0,3 @@

import { Binder } from '@ribajs/core';
import { DragscrollOptions } from '../services/dragscroll.service';
import { Binder } from "@ribajs/core";
import { DragscrollOptions } from "../services/dragscroll.service";
/**

@@ -4,0 +4,0 @@ * dragscroll

@@ -8,15 +8,18 @@ "use strict";

exports.scrollbarDraggableBinder = {
name: 'scrollbar-draggable',
routine(el, options) {
this.customData = this.customData || {};
if (this.customData.dragscroll) {
this.customData.dragscroll.removeEventListeners();
}
this.customData.dragscroll = new dragscroll_service_1.Dragscroll(el, options);
},
unbind() {
if (this.customData.dragscroll) {
this.customData.dragscroll.removeEventListeners();
}
},
name: "scrollbar-draggable",
routine(el, options) {
this.customData = this.customData || {};
if (this.customData.dragscroll) {
this.customData.dragscroll.removeEventListeners();
}
this.customData.dragscroll = new dragscroll_service_1.Dragscroll(
el,
options
);
},
unbind() {
if (this.customData.dragscroll) {
this.customData.dragscroll.removeEventListeners();
}
},
};

@@ -1,2 +0,2 @@

import { Binder } from '@ribajs/core';
import { Binder } from "@ribajs/core";
export declare const touchEventsBinder: Binder<string>;

@@ -5,35 +5,37 @@ "use strict";

exports.touchEventsBinder = {
name: 'touch-events',
bind(el) {
if (!this.customData) {
this.customData = {};
}
this.customData.touchEventService = new touch_events_service_1.TouchEventService(el);
el.addEventListener('tapstart', (event) => {
console.debug('tapstart detail', event.detail);
});
el.addEventListener('taphold', (event) => {
console.debug('taphold detail', event.detail);
});
el.addEventListener('doubletap', (event) => {
console.debug('doubletap detail', event.detail);
});
el.addEventListener('swipe', (event) => {
console.debug('swipe detail', event.detail);
});
el.addEventListener('touchstart', (event) => {
console.debug('touchstart', event);
});
el.addEventListener('touchmove', (event) => {
console.debug('touchmove', event);
});
},
unbind(el) {
if (this.customData.touchEventService) {
this.customData.touchEventService.removeEventListeners();
}
},
routine(el, value) {
// nothing
},
name: "touch-events",
bind(el) {
if (!this.customData) {
this.customData = {};
}
this.customData.touchEventService = new touch_events_service_1.TouchEventService(
el
);
el.addEventListener("tapstart", (event) => {
console.debug("tapstart detail", event.detail);
});
el.addEventListener("taphold", (event) => {
console.debug("taphold detail", event.detail);
});
el.addEventListener("doubletap", (event) => {
console.debug("doubletap detail", event.detail);
});
el.addEventListener("swipe", (event) => {
console.debug("swipe detail", event.detail);
});
el.addEventListener("touchstart", (event) => {
console.debug("touchstart", event);
});
el.addEventListener("touchmove", (event) => {
console.debug("touchmove", event);
});
},
unbind(el) {
if (this.customData.touchEventService) {
this.customData.touchEventService.removeEventListeners();
}
},
routine(el, value) {
// nothing
},
};

@@ -5,22 +5,24 @@ "use strict";

const touch_events_binder_1 = require("./touch-events.binder");
describe('riba.binders', () => {
let el;
const riba = new core_1.Riba();
riba.module.binder.regist(touch_events_binder_1.TouchEventsBinder);
beforeEach(() => {
el = document.createElement('div');
document.body.appendChild(el);
describe("riba.binders", () => {
let el;
const riba = new core_1.Riba();
riba.module.binder.regist(touch_events_binder_1.TouchEventsBinder);
beforeEach(() => {
el = document.createElement("div");
document.body.appendChild(el);
});
afterEach(() => {
if (!el.parentNode) {
throw new Error("el.parentNode is not defined!");
}
el.parentNode.removeChild(el);
});
describe("TouchEvents", () => {
it("sets the element's text content", () => {
riba.binders["test-app-example"].routine(el, "<em>hello</em>");
expect(el.innerHTML).toEqual(
"<em>hello</em> from test-app-example <strong>binder</strong>!"
);
});
afterEach(() => {
if (!el.parentNode) {
throw new Error('el.parentNode is not defined!');
}
el.parentNode.removeChild(el);
});
describe('TouchEvents', () => {
it('sets the element\'s text content', () => {
riba.binders['test-app-example'].routine(el, '<em>hello</em>');
expect(el.innerHTML).toEqual('<em>hello</em> from test-app-example <strong>binder</strong>!');
});
});
});
});

@@ -1,4 +0,4 @@

export * from './binders';
export * from './services';
import { RibaModule } from '@ribajs/core';
export * from "./binders";
export * from "./services";
import { RibaModule } from "@ribajs/core";
export declare const extrasModule: RibaModule;
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
var __importStar = (this && this.__importStar) || function (mod) {
var __importStar =
(this && this.__importStar) ||
function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
if (mod != null)
for (var k in mod)
if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -23,6 +27,9 @@ __export(require("./binders"));

exports.extrasModule = {
formatters: {},
binders,
services: { TouchEventService: services_1.TouchEventService, Autoscroll: services_1.Autoscroll },
components: {},
formatters: {},
binders,
services: {
TouchEventService: services_1.TouchEventService,
Autoscroll: services_1.Autoscroll,
},
components: {},
};

@@ -1,6 +0,6 @@

export * from './services';
export * from './binders';
import { extrasModule } from './extras.module';
export * from "./services";
export * from "./binders";
import { extrasModule } from "./extras.module";
export { extrasModule };
export default extrasModule;
export * from './types';
export * from "./types";
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}

@@ -5,0 +5,0 @@ Object.defineProperty(exports, "__esModule", { value: true });

@@ -1,2 +0,2 @@

import { RibaModule } from '@ribajs/core';
import { RibaModule } from "@ribajs/core";
export declare const jqueryModule: RibaModule;
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
var __importStar =
(this && this.__importStar) ||
function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
if (mod != null)
for (var k in mod)
if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -15,6 +19,6 @@ const binders = __importStar(require("./binders"));

exports.jqueryModule = {
formatters: {},
binders,
services: {},
components: {},
formatters: {},
binders,
services: {},
components: {},
};
export interface AutoscrollOptions {
angle?: 'vertical' | 'horizontal';
direction?: 1 | -1;
velocity?: number;
width?: string;
pauseOnHover?: boolean;
angle?: "vertical" | "horizontal";
direction?: 1 | -1;
velocity?: number;
width?: string;
pauseOnHover?: boolean;
}
export declare class Autoscroll {
protected direction: number;
protected limit: number;
protected options: AutoscrollOptions;
protected el: HTMLElement;
protected pause: boolean;
protected velocity: number;
protected move: number;
protected lastMove: number;
protected position: number;
protected angle: 'horizontal' | 'vertical';
protected pauseOnHover: boolean;
constructor(el: HTMLElement, options?: AutoscrollOptions);
removeEventListeners(): void;
protected onMouseIn(): void;
protected onMouseOut(): void;
protected onResize(): void;
protected onTouchEnd(): void;
protected getPosition(): number;
protected getLimit(el: HTMLElement, options: AutoscrollOptions): number;
protected render(interp: number): void;
protected update(delta: number): void;
protected scroll(move: number): void;
protected direction: number;
protected limit: number;
protected options: AutoscrollOptions;
protected el: HTMLElement;
protected pause: boolean;
protected velocity: number;
protected move: number;
protected lastMove: number;
protected position: number;
protected angle: "horizontal" | "vertical";
protected pauseOnHover: boolean;
constructor(el: HTMLElement, options?: AutoscrollOptions);
removeEventListeners(): void;
protected onMouseIn(): void;
protected onMouseOut(): void;
protected onResize(): void;
protected onTouchEnd(): void;
protected getPosition(): number;
protected getLimit(el: HTMLElement, options: AutoscrollOptions): number;
protected render(interp: number): void;
protected update(delta: number): void;
protected scroll(move: number): void;
}

@@ -6,100 +6,111 @@ "use strict";

class Autoscroll {
constructor(el, options = {}) {
this.direction = 1;
this.pause = false;
this.velocity = 0.008;
this.move = 0;
this.lastMove = 0;
this.angle = 'horizontal';
this.pauseOnHover = true;
this.el = el;
this.options = options;
this.direction = this.options.direction || this.direction;
this.velocity = this.options.velocity || this.velocity;
this.angle = this.options.angle || this.angle;
this.pauseOnHover = typeof (this.options.pauseOnHover) === 'boolean' ? this.options.pauseOnHover : this.pauseOnHover;
this.limit = this.getLimit(this.el, this.options);
this.position = this.getPosition();
window.addEventListener('resize', this.onResize.bind(this));
if (this.direction === -1) {
// start right
this.el.scrollLeft = this.limit;
}
else {
// start left
this.el.scrollLeft = 0;
}
this.el.addEventListener('mouseenter', this.onMouseIn.bind(this));
this.el.addEventListener('mouseover', this.onMouseIn.bind(this));
this.el.addEventListener('mouseout', this.onMouseOut.bind(this));
this.el.addEventListener('mouseleave', this.onMouseOut.bind(this));
this.el.addEventListener('mouseup', this.onTouchEnd.bind(this));
this.el.addEventListener('touchend', this.onTouchEnd.bind(this));
gameloop_service_1.Gameloop.startLoop({ maxFPS: 60 }, this.render.bind(this), this.update.bind(this));
constructor(el, options = {}) {
this.direction = 1;
this.pause = false;
this.velocity = 0.008;
this.move = 0;
this.lastMove = 0;
this.angle = "horizontal";
this.pauseOnHover = true;
this.el = el;
this.options = options;
this.direction = this.options.direction || this.direction;
this.velocity = this.options.velocity || this.velocity;
this.angle = this.options.angle || this.angle;
this.pauseOnHover =
typeof this.options.pauseOnHover === "boolean"
? this.options.pauseOnHover
: this.pauseOnHover;
this.limit = this.getLimit(this.el, this.options);
this.position = this.getPosition();
window.addEventListener("resize", this.onResize.bind(this));
if (this.direction === -1) {
// start right
this.el.scrollLeft = this.limit;
} else {
// start left
this.el.scrollLeft = 0;
}
removeEventListeners() {
window.removeEventListener('resize', this.onResize.bind(this));
this.el.removeEventListener('mouseenter', this.onMouseIn.bind(this));
this.el.removeEventListener('mouseover', this.onMouseIn.bind(this));
this.el.removeEventListener('mouseout', this.onMouseOut.bind(this));
this.el.removeEventListener('mouseleave', this.onMouseOut.bind(this));
this.el.removeEventListener('mouseup', this.onTouchEnd.bind(this));
this.el.removeEventListener('touchend', this.onTouchEnd.bind(this));
this.el.addEventListener("mouseenter", this.onMouseIn.bind(this));
this.el.addEventListener("mouseover", this.onMouseIn.bind(this));
this.el.addEventListener("mouseout", this.onMouseOut.bind(this));
this.el.addEventListener("mouseleave", this.onMouseOut.bind(this));
this.el.addEventListener("mouseup", this.onTouchEnd.bind(this));
this.el.addEventListener("touchend", this.onTouchEnd.bind(this));
gameloop_service_1.Gameloop.startLoop(
{ maxFPS: 60 },
this.render.bind(this),
this.update.bind(this)
);
}
removeEventListeners() {
window.removeEventListener("resize", this.onResize.bind(this));
this.el.removeEventListener("mouseenter", this.onMouseIn.bind(this));
this.el.removeEventListener("mouseover", this.onMouseIn.bind(this));
this.el.removeEventListener("mouseout", this.onMouseOut.bind(this));
this.el.removeEventListener("mouseleave", this.onMouseOut.bind(this));
this.el.removeEventListener("mouseup", this.onTouchEnd.bind(this));
this.el.removeEventListener("touchend", this.onTouchEnd.bind(this));
}
onMouseIn() {
if (this.pauseOnHover) {
this.pause = true;
}
onMouseIn() {
if (this.pauseOnHover) {
this.pause = true;
}
}
onMouseOut() {
this.pause = false;
}
onResize() {
this.limit = this.getLimit(this.el, this.options);
this.pause = false;
}
onTouchEnd() {
this.position =
this.angle === "vertical" ? this.el.scrollTop : this.el.scrollLeft;
}
getPosition() {
return (
(this.angle === "vertical" ? this.el.scrollTop : this.el.scrollLeft) || 0
);
}
getLimit(el, options) {
return this.angle === "vertical"
? utils_service_1.Utils.getScrollPosition(el).maxY
: utils_service_1.Utils.getScrollPosition(el).maxX;
}
render(interp) {
if (this.pause) {
return;
}
onMouseOut() {
this.pause = false;
const move = this.lastMove + (this.move - this.lastMove) * interp;
this.move = 0;
this.scroll(move);
}
update(delta) {
// console.debug('delta', delta);
if (this.pause) {
return;
}
onResize() {
this.limit = this.getLimit(this.el, this.options);
this.pause = false;
this.lastMove = this.move;
this.move += this.velocity * delta;
// Switch directions if we go too far
// `Math.floor()` rounds down, `Math.ceil()` rounds up, `Math.round()` rounds to the nearest integer
if (Math.floor(this.position) <= 0 && this.direction !== 1) {
this.direction = 1;
}
onTouchEnd() {
this.position = this.angle === 'vertical' ? this.el.scrollTop : this.el.scrollLeft;
if (Math.ceil(this.position) >= this.limit && this.direction !== -1) {
this.direction = -1;
}
getPosition() {
return (this.angle === 'vertical' ? this.el.scrollTop : this.el.scrollLeft) || 0;
}
scroll(move) {
const newPosition =
this.direction > 0 ? this.position + move : this.position - move;
if (this.angle === "vertical") {
this.el.scrollTop = Math.ceil(newPosition);
} else {
this.el.scrollLeft = Math.ceil(newPosition);
}
getLimit(el, options) {
return this.angle === 'vertical' ? utils_service_1.Utils.getScrollPosition(el).maxY : utils_service_1.Utils.getScrollPosition(el).maxX;
}
render(interp) {
if (this.pause) {
return;
}
const move = (this.lastMove + (this.move - this.lastMove) * interp);
this.move = 0;
this.scroll(move);
}
update(delta) {
// console.debug('delta', delta);
if (this.pause) {
return;
}
this.lastMove = this.move;
this.move += (this.velocity * delta);
// Switch directions if we go too far
// `Math.floor()` rounds down, `Math.ceil()` rounds up, `Math.round()` rounds to the nearest integer
if (Math.floor(this.position) <= 0 && this.direction !== 1) {
this.direction = 1;
}
if (Math.ceil(this.position) >= this.limit && this.direction !== -1) {
this.direction = -1;
}
}
scroll(move) {
const newPosition = this.direction > 0 ? this.position + move : this.position - move;
if (this.angle === 'vertical') {
this.el.scrollTop = Math.ceil(newPosition);
}
else {
this.el.scrollLeft = Math.ceil(newPosition);
}
this.position = newPosition;
}
this.position = newPosition;
}
}
exports.Autoscroll = Autoscroll;
export interface DragscrollOptions {
preventDefault?: boolean;
detectGlobalMove?: boolean;
preventDefault?: boolean;
detectGlobalMove?: boolean;
}

@@ -10,13 +10,13 @@ /**

export declare class Dragscroll {
private options;
private lastClientX;
private lastClientY;
private el;
private pushed;
constructor(el: HTMLElement, options?: DragscrollOptions);
removeEventListeners(): void;
protected checkDraggable(): void;
protected onMouseDown<EventListener>(e: MouseEvent): void;
protected onMouseUp<EventListener>(e: MouseEvent): void;
protected onMouseMove<EventListener>(e: MouseEvent): void;
private options;
private lastClientX;
private lastClientY;
private el;
private pushed;
constructor(el: HTMLElement, options?: DragscrollOptions);
removeEventListeners(): void;
protected checkDraggable(): void;
protected onMouseDown<EventListener>(e: MouseEvent): void;
protected onMouseUp<EventListener>(e: MouseEvent): void;
protected onMouseMove<EventListener>(e: MouseEvent): void;
}

@@ -9,78 +9,90 @@ "use strict";

class Dragscroll {
constructor(el, options = { detectGlobalMove: true, preventDefault: true }) {
this.lastClientX = 0;
this.lastClientY = 0;
this.pushed = false;
this.el = el;
this.options = options;
el.removeEventListener('mousedown', this.onMouseDown.bind(this), false);
el.addEventListener('mousedown', this.onMouseDown.bind(this), false);
window.addEventListener('resize', this.checkDraggable.bind(this));
// Use global move if your element does not use the full width / height
if (this.options.detectGlobalMove) {
window.removeEventListener('mouseup', this.onMouseUp.bind(this), false);
window.removeEventListener('mousemove', this.onMouseMove.bind(this), false);
window.addEventListener('mouseup', this.onMouseUp.bind(this), false);
window.addEventListener('mousemove', this.onMouseMove.bind(this), false);
}
else {
el.removeEventListener('mouseup', this.onMouseUp.bind(this), false);
el.removeEventListener('mousemove', this.onMouseMove.bind(this), false);
el.addEventListener('mouseup', this.onMouseUp.bind(this), false);
el.addEventListener('mousemove', this.onMouseMove.bind(this), false);
}
// initial
this.checkDraggable();
constructor(el, options = { detectGlobalMove: true, preventDefault: true }) {
this.lastClientX = 0;
this.lastClientY = 0;
this.pushed = false;
this.el = el;
this.options = options;
el.removeEventListener("mousedown", this.onMouseDown.bind(this), false);
el.addEventListener("mousedown", this.onMouseDown.bind(this), false);
window.addEventListener("resize", this.checkDraggable.bind(this));
// Use global move if your element does not use the full width / height
if (this.options.detectGlobalMove) {
window.removeEventListener("mouseup", this.onMouseUp.bind(this), false);
window.removeEventListener(
"mousemove",
this.onMouseMove.bind(this),
false
);
window.addEventListener("mouseup", this.onMouseUp.bind(this), false);
window.addEventListener("mousemove", this.onMouseMove.bind(this), false);
} else {
el.removeEventListener("mouseup", this.onMouseUp.bind(this), false);
el.removeEventListener("mousemove", this.onMouseMove.bind(this), false);
el.addEventListener("mouseup", this.onMouseUp.bind(this), false);
el.addEventListener("mousemove", this.onMouseMove.bind(this), false);
}
removeEventListeners() {
window.removeEventListener('resize', this.checkDraggable);
this.el.removeEventListener('mousedown', this.onMouseDown.bind(this), false);
this.el.removeEventListener('mouseup', this.onMouseUp.bind(this), false);
this.el.removeEventListener('mousemove', this.onMouseMove.bind(this), false);
// initial
this.checkDraggable();
}
removeEventListeners() {
window.removeEventListener("resize", this.checkDraggable);
this.el.removeEventListener(
"mousedown",
this.onMouseDown.bind(this),
false
);
this.el.removeEventListener("mouseup", this.onMouseUp.bind(this), false);
this.el.removeEventListener(
"mousemove",
this.onMouseMove.bind(this),
false
);
}
checkDraggable() {
if (utils_service_1.Utils.isScrollable(this.el)) {
this.el.classList.add("draggable");
} else {
this.el.classList.remove("draggable");
}
checkDraggable() {
if (utils_service_1.Utils.isScrollable(this.el)) {
this.el.classList.add('draggable');
}
else {
this.el.classList.remove('draggable');
}
}
// protected triggerScrollendEvent(originalEvent: Event) {
// const extraParameters: any = Utils.getScrollPosition(originalEvent.target as HTMLElement);
// extraParameters.originalEvent = originalEvent;
// extraParameters.target = originalEvent.target;
// const scrollendEvent = new CustomEvent('scrollend', {
// detail: extraParameters,
// });
// this.el.dispatchEvent(scrollendEvent);
// }
onMouseDown(e) {
this.pushed = true;
this.lastClientX = e.clientX;
this.lastClientY = e.clientY;
if (this.options.preventDefault) {
e.preventDefault();
}
// protected triggerScrollendEvent(originalEvent: Event) {
// const extraParameters: any = Utils.getScrollPosition(originalEvent.target as HTMLElement);
// extraParameters.originalEvent = originalEvent;
// extraParameters.target = originalEvent.target;
// const scrollendEvent = new CustomEvent('scrollend', {
// detail: extraParameters,
// });
// this.el.dispatchEvent(scrollendEvent);
// }
onMouseDown(e) {
this.pushed = true;
this.lastClientX = e.clientX;
this.lastClientY = e.clientY;
if (this.options.preventDefault) {
e.preventDefault();
}
onMouseUp(e) {
this.pushed = false;
// this.triggerScrollendEvent(e);
}
onMouseMove(e) {
let newScrollX = 0;
let newScrollY = 0;
if (this.pushed) {
this.el.scrollLeft -= newScrollX =
-this.lastClientX + (this.lastClientX = e.clientX);
this.el.scrollTop -= newScrollY =
-this.lastClientY + (this.lastClientY = e.clientY);
if (this.el === document.body) {
if (document.documentElement) {
this.el = document.documentElement;
}
this.el.scrollLeft -= newScrollX;
this.el.scrollTop -= newScrollY;
}
}
onMouseUp(e) {
this.pushed = false;
// this.triggerScrollendEvent(e);
}
onMouseMove(e) {
let newScrollX = 0;
let newScrollY = 0;
if (this.pushed) {
this.el.scrollLeft -= newScrollX = (-this.lastClientX + (this.lastClientX = e.clientX));
this.el.scrollTop -= newScrollY = (-this.lastClientY + (this.lastClientY = e.clientY));
if (this.el === document.body) {
if (document.documentElement) {
this.el = document.documentElement;
}
this.el.scrollLeft -= newScrollX;
this.el.scrollTop -= newScrollY;
}
}
}
}
}
exports.Dragscroll = Dragscroll;
export declare type RenderCallback = (interp: number) => void;
export declare type UpdateCallback = (delta: number) => void;
export interface GameloopOptions {
maxFPS?: number;
maxFPS?: number;
}

@@ -11,26 +11,30 @@ /**

export declare class Gameloop {
static maxFPS: number;
static startLoop(options?: GameloopOptions, renderCallback?: RenderCallback, updateCallback?: UpdateCallback): void;
protected static renderCallbacks: RenderCallback[];
protected static updateCallbacks: UpdateCallback[];
protected static timestep: number;
protected static loopStarted: boolean;
protected static lastFrameTimeMs: number;
protected static delta: number;
protected static fps: number;
protected static framesThisSecond: number;
protected static lastFpsUpdate: number;
protected static setOptions(options: GameloopOptions): void;
/**
* The main / game loop
* @param timestamp
*/
protected static loop(timestamp: number): void;
protected static begin(timestamp: number, delta: number): void;
protected static render(interp: number): void;
protected static update(delta: number): void;
protected static addRenderCallback(renderCallback: RenderCallback): void;
protected static addUpdateCallback(updateCallback: UpdateCallback): void;
protected static panic(): void;
constructor(options?: GameloopOptions);
static maxFPS: number;
static startLoop(
options?: GameloopOptions,
renderCallback?: RenderCallback,
updateCallback?: UpdateCallback
): void;
protected static renderCallbacks: RenderCallback[];
protected static updateCallbacks: UpdateCallback[];
protected static timestep: number;
protected static loopStarted: boolean;
protected static lastFrameTimeMs: number;
protected static delta: number;
protected static fps: number;
protected static framesThisSecond: number;
protected static lastFpsUpdate: number;
protected static setOptions(options: GameloopOptions): void;
/**
* The main / game loop
* @param timestamp
*/
protected static loop(timestamp: number): void;
protected static begin(timestamp: number, delta: number): void;
protected static render(interp: number): void;
protected static update(delta: number): void;
protected static addRenderCallback(renderCallback: RenderCallback): void;
protected static addUpdateCallback(updateCallback: UpdateCallback): void;
protected static panic(): void;
constructor(options?: GameloopOptions);
}

@@ -8,84 +8,85 @@ "use strict";

class Gameloop {
constructor(options = {}) {
Gameloop.setOptions(options);
constructor(options = {}) {
Gameloop.setOptions(options);
}
static startLoop(options = {}, renderCallback, updateCallback) {
this.setOptions(options);
if (renderCallback) {
this.addRenderCallback(renderCallback);
}
static startLoop(options = {}, renderCallback, updateCallback) {
this.setOptions(options);
if (renderCallback) {
this.addRenderCallback(renderCallback);
}
if (updateCallback) {
this.addUpdateCallback(updateCallback);
}
if (!this.loopStarted) {
this.loopStarted = true;
window.requestAnimationFrame(this.loop.bind(this));
}
if (updateCallback) {
this.addUpdateCallback(updateCallback);
}
static setOptions(options) {
this.maxFPS = typeof (options.maxFPS) === 'number' ? options.maxFPS : this.maxFPS;
if (!this.loopStarted) {
this.loopStarted = true;
window.requestAnimationFrame(this.loop.bind(this));
}
/**
* The main / game loop
* @param timestamp
*/
static loop(timestamp) {
// Throttle the frame rate.
if (timestamp < this.lastFrameTimeMs + (1000 / this.maxFPS)) {
requestAnimationFrame(this.loop.bind(this));
return;
}
const progress = timestamp - this.lastFrameTimeMs;
this.delta += progress;
this.lastFrameTimeMs = timestamp;
this.begin(timestamp, this.delta);
if (timestamp > this.lastFpsUpdate + 1000) {
this.fps = 0.25 * this.framesThisSecond + 0.75 * this.fps;
this.lastFpsUpdate = timestamp;
this.framesThisSecond = 0;
}
this.framesThisSecond++;
let numUpdateSteps = 0;
while (this.delta >= this.timestep) {
this.update(this.timestep);
this.delta -= this.timestep;
if (++numUpdateSteps >= 240) {
this.panic();
break;
}
}
this.render(this.delta / this.timestep);
window.requestAnimationFrame(this.loop.bind(this));
}
static setOptions(options) {
this.maxFPS =
typeof options.maxFPS === "number" ? options.maxFPS : this.maxFPS;
}
/**
* The main / game loop
* @param timestamp
*/
static loop(timestamp) {
// Throttle the frame rate.
if (timestamp < this.lastFrameTimeMs + 1000 / this.maxFPS) {
requestAnimationFrame(this.loop.bind(this));
return;
}
static begin(timestamp, delta) {
//
const progress = timestamp - this.lastFrameTimeMs;
this.delta += progress;
this.lastFrameTimeMs = timestamp;
this.begin(timestamp, this.delta);
if (timestamp > this.lastFpsUpdate + 1000) {
this.fps = 0.25 * this.framesThisSecond + 0.75 * this.fps;
this.lastFpsUpdate = timestamp;
this.framesThisSecond = 0;
}
static render(interp) {
for (const renderCallback of this.renderCallbacks) {
if (typeof (renderCallback) === 'function') {
renderCallback(interp);
}
}
this.framesThisSecond++;
let numUpdateSteps = 0;
while (this.delta >= this.timestep) {
this.update(this.timestep);
this.delta -= this.timestep;
if (++numUpdateSteps >= 240) {
this.panic();
break;
}
}
static update(delta) {
for (const updateCallback of this.updateCallbacks) {
if (typeof (updateCallback) === 'function') {
updateCallback(delta);
}
}
this.render(this.delta / this.timestep);
window.requestAnimationFrame(this.loop.bind(this));
}
static begin(timestamp, delta) {
//
}
static render(interp) {
for (const renderCallback of this.renderCallbacks) {
if (typeof renderCallback === "function") {
renderCallback(interp);
}
}
static addRenderCallback(renderCallback) {
this.renderCallbacks.push(renderCallback);
}
static update(delta) {
for (const updateCallback of this.updateCallbacks) {
if (typeof updateCallback === "function") {
updateCallback(delta);
}
}
static addUpdateCallback(updateCallback) {
this.updateCallbacks.push(updateCallback);
}
static panic() {
this.delta = 0; // discard the unsimulated time
}
}
static addRenderCallback(renderCallback) {
this.renderCallbacks.push(renderCallback);
}
static addUpdateCallback(updateCallback) {
this.updateCallbacks.push(updateCallback);
}
static panic() {
this.delta = 0; // discard the unsimulated time
}
}
exports.Gameloop = Gameloop;
Gameloop.maxFPS = 60;
Gameloop.renderCallbacks = new Array();
Gameloop.updateCallbacks = new Array();
Gameloop.renderCallbacks = [];
Gameloop.updateCallbacks = [];
// We want to simulate 1000 ms / 60 FPS = 16.667 ms per frame every time we run scroll()

@@ -92,0 +93,0 @@ Gameloop.timestep = 1000 / 60;

@@ -1,6 +0,6 @@

export * from './autoscroll.service';
export * from './dragscroll.service';
export * from './gameloop.service';
export * from './touch-events/scroll-events.service';
export * from './touch-events/touch-events.service';
export * from './utils.service';
export * from "./autoscroll.service";
export * from "./dragscroll.service";
export * from "./gameloop.service";
export * from "./touch-events/scroll-events.service";
export * from "./touch-events/touch-events.service";
export * from "./utils.service";
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}

@@ -5,0 +5,0 @@ Object.defineProperty(exports, "__esModule", { value: true });

@@ -1,2 +0,2 @@

import { Position } from '../types';
import { Position } from "../types";
/**

@@ -29,130 +29,152 @@ * Vanilla version of jQuery Mobile Events

export interface Settings {
tapPixelRange: number;
swipeHThreshold: number;
swipeVThreshold: number;
tapholdThreshold: number;
doubletapInterval: number;
shakeThreshold: number;
touchCapable: boolean;
startevent: Array<'touchstart' | 'mousedown'>;
endevent: Array<'touchend' | 'touchcancel' | 'mouseup'>;
moveevent: Array<'touchmove' | 'mousemove'>;
tapevent: Array<'tap' | 'click'>;
scrollevent: Array<'touchmove' | 'scroll'>;
tapPixelRange: number;
swipeHThreshold: number;
swipeVThreshold: number;
tapholdThreshold: number;
doubletapInterval: number;
shakeThreshold: number;
touchCapable: boolean;
startevent: Array<"touchstart" | "mousedown">;
endevent: Array<"touchend" | "touchcancel" | "mouseup">;
moveevent: Array<"touchmove" | "mousemove">;
tapevent: Array<"tap" | "click">;
scrollevent: Array<"touchmove" | "scroll">;
}
export interface Offset {
x: number;
y: number;
x: number;
y: number;
}
export interface TouchData {
position: Position;
offset: Offset;
time: number;
index?: number;
position: Position;
offset: Offset;
time: number;
index?: number;
}
export declare enum TouchType {
DEFAULT = 0,
TARGET = 1,
CHANGED = 2
DEFAULT = 0,
TARGET = 1,
CHANGED = 2,
}
export declare class TouchEventService {
get isTouchCapable(): boolean;
get startEvent(): ("mousedown" | "touchstart")[];
get endEvent(): ("mouseup" | "touchcancel" | "touchend")[];
get moveEvent(): ("mousemove" | "touchmove")[];
get tapEvent(): ("click" | "tap")[];
get scrollEvent(): ("scroll" | "touchmove")[];
/** Set the X threshold of swipe events */
set swipeThresholdX(threshold: number);
/** Set the Y threshold of swipe events */
set swipeThresholdY(threshold: number);
/** Set the double tap interval */
set doubleTapInt(interval: number);
/** Set the taphold threshold */
set tapHoldThreshold(threshold: number);
/** Set the pixel range for tapas */
set tapRange(range: number);
protected el: HTMLElement;
/** Used internally for `taphold` */
protected startPosition: Position;
/** Used internally for `taphold` */
protected endPosition: Position;
/** Used internally for `swipe` */
protected originalCoord: Position;
/** Used internally for `swipe` */
protected finalCoord: Position;
/** Used internally for `scrollstart` and `scrollend` */
protected scrollPosition: Position | null;
/** Used internally for `swipe` */
protected startEvnt: TouchData | null;
/** Used internally for `taphold` and `singletap` */
protected tapheld: boolean;
/** Used internally for `doubletap` */
protected firstTap: TouchData | null;
/** Used internally for `doubletap` */
protected cooling: boolean;
/** Used internally for `doubletap` and `singletap` */
protected doubletapped: boolean;
/** Used internally for `doubletap` */
protected lastTouch: number;
/** Used internally for `swipe` */
protected hasSwiped: boolean;
/** Used internally for `tap` */
protected tapStarted: boolean;
/** Used internally for `swipe` */
protected swipeStarted: boolean;
/** Used internally for `tap`, `taphold` and `singletap` */
protected startTime: number;
protected holdTimer: number;
protected tapTimer: number;
/** Used internally for `doubletap` */
protected actionTimer: number;
protected scrollTimer: number;
protected settings: Settings;
constructor(el: HTMLElement, settings?: Settings);
removeEventListeners(): void;
protected triggerCustomEvent(eventName: string, originalEvent: Event, extraParameters?: any): void;
protected getSwipeDir(startPosition: Position, endPosition: Position, hThreshold?: number, vThreshold?: number): string;
protected getPostion(event: TouchEvent | MouseEvent, type?: TouchType, index?: number): Position;
protected getOffset(event: TouchEvent | MouseEvent, type?: TouchType, index?: number): Offset;
protected getTouchData(event: TouchEvent | MouseEvent, withIndex?: boolean, positionType?: TouchType, offsetType?: TouchType): TouchData;
protected addEventListeners(): void;
protected onStartEvent(event: TouchEvent | MouseEvent): boolean;
protected onEndEvent(event: TouchEvent | MouseEvent): boolean;
protected onMoveEvent(event: TouchEvent | MouseEvent): boolean;
protected onScrollEvent(event: TouchEvent | MouseEvent): boolean;
/** tapstart Event */
protected tapstart(event: TouchEvent | MouseEvent): boolean;
/** tapmove Event */
protected tapmove(event: TouchEvent | MouseEvent): boolean;
/** tapend Event */
protected tapend(event: TouchEvent | MouseEvent): boolean;
/** taphold Event */
protected taphold(event: TouchEvent | MouseEvent): boolean;
/** doubletap Event */
protected doubletap(event: TouchEvent | MouseEvent): void;
/**
* singletap Event
* This is used in conjuction with doubletap when both events are needed on the same element
*/
protected singletap(event: TouchEvent | MouseEvent): void;
/** tap Event */
protected tap(event: TouchEvent | MouseEvent): void;
/**
* swipe Event
* (also handles swipeup, swiperight, swipedown and swipeleft)
*
* (similar to `touchMove` method in jquery touch events)
*/
protected swipe(event: TouchEvent | MouseEvent): void;
/**
* swipeend Event
* (similar `touchEnd` method in jquery touch events)
*/
protected swipeend(event: TouchEvent | MouseEvent): void;
/**
* scrollstart Event
* (also handles `scrollend`)
*/
protected scrollstart(event: TouchEvent | MouseEvent): false | undefined;
get isTouchCapable(): boolean;
get startEvent(): ("mousedown" | "touchstart")[];
get endEvent(): ("mouseup" | "touchcancel" | "touchend")[];
get moveEvent(): ("mousemove" | "touchmove")[];
get tapEvent(): ("click" | "tap")[];
get scrollEvent(): ("scroll" | "touchmove")[];
/** Set the X threshold of swipe events */
set swipeThresholdX(threshold: number);
/** Set the Y threshold of swipe events */
set swipeThresholdY(threshold: number);
/** Set the double tap interval */
set doubleTapInt(interval: number);
/** Set the taphold threshold */
set tapHoldThreshold(threshold: number);
/** Set the pixel range for tapas */
set tapRange(range: number);
protected el: HTMLElement;
/** Used internally for `taphold` */
protected startPosition: Position;
/** Used internally for `taphold` */
protected endPosition: Position;
/** Used internally for `swipe` */
protected originalCoord: Position;
/** Used internally for `swipe` */
protected finalCoord: Position;
/** Used internally for `scrollstart` and `scrollend` */
protected scrollPosition: Position | null;
/** Used internally for `swipe` */
protected startEvnt: TouchData | null;
/** Used internally for `taphold` and `singletap` */
protected tapheld: boolean;
/** Used internally for `doubletap` */
protected firstTap: TouchData | null;
/** Used internally for `doubletap` */
protected cooling: boolean;
/** Used internally for `doubletap` and `singletap` */
protected doubletapped: boolean;
/** Used internally for `doubletap` */
protected lastTouch: number;
/** Used internally for `swipe` */
protected hasSwiped: boolean;
/** Used internally for `tap` */
protected tapStarted: boolean;
/** Used internally for `swipe` */
protected swipeStarted: boolean;
/** Used internally for `tap`, `taphold` and `singletap` */
protected startTime: number;
protected holdTimer: number;
protected tapTimer: number;
/** Used internally for `doubletap` */
protected actionTimer: number;
protected scrollTimer: number;
protected settings: Settings;
constructor(el: HTMLElement, settings?: Settings);
removeEventListeners(): void;
protected triggerCustomEvent(
eventName: string,
originalEvent: Event,
extraParameters?: any
): void;
protected getSwipeDir(
startPosition: Position,
endPosition: Position,
hThreshold?: number,
vThreshold?: number
): string;
protected getPostion(
event: TouchEvent | MouseEvent,
type?: TouchType,
index?: number
): Position;
protected getOffset(
event: TouchEvent | MouseEvent,
type?: TouchType,
index?: number
): Offset;
protected getTouchData(
event: TouchEvent | MouseEvent,
withIndex?: boolean,
positionType?: TouchType,
offsetType?: TouchType
): TouchData;
protected addEventListeners(): void;
protected onStartEvent(event: TouchEvent | MouseEvent): boolean;
protected onEndEvent(event: TouchEvent | MouseEvent): boolean;
protected onMoveEvent(event: TouchEvent | MouseEvent): boolean;
protected onScrollEvent(event: TouchEvent | MouseEvent): boolean;
/** tapstart Event */
protected tapstart(event: TouchEvent | MouseEvent): boolean;
/** tapmove Event */
protected tapmove(event: TouchEvent | MouseEvent): boolean;
/** tapend Event */
protected tapend(event: TouchEvent | MouseEvent): boolean;
/** taphold Event */
protected taphold(event: TouchEvent | MouseEvent): boolean;
/** doubletap Event */
protected doubletap(event: TouchEvent | MouseEvent): void;
/**
* singletap Event
* This is used in conjuction with doubletap when both events are needed on the same element
*/
protected singletap(event: TouchEvent | MouseEvent): void;
/** tap Event */
protected tap(event: TouchEvent | MouseEvent): void;
/**
* swipe Event
* (also handles swipeup, swiperight, swipedown and swipeleft)
*
* (similar to `touchMove` method in jquery touch events)
*/
protected swipe(event: TouchEvent | MouseEvent): void;
/**
* swipeend Event
* (similar `touchEnd` method in jquery touch events)
*/
protected swipeend(event: TouchEvent | MouseEvent): void;
/**
* scrollstart Event
* (also handles `scrollend`)
*/
protected scrollstart(event: TouchEvent | MouseEvent): false | undefined;
}

@@ -7,548 +7,665 @@ "use strict";

(function (TouchType) {
TouchType[TouchType["DEFAULT"] = 0] = "DEFAULT";
TouchType[TouchType["TARGET"] = 1] = "TARGET";
TouchType[TouchType["CHANGED"] = 2] = "CHANGED";
})(TouchType = exports.TouchType || (exports.TouchType = {}));
TouchType[(TouchType["DEFAULT"] = 0)] = "DEFAULT";
TouchType[(TouchType["TARGET"] = 1)] = "TARGET";
TouchType[(TouchType["CHANGED"] = 2)] = "CHANGED";
})((TouchType = exports.TouchType || (exports.TouchType = {})));
class TouchEventService {
constructor(el, settings = {
tapPixelRange: 5,
swipeHThreshold: 50,
swipeVThreshold: 50,
tapholdThreshold: 750,
doubletapInterval: 500,
shakeThreshold: 15,
touchCapable: ('ontouchstart' in window),
startevent: ['touchstart'],
endevent: ['touchend'],
moveevent: ['touchmove'],
tapevent: ['tap'],
scrollevent: ['touchmove'],
}) {
/** Used internally for `taphold` */
this.startPosition = {
x: 0,
y: 0,
};
/** Used internally for `taphold` */
this.endPosition = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.originalCoord = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.finalCoord = {
x: 0,
y: 0,
};
/** Used internally for `scrollstart` and `scrollend` */
this.scrollPosition = null;
/** Used internally for `swipe` */
this.startEvnt = null;
/** Used internally for `taphold` and `singletap` */
this.tapheld = false;
/** Used internally for `doubletap` */
this.firstTap = null;
/** Used internally for `doubletap` */
this.cooling = false;
/** Used internally for `doubletap` and `singletap` */
this.doubletapped = false;
/** Used internally for `doubletap` */
this.lastTouch = 0;
/** Used internally for `swipe` */
this.hasSwiped = false;
/** Used internally for `tap` */
this.tapStarted = false;
/** Used internally for `swipe` */
this.swipeStarted = false;
/** Used internally for `tap`, `taphold` and `singletap` */
this.startTime = 0;
// TIMERS:
this.holdTimer = -1;
this.tapTimer = -1;
/** Used internally for `doubletap` */
this.actionTimer = -1;
this.scrollTimer = -1;
this.el = el;
// Set settings by device type (if device is touch capable)
settings.startevent = settings.touchCapable ? ['touchstart'] : ['mousedown'];
settings.endevent = settings.touchCapable ? ['touchend'] : ['mouseup'];
settings.moveevent = settings.touchCapable ? ['touchmove'] : ['mousemove'];
settings.tapevent = settings.touchCapable ? ['tap'] : ['click'];
settings.scrollevent = settings.touchCapable ? ['touchmove'] : ['scroll'];
this.settings = settings;
this.addEventListeners();
constructor(
el,
settings = {
tapPixelRange: 5,
swipeHThreshold: 50,
swipeVThreshold: 50,
tapholdThreshold: 750,
doubletapInterval: 500,
shakeThreshold: 15,
touchCapable: "ontouchstart" in window,
startevent: ["touchstart"],
endevent: ["touchend"],
moveevent: ["touchmove"],
tapevent: ["tap"],
scrollevent: ["touchmove"],
}
// GETTERS:
get isTouchCapable() {
return this.settings.touchCapable;
) {
/** Used internally for `taphold` */
this.startPosition = {
x: 0,
y: 0,
};
/** Used internally for `taphold` */
this.endPosition = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.originalCoord = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.finalCoord = {
x: 0,
y: 0,
};
/** Used internally for `scrollstart` and `scrollend` */
this.scrollPosition = null;
/** Used internally for `swipe` */
this.startEvnt = null;
/** Used internally for `taphold` and `singletap` */
this.tapheld = false;
/** Used internally for `doubletap` */
this.firstTap = null;
/** Used internally for `doubletap` */
this.cooling = false;
/** Used internally for `doubletap` and `singletap` */
this.doubletapped = false;
/** Used internally for `doubletap` */
this.lastTouch = 0;
/** Used internally for `swipe` */
this.hasSwiped = false;
/** Used internally for `tap` */
this.tapStarted = false;
/** Used internally for `swipe` */
this.swipeStarted = false;
/** Used internally for `tap`, `taphold` and `singletap` */
this.startTime = 0;
// TIMERS:
this.holdTimer = -1;
this.tapTimer = -1;
/** Used internally for `doubletap` */
this.actionTimer = -1;
this.scrollTimer = -1;
this.el = el;
// Set settings by device type (if device is touch capable)
settings.startevent = settings.touchCapable
? ["touchstart"]
: ["mousedown"];
settings.endevent = settings.touchCapable ? ["touchend"] : ["mouseup"];
settings.moveevent = settings.touchCapable ? ["touchmove"] : ["mousemove"];
settings.tapevent = settings.touchCapable ? ["tap"] : ["click"];
settings.scrollevent = settings.touchCapable ? ["touchmove"] : ["scroll"];
this.settings = settings;
this.addEventListeners();
}
// GETTERS:
get isTouchCapable() {
return this.settings.touchCapable;
}
get startEvent() {
return this.settings.startevent;
}
get endEvent() {
return this.settings.endevent;
}
get moveEvent() {
return this.settings.moveevent;
}
get tapEvent() {
return this.settings.tapevent;
}
get scrollEvent() {
return this.settings.scrollevent;
}
// SETTERS:
/** Set the X threshold of swipe events */
set swipeThresholdX(threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
get startEvent() {
return this.settings.startevent;
this.settings.swipeHThreshold = threshold;
}
/** Set the Y threshold of swipe events */
set swipeThresholdY(threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
get endEvent() {
return this.settings.endevent;
this.settings.swipeVThreshold = threshold;
}
/** Set the double tap interval */
set doubleTapInt(interval) {
if (typeof interval !== "number") {
throw new Error("Interval parameter must be a type of number");
}
get moveEvent() {
return this.settings.moveevent;
this.settings.doubletapInterval = interval;
}
/** Set the taphold threshold */
set tapHoldThreshold(threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
get tapEvent() {
return this.settings.tapevent;
this.settings.tapholdThreshold = threshold;
}
/** Set the pixel range for tapas */
set tapRange(range) {
if (typeof range !== "number") {
throw new Error("Ranger parameter must be a type of number");
}
get scrollEvent() {
return this.settings.scrollevent;
this.settings.tapPixelRange = range;
}
removeEventListeners() {
for (const eventName of this.settings.startevent) {
this.el.removeEventListener(eventName, this.onStartEvent.bind(this));
}
// SETTERS:
/** Set the X threshold of swipe events */
set swipeThresholdX(threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
}
this.settings.swipeHThreshold = threshold;
for (const eventName of this.settings.moveevent) {
this.el.removeEventListener(eventName, this.onMoveEvent.bind(this));
}
/** Set the Y threshold of swipe events */
set swipeThresholdY(threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
}
this.settings.swipeVThreshold = threshold;
for (const eventName of this.settings.endevent) {
this.el.removeEventListener(eventName, this.onEndEvent.bind(this));
}
/** Set the double tap interval */
set doubleTapInt(interval) {
if (typeof interval !== 'number') {
throw new Error('Interval parameter must be a type of number');
}
this.settings.doubletapInterval = interval;
for (const eventName of this.settings.scrollevent) {
this.el.removeEventListener(eventName, this.onScrollEvent.bind(this));
}
/** Set the taphold threshold */
set tapHoldThreshold(threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
}
this.settings.tapholdThreshold = threshold;
}
// HELPER METHODS:
triggerCustomEvent(eventName, originalEvent, extraParameters = {}) {
extraParameters.originalEvent = originalEvent;
extraParameters.target = originalEvent.target;
// create and dispatch the event
const event = new CustomEvent(eventName, {
detail: extraParameters,
});
this.el.dispatchEvent(event);
}
getSwipeDir(
startPosition,
endPosition,
hThreshold = this.settings.swipeHThreshold,
vThreshold = this.settings.swipeVThreshold
) {
let swipeDir = "";
if (
startPosition.y > endPosition.y &&
startPosition.y - endPosition.y > vThreshold
) {
swipeDir = "swipeup";
}
/** Set the pixel range for tapas */
set tapRange(range) {
if (typeof range !== 'number') {
throw new Error('Ranger parameter must be a type of number');
}
this.
settings.tapPixelRange = range;
if (
startPosition.x < endPosition.x &&
endPosition.x - startPosition.x > hThreshold
) {
swipeDir = "swiperight";
}
removeEventListeners() {
for (const eventName of this.settings.startevent) {
this.el.removeEventListener(eventName, this.onStartEvent.bind(this));
}
for (const eventName of this.settings.moveevent) {
this.el.removeEventListener(eventName, this.onMoveEvent.bind(this));
}
for (const eventName of this.settings.endevent) {
this.el.removeEventListener(eventName, this.onEndEvent.bind(this));
}
for (const eventName of this.settings.scrollevent) {
this.el.removeEventListener(eventName, this.onScrollEvent.bind(this));
}
if (
startPosition.y < endPosition.y &&
endPosition.y - startPosition.y > vThreshold
) {
swipeDir = "swipedown";
}
// HELPER METHODS:
triggerCustomEvent(eventName, originalEvent, extraParameters = {}) {
extraParameters.originalEvent = originalEvent;
extraParameters.target = originalEvent.target;
// create and dispatch the event
const event = new CustomEvent(eventName, {
detail: extraParameters,
});
this.el.dispatchEvent(event);
if (
startPosition.x > endPosition.x &&
startPosition.x - endPosition.x > hThreshold
) {
swipeDir = "swipeleft";
}
getSwipeDir(startPosition, endPosition, hThreshold = this.settings.swipeHThreshold, vThreshold = this.settings.swipeVThreshold) {
let swipeDir = '';
if (startPosition.y > endPosition.y && (startPosition.y - endPosition.y > vThreshold)) {
swipeDir = 'swipeup';
}
if (startPosition.x < endPosition.x && (endPosition.x - startPosition.x > hThreshold)) {
swipeDir = 'swiperight';
}
if (startPosition.y < endPosition.y && (endPosition.y - startPosition.y > vThreshold)) {
swipeDir = 'swipedown';
}
if (startPosition.x > endPosition.x && (startPosition.x - endPosition.x > hThreshold)) {
swipeDir = 'swipeleft';
}
return swipeDir;
return swipeDir;
}
getPostion(event, type = TouchType.DEFAULT, index = 0) {
let touchesTypes;
switch (type) {
case TouchType.CHANGED:
touchesTypes = event.changedTouches;
break;
case TouchType.TARGET:
touchesTypes = event.targetTouches;
break;
default:
touchesTypes = event.touches;
break;
}
getPostion(event, type = TouchType.DEFAULT, index = 0) {
let touchesTypes;
switch (type) {
case TouchType.CHANGED:
touchesTypes = event.changedTouches;
break;
case TouchType.TARGET:
touchesTypes = event.targetTouches;
break;
default:
touchesTypes = event.touches;
break;
}
const position = {
x: (this.settings.touchCapable) ? touchesTypes[index].pageX : event.pageX,
y: (this.settings.touchCapable) ? touchesTypes[index].pageY : event.pageY,
};
return position;
const position = {
x: this.settings.touchCapable ? touchesTypes[index].pageX : event.pageX,
y: this.settings.touchCapable ? touchesTypes[index].pageY : event.pageY,
};
return position;
}
getOffset(event, type = TouchType.DEFAULT, index = 0) {
const boundingClientRect = this.el.getBoundingClientRect();
let touchesTypes;
switch (type) {
case TouchType.CHANGED:
touchesTypes = event.changedTouches;
break;
case TouchType.TARGET:
touchesTypes = event.targetTouches;
break;
default:
touchesTypes = event.touches;
break;
}
getOffset(event, type = TouchType.DEFAULT, index = 0) {
const boundingClientRect = this.el.getBoundingClientRect();
let touchesTypes;
switch (type) {
case TouchType.CHANGED:
touchesTypes = event.changedTouches;
break;
case TouchType.TARGET:
touchesTypes = event.targetTouches;
break;
default:
touchesTypes = event.touches;
break;
}
const offset = {
x: (this.settings.touchCapable) ? Math.round(touchesTypes[index].pageX - (boundingClientRect ? boundingClientRect.left : 0)) : Math.round(event.pageX - (boundingClientRect ? boundingClientRect.left : 0)),
y: (this.settings.touchCapable) ? Math.round(touchesTypes[index].pageY - (boundingClientRect ? boundingClientRect.top : 0)) : Math.round(event.pageY - (boundingClientRect ? boundingClientRect.top : 0)),
};
return offset;
const offset = {
x: this.settings.touchCapable
? Math.round(
touchesTypes[index].pageX -
(boundingClientRect ? boundingClientRect.left : 0)
)
: Math.round(
event.pageX - (boundingClientRect ? boundingClientRect.left : 0)
),
y: this.settings.touchCapable
? Math.round(
touchesTypes[index].pageY -
(boundingClientRect ? boundingClientRect.top : 0)
)
: Math.round(
event.pageY - (boundingClientRect ? boundingClientRect.top : 0)
),
};
return offset;
}
getTouchData(
event,
withIndex = false,
positionType = TouchType.DEFAULT,
offsetType = TouchType.CHANGED
) {
const touchData = {
position: this.getPostion(event, positionType),
offset: this.getOffset(event, offsetType),
time: Date.now(),
};
if (withIndex) {
touchData.index = utils_service_1.Utils.getElementIndex(event.target);
}
getTouchData(event, withIndex = false, positionType = TouchType.DEFAULT, offsetType = TouchType.CHANGED) {
const touchData = {
position: this.getPostion(event, positionType),
offset: this.getOffset(event, offsetType),
time: Date.now(),
};
if (withIndex) {
touchData.index = utils_service_1.Utils.getElementIndex(event.target);
}
return touchData;
return touchData;
}
addEventListeners() {
for (const eventName of this.settings.startevent) {
this.el.addEventListener(eventName, this.onStartEvent.bind(this));
}
addEventListeners() {
for (const eventName of this.settings.startevent) {
this.el.addEventListener(eventName, this.onStartEvent.bind(this));
}
for (const eventName of this.settings.moveevent) {
this.el.addEventListener(eventName, this.onMoveEvent.bind(this));
}
for (const eventName of this.settings.endevent) {
this.el.addEventListener(eventName, this.onEndEvent.bind(this));
}
for (const eventName of this.settings.scrollevent) {
this.el.addEventListener(eventName, this.onScrollEvent.bind(this));
}
for (const eventName of this.settings.moveevent) {
this.el.addEventListener(eventName, this.onMoveEvent.bind(this));
}
// EVENT HANDLERS:
onStartEvent(event) {
if (event.which && event.which !== 1) {
return false;
}
this.startPosition = this.getPostion(event, TouchType.TARGET);
this.endPosition = {
x: this.startPosition.x,
y: this.startPosition.y,
};
this.startTime = Date.now();
// For `doubletap`
this.doubletapped = false;
if (!this.firstTap) {
this.firstTap = this.getTouchData(event, true, TouchType.DEFAULT, TouchType.CHANGED);
}
// For `tap`, `swipe`
this.tapStarted = true;
this.swipeStarted = true;
// For `swipe`
this.originalCoord = this.getPostion(event, TouchType.TARGET);
this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.startEvnt = this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED);
this.tapstart(event);
this.taphold(event);
return true;
for (const eventName of this.settings.endevent) {
this.el.addEventListener(eventName, this.onEndEvent.bind(this));
}
onEndEvent(event) {
this.endPosition = this.getPostion(event, TouchType.CHANGED);
this.tapheld = false;
window.clearTimeout(this.holdTimer);
this.tapend(event);
this.swipeend(event);
this.tap(event);
this.doubletap(event);
this.singletap(event);
this.tapStarted = false;
this.swipeStarted = false;
this.hasSwiped = false;
return true;
for (const eventName of this.settings.scrollevent) {
this.el.addEventListener(eventName, this.onScrollEvent.bind(this));
}
onMoveEvent(event) {
this.endPosition = this.getPostion(event, TouchType.TARGET);
this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.tapmove(event);
this.swipe(event);
return true;
}
// EVENT HANDLERS:
onStartEvent(event) {
if (event.which && event.which !== 1) {
return false;
}
onScrollEvent(event) {
this.scrollstart(event);
return true;
this.startPosition = this.getPostion(event, TouchType.TARGET);
this.endPosition = {
x: this.startPosition.x,
y: this.startPosition.y,
};
this.startTime = Date.now();
// For `doubletap`
this.doubletapped = false;
if (!this.firstTap) {
this.firstTap = this.getTouchData(
event,
true,
TouchType.DEFAULT,
TouchType.CHANGED
);
}
// CUSTOM EVENT METHODS:
/** tapstart Event */
tapstart(event) {
this.triggerCustomEvent('tapstart', event, this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED));
return true;
// For `tap`, `swipe`
this.tapStarted = true;
this.swipeStarted = true;
// For `swipe`
this.originalCoord = this.getPostion(event, TouchType.TARGET);
this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.startEvnt = this.getTouchData(
event,
false,
TouchType.DEFAULT,
TouchType.CHANGED
);
this.tapstart(event);
this.taphold(event);
return true;
}
onEndEvent(event) {
this.endPosition = this.getPostion(event, TouchType.CHANGED);
this.tapheld = false;
window.clearTimeout(this.holdTimer);
this.tapend(event);
this.swipeend(event);
this.tap(event);
this.doubletap(event);
this.singletap(event);
this.tapStarted = false;
this.swipeStarted = false;
this.hasSwiped = false;
return true;
}
onMoveEvent(event) {
this.endPosition = this.getPostion(event, TouchType.TARGET);
this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.tapmove(event);
this.swipe(event);
return true;
}
onScrollEvent(event) {
this.scrollstart(event);
return true;
}
// CUSTOM EVENT METHODS:
/** tapstart Event */
tapstart(event) {
this.triggerCustomEvent(
"tapstart",
event,
this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED)
);
return true;
}
/** tapmove Event */
tapmove(event) {
this.triggerCustomEvent(
"tapmove",
event,
this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED)
);
return true;
}
/** tapend Event */
tapend(event) {
this.triggerCustomEvent(
"tapend",
event,
this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED)
);
return true;
}
/** taphold Event */
taphold(event) {
this.holdTimer = window.setTimeout(() => {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
// helded?
if (
(this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange)
) {
this.tapheld = true;
const endTime = Date.now();
const duration = endTime - this.startTime;
const touchesLength = event.targetTouches
? event.targetTouches.length
: 1;
const touches = [];
for (let i = 0; i < touchesLength; i++) {
const elOffset = this.el.getBoundingClientRect();
const touch = {
position: {
x: this.settings.touchCapable
? event.changedTouches[i].pageX
: event.pageX,
y: this.settings.touchCapable
? event.changedTouches[i].pageY
: event.pageY,
},
offset: {
x: this.settings.touchCapable
? Math.round(
event.changedTouches[i].pageX -
(elOffset ? elOffset.left : 0)
)
: Math.round(event.pageX - (elOffset ? elOffset.left : 0)),
y: this.settings.touchCapable
? Math.round(
event.changedTouches[i].pageY -
(elOffset ? elOffset.top : 0)
)
: Math.round(event.pageY - (elOffset ? elOffset.top : 0)),
},
};
touches.push(touch);
}
const eventName =
touchesLength > 1 ? "taphold" + touchesLength : "taphold";
const touchData = {
touches,
time: Date.now(),
duration,
};
this.triggerCustomEvent(eventName, event, touchData);
}
}, this.settings.tapholdThreshold);
return true;
}
/** doubletap Event */
doubletap(event) {
const now = Date.now();
const lastTouch = Number(this.lastTouch) || now + 1;
const delta = now - lastTouch;
if (this.actionTimer !== -1) {
window.clearTimeout(this.actionTimer);
}
/** tapmove Event */
tapmove(event) {
this.triggerCustomEvent('tapmove', event, this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED));
return true;
if (
delta < this.settings.doubletapInterval &&
delta > 100 &&
this.firstTap &&
utils_service_1.Utils.getElementIndex(event.target) ===
this.firstTap.index
) {
this.doubletapped = true;
window.clearTimeout(this.tapTimer);
const lastTap = this.getTouchData(
event,
true,
TouchType.CHANGED,
TouchType.CHANGED
);
const touchData = {
firstTap: this.firstTap,
secondTap: lastTap,
interval: lastTap.time - this.firstTap.time,
};
if (!this.cooling) {
this.triggerCustomEvent("doubletap", event, touchData);
this.firstTap = null;
}
this.cooling = true;
window.setTimeout(() => {
this.cooling = false;
}, this.settings.doubletapInterval);
} else {
this.actionTimer = window.setTimeout(
() => {
this.firstTap = null;
window.clearTimeout(this.actionTimer);
},
this.settings.doubletapInterval,
[event]
);
}
/** tapend Event */
tapend(event) {
this.triggerCustomEvent('tapend', event, this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED));
return true;
}
/** taphold Event */
taphold(event) {
this.holdTimer = window.setTimeout(() => {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
// helded?
if ((this.startPosition.x === this.endPosition.x
&&
this.startPosition.y === this.endPosition.y)
||
(diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange)) {
this.tapheld = true;
const endTime = Date.now();
const duration = endTime - this.startTime;
const touchesLength = (event.targetTouches) ? event.targetTouches.length : 1;
const touches = new Array();
for (let i = 0; i < touchesLength; i++) {
const elOffset = this.el.getBoundingClientRect();
const touch = {
position: {
x: (this.settings.touchCapable) ? event.changedTouches[i].pageX : event.pageX,
y: (this.settings.touchCapable) ? event.changedTouches[i].pageY : event.pageY,
},
offset: {
x: (this.settings.touchCapable) ? Math.round(event.changedTouches[i].pageX - (elOffset ? elOffset.left : 0)) : Math.round(event.pageX - (elOffset ? elOffset.left : 0)),
y: (this.settings.touchCapable) ? Math.round(event.changedTouches[i].pageY - (elOffset ? elOffset.top : 0)) : Math.round(event.pageY - (elOffset ? elOffset.top : 0)),
},
};
touches.push(touch);
}
const eventName = (touchesLength > 1) ? 'taphold' + touchesLength : 'taphold';
const touchData = {
touches,
time: Date.now(),
duration,
};
this.triggerCustomEvent(eventName, event, touchData);
}
}, this.settings.tapholdThreshold);
return true;
}
/** doubletap Event */
doubletap(event) {
const now = Date.now();
const lastTouch = Number(this.lastTouch) || now + 1;
const delta = now - lastTouch;
if (this.actionTimer !== -1) {
window.clearTimeout(this.actionTimer);
this.lastTouch = now;
}
/**
* singletap Event
* This is used in conjuction with doubletap when both events are needed on the same element
*/
singletap(event) {
this.tapTimer = window.setTimeout(() => {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
if (
!this.doubletapped &&
!this.tapheld &&
((this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange))
) {
const touchData = this.getTouchData(
event,
false,
TouchType.CHANGED,
TouchType.CHANGED
);
// Was it a taphold?
if (touchData.time - this.startTime < this.settings.tapholdThreshold) {
this.triggerCustomEvent("singletap", event, touchData);
}
if (delta < this.settings.doubletapInterval
&&
delta > 100
&&
(this.firstTap
&&
utils_service_1.Utils.getElementIndex(event.target) === this.firstTap.index)) {
this.doubletapped = true;
window.clearTimeout(this.tapTimer);
const lastTap = this.getTouchData(event, true, TouchType.CHANGED, TouchType.CHANGED);
const touchData = {
firstTap: this.firstTap,
secondTap: lastTap,
interval: lastTap.time - this.firstTap.time,
};
if (!this.cooling) {
this.triggerCustomEvent('doubletap', event, touchData);
this.firstTap = null;
}
this.cooling = true;
window.setTimeout(() => {
this.cooling = false;
}, this.settings.doubletapInterval);
}
else {
this.actionTimer = window.setTimeout(() => {
this.firstTap = null;
window.clearTimeout(this.actionTimer);
}, this.settings.doubletapInterval, [event]);
}
this.lastTouch = now;
}
}, this.settings.doubletapInterval);
}
/** tap Event */
tap(event) {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
if (
this.tapStarted &&
Date.now() - this.startTime < this.settings.tapholdThreshold &&
((this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange))
) {
const touchesLength = event.targetTouches
? event.targetTouches.length
: 1;
const touches = [];
for (let i = 0; i < touchesLength; i++) {
const elOffset = this.el.getBoundingClientRect();
const touch = {
position: {
x: this.settings.touchCapable
? event.changedTouches[i].pageX
: event.pageX,
y: this.settings.touchCapable
? event.changedTouches[i].pageY
: event.pageY,
},
offset: {
x: this.settings.touchCapable
? Math.round(
event.changedTouches[i].pageX - (elOffset ? elOffset.left : 0)
)
: Math.round(event.pageX - (elOffset ? elOffset.left : 0)),
y: this.settings.touchCapable
? Math.round(
event.changedTouches[i].pageY - (elOffset ? elOffset.top : 0)
)
: Math.round(event.pageY - (elOffset ? elOffset.top : 0)),
},
};
touches.push(touch);
}
const touchData = {
touches,
time: Date.now(),
};
const eventName = touchesLength > 1 ? "tap" + touchesLength : "tap";
this.triggerCustomEvent(eventName, event, touchData);
}
/**
* singletap Event
* This is used in conjuction with doubletap when both events are needed on the same element
*/
singletap(event) {
this.tapTimer = window.setTimeout(() => {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
if (!this.doubletapped
&&
!this.tapheld
&&
(((this.startPosition.x === this.endPosition.x)
&&
(this.startPosition.y === this.endPosition.y))
||
(diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange))) {
const touchData = this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED);
// Was it a taphold?
if ((touchData.time - this.startTime) < this.settings.tapholdThreshold) {
this.triggerCustomEvent('singletap', event, touchData);
}
}
}, this.settings.doubletapInterval);
}
/**
* swipe Event
* (also handles swipeup, swiperight, swipedown and swipeleft)
*
* (similar to `touchMove` method in jquery touch events)
*/
swipe(event) {
const swipeDir = this.getSwipeDir(this.originalCoord, this.finalCoord);
if (swipeDir && this.swipeStarted && this.startEvnt) {
this.originalCoord.x = 0;
this.originalCoord.y = 0;
this.finalCoord.x = 0;
this.finalCoord.y = 0;
this.swipeStarted = false;
const endEvnt = this.getTouchData(
event,
false,
TouchType.DEFAULT,
TouchType.CHANGED
);
// Calculate the swipe amount (normalized):
const xAmount = Math.abs(this.startEvnt.position.x - endEvnt.position.x);
const yAmount = Math.abs(this.startEvnt.position.y - endEvnt.position.y);
const touchData = {
startEvnt: this.startEvnt,
endEvnt,
direction: swipeDir.replace("swipe", ""),
xAmount,
yAmount,
duration: endEvnt.time - this.startEvnt.time,
};
this.hasSwiped = true;
this.triggerCustomEvent("swipe", event, touchData);
this.triggerCustomEvent(swipeDir, event, touchData);
}
/** tap Event */
tap(event) {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
if (this.tapStarted
&&
((Date.now() - this.startTime) < this.settings.tapholdThreshold)
&&
((this.startPosition.x === this.endPosition.x
&&
this.startPosition.y === this.endPosition.y)
||
(diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange))) {
const touchesLength = (event.targetTouches) ? event.targetTouches.length : 1;
const touches = new Array();
for (let i = 0; i < touchesLength; i++) {
const elOffset = this.el.getBoundingClientRect();
const touch = {
position: {
x: (this.settings.touchCapable) ? event.changedTouches[i].pageX : event.pageX,
y: (this.settings.touchCapable) ? event.changedTouches[i].pageY : event.pageY,
},
offset: {
x: (this.settings.touchCapable) ? Math.round(event.changedTouches[i].pageX - (elOffset ? elOffset.left : 0)) : Math.round(event.pageX - (elOffset ? elOffset.left : 0)),
y: (this.settings.touchCapable) ? Math.round(event.changedTouches[i].pageY - (elOffset ? elOffset.top : 0)) : Math.round(event.pageY - (elOffset ? elOffset.top : 0)),
},
};
touches.push(touch);
}
const touchData = {
touches,
time: Date.now(),
};
const eventName = (touchesLength > 1) ? 'tap' + touchesLength : 'tap';
this.triggerCustomEvent(eventName, event, touchData);
}
}
/**
* swipeend Event
* (similar `touchEnd` method in jquery touch events)
*/
swipeend(event) {
const endEvnt = this.getTouchData(
event,
false,
TouchType.CHANGED,
TouchType.CHANGED
);
if (this.hasSwiped && this.startEvnt) {
const swipeDir = this.getSwipeDir(
this.startEvnt.position,
endEvnt.position
);
// Calculate the swipe amount (normalized):
const xAmount = Math.abs(this.startEvnt.position.x - endEvnt.position.x);
const yAmount = Math.abs(this.startEvnt.position.y - endEvnt.position.y);
const touchData = {
startEvnt: this.startEvnt,
endEvnt,
direction: swipeDir.replace("swipe", ""),
xAmount,
yAmount,
duration: endEvnt.time - this.startEvnt.time,
};
this.triggerCustomEvent("swipeend", event, touchData);
}
/**
* swipe Event
* (also handles swipeup, swiperight, swipedown and swipeleft)
*
* (similar to `touchMove` method in jquery touch events)
*/
swipe(event) {
const swipeDir = this.getSwipeDir(this.originalCoord, this.finalCoord);
if (swipeDir && this.swipeStarted && this.startEvnt) {
this.originalCoord.x = 0;
this.originalCoord.y = 0;
this.finalCoord.x = 0;
this.finalCoord.y = 0;
this.swipeStarted = false;
const endEvnt = this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED);
// Calculate the swipe amount (normalized):
const xAmount = Math.abs(this.startEvnt.position.x - endEvnt.position.x);
const yAmount = Math.abs(this.startEvnt.position.y - endEvnt.position.y);
const touchData = {
startEvnt: this.startEvnt,
endEvnt,
direction: swipeDir.replace('swipe', ''),
xAmount,
yAmount,
duration: endEvnt.time - this.startEvnt.time,
};
this.hasSwiped = true;
this.triggerCustomEvent('swipe', event, touchData);
this.triggerCustomEvent(swipeDir, event, touchData);
}
}
/**
* scrollstart Event
* (also handles `scrollend`)
*/
scrollstart(event) {
if (!event.target) {
return false;
}
/**
* swipeend Event
* (similar `touchEnd` method in jquery touch events)
*/
swipeend(event) {
const endEvnt = this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED);
if (this.hasSwiped && this.startEvnt) {
const swipeDir = this.getSwipeDir(this.startEvnt.position, endEvnt.position);
// Calculate the swipe amount (normalized):
const xAmount = Math.abs(this.startEvnt.position.x - endEvnt.position.x);
const yAmount = Math.abs(this.startEvnt.position.y - endEvnt.position.y);
const touchData = {
startEvnt: this.startEvnt,
endEvnt,
direction: swipeDir.replace('swipe', ''),
xAmount,
yAmount,
duration: endEvnt.time - this.startEvnt.time,
};
this.triggerCustomEvent('swipeend', event, touchData);
}
if (this.scrollPosition === null) {
this.scrollPosition = utils_service_1.Utils.getScrollPosition(
event.target
);
this.triggerCustomEvent("scrollstart", event, this.scrollPosition);
}
/**
* scrollstart Event
* (also handles `scrollend`)
*/
scrollstart(event) {
if (!event.target) {
return false;
}
if (this.scrollPosition === null) {
this.scrollPosition = utils_service_1.Utils.getScrollPosition(event.target);
this.triggerCustomEvent('scrollstart', event, this.scrollPosition);
}
if (this.scrollTimer !== -1) {
window.clearTimeout(this.scrollTimer);
}
this.scrollTimer = window.setTimeout(() => {
core_1.Utils.debounce(this.triggerCustomEvent.bind(this, 'scrollend', event, event.target ? utils_service_1.Utils.getScrollPosition(event.target) : {}));
this.scrollPosition = null;
}, 50);
if (this.scrollTimer !== -1) {
window.clearTimeout(this.scrollTimer);
}
this.scrollTimer = window.setTimeout(() => {
core_1.Utils.debounce(
this.triggerCustomEvent.bind(
this,
"scrollend",
event,
event.target
? utils_service_1.Utils.getScrollPosition(event.target)
: {}
)
);
this.scrollPosition = null;
}, 50);
}
}
exports.TouchEventService = TouchEventService;
export declare abstract class BaseTouchEventService {
protected touchCapable: boolean;
/** The element to trigger the events on */
protected el: HTMLElement;
get isTouchCapable(): boolean;
constructor(el: HTMLElement);
protected triggerCustomEvent(eventName: string, originalEvent: Event, extraParameters?: any): void;
protected touchCapable: boolean;
/** The element to trigger the events on */
protected el: HTMLElement;
get isTouchCapable(): boolean;
constructor(el: HTMLElement);
protected triggerCustomEvent(
eventName: string,
originalEvent: Event,
extraParameters?: any
): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class BaseTouchEventService {
constructor(el) {
this.el = el;
this.touchCapable = ('ontouchstart' in window);
}
get isTouchCapable() {
return this.touchCapable;
}
triggerCustomEvent(eventName, originalEvent, extraParameters = {}) {
extraParameters.originalEvent = originalEvent;
extraParameters.target = originalEvent.target;
// create and dispatch the event
const event = new CustomEvent(eventName, {
detail: extraParameters,
});
this.el.dispatchEvent(event);
}
constructor(el) {
this.el = el;
this.touchCapable = "ontouchstart" in window;
}
get isTouchCapable() {
return this.touchCapable;
}
triggerCustomEvent(eventName, originalEvent, extraParameters = {}) {
extraParameters.originalEvent = originalEvent;
extraParameters.target = originalEvent.target;
// create and dispatch the event
const event = new CustomEvent(eventName, {
detail: extraParameters,
});
this.el.dispatchEvent(event);
}
}
exports.BaseTouchEventService = BaseTouchEventService;

@@ -1,18 +0,18 @@

import { BaseTouchEventService } from './base-touch-events.service';
import { BaseTouchEventService } from "./base-touch-events.service";
export declare class ScrollEventsService extends BaseTouchEventService {
isScrolling: boolean;
protected _scrollEvent: Array<'touchmove' | 'scroll'>;
/** The element to trigger the events on */
protected el: HTMLElement;
protected scrollTimer: number | null;
constructor(el: HTMLElement);
removeEventListeners(): void;
get scrollEvent(): ("scroll" | "touchmove")[];
protected addEventListeners(): void;
protected onScrollEvent(event: TouchEvent | MouseEvent): boolean;
/**
* scrollstart Event
* (also handles `scrollEnd`)
*/
protected scrollstart(event: TouchEvent | MouseEvent): false | undefined;
isScrolling: boolean;
protected _scrollEvent: Array<"touchmove" | "scroll">;
/** The element to trigger the events on */
protected el: HTMLElement;
protected scrollTimer: number | null;
constructor(el: HTMLElement);
removeEventListeners(): void;
get scrollEvent(): ("scroll" | "touchmove")[];
protected addEventListeners(): void;
protected onScrollEvent(event: TouchEvent | MouseEvent): boolean;
/**
* scrollstart Event
* (also handles `scrollEnd`)
*/
protected scrollstart(event: TouchEvent | MouseEvent): false | undefined;
}

@@ -5,50 +5,50 @@ "use strict";

class ScrollEventsService extends base_touch_events_service_1.BaseTouchEventService {
constructor(el) {
super(el);
this.isScrolling = false;
this.scrollTimer = null;
this.el = el;
this._scrollEvent = this.touchCapable ? ['touchmove'] : ['scroll'];
this.addEventListeners();
constructor(el) {
super(el);
this.isScrolling = false;
this.scrollTimer = null;
this.el = el;
this._scrollEvent = this.touchCapable ? ["touchmove"] : ["scroll"];
this.addEventListeners();
}
removeEventListeners() {
for (const eventName of this._scrollEvent) {
this.el.removeEventListener(eventName, this.onScrollEvent.bind(this));
}
removeEventListeners() {
for (const eventName of this._scrollEvent) {
this.el.removeEventListener(eventName, this.onScrollEvent.bind(this));
}
}
get scrollEvent() {
return this._scrollEvent;
}
addEventListeners() {
for (const eventName of this._scrollEvent) {
this.el.addEventListener(eventName, this.onScrollEvent.bind(this), false);
}
get scrollEvent() {
return this._scrollEvent;
}
onScrollEvent(event) {
this.scrollstart(event);
return true;
}
/**
* scrollstart Event
* (also handles `scrollEnd`)
*/
scrollstart(event) {
if (!event.target) {
return false;
}
addEventListeners() {
for (const eventName of this._scrollEvent) {
this.el.addEventListener(eventName, this.onScrollEvent.bind(this), false);
}
if (!this.isScrolling) {
this.isScrolling = true;
this.triggerCustomEvent("scrollStart", event, {});
}
onScrollEvent(event) {
this.scrollstart(event);
return true;
// console.debug('scroll timer is ', this.scrollTimer);
if (this.scrollTimer !== null) {
clearTimeout(this.scrollTimer);
this.scrollTimer = null;
}
/**
* scrollstart Event
* (also handles `scrollEnd`)
*/
scrollstart(event) {
if (!event.target) {
return false;
}
if (!this.isScrolling) {
this.isScrolling = true;
this.triggerCustomEvent('scrollStart', event, {});
}
// console.debug('scroll timer is ', this.scrollTimer);
if (this.scrollTimer !== null) {
clearTimeout(this.scrollTimer);
this.scrollTimer = null;
}
this.scrollTimer = window.setTimeout(() => {
this.triggerCustomEvent('scrollEnd', event, {});
this.isScrolling = false;
}, 100);
}
this.scrollTimer = window.setTimeout(() => {
this.triggerCustomEvent("scrollEnd", event, {});
this.isScrolling = false;
}, 100);
}
}
exports.ScrollEventsService = ScrollEventsService;

@@ -1,4 +0,4 @@

import { Position } from '../../types';
import { ScrollEventsService } from './scroll-events.service';
import { BaseTouchEventService } from './base-touch-events.service';
import { Position } from "../../types";
import { ScrollEventsService } from "./scroll-events.service";
import { BaseTouchEventService } from "./base-touch-events.service";
/**

@@ -31,121 +31,139 @@ * Vanilla version of jQuery Mobile Events

export interface Settings {
tapPixelRange: number;
swipeHThreshold: number;
swipeVThreshold: number;
tapholdThreshold: number;
doubletapInterval: number;
shakeThreshold: number;
touchCapable: boolean;
startevent: Array<'touchstart' | 'mousedown'>;
endevent: Array<'touchend' | 'touchcancel' | 'mouseup'>;
moveevent: Array<'touchmove' | 'mousemove'>;
tapevent: Array<'tap' | 'click'>;
tapPixelRange: number;
swipeHThreshold: number;
swipeVThreshold: number;
tapholdThreshold: number;
doubletapInterval: number;
shakeThreshold: number;
touchCapable: boolean;
startevent: Array<"touchstart" | "mousedown">;
endevent: Array<"touchend" | "touchcancel" | "mouseup">;
moveevent: Array<"touchmove" | "mousemove">;
tapevent: Array<"tap" | "click">;
}
export interface Offset {
x: number;
y: number;
x: number;
y: number;
}
export interface TouchData {
position: Position;
offset: Offset;
time: number;
index?: number;
position: Position;
offset: Offset;
time: number;
index?: number;
}
export declare enum TouchType {
DEFAULT = 0,
TARGET = 1,
CHANGED = 2
DEFAULT = 0,
TARGET = 1,
CHANGED = 2,
}
export declare class TouchEventService extends BaseTouchEventService {
get isTouchCapable(): boolean;
get startEvent(): ("mousedown" | "touchstart")[];
get endEvent(): ("mouseup" | "touchcancel" | "touchend")[];
get moveEvent(): ("mousemove" | "touchmove")[];
get tapEvent(): ("click" | "tap")[];
get scrollEvent(): ("scroll" | "touchmove")[];
/** Set the X threshold of swipe events */
set swipeThresholdX(threshold: number);
/** Set the Y threshold of swipe events */
set swipeThresholdY(threshold: number);
/** Set the double tap interval */
set doubleTapInt(interval: number);
/** Set the taphold threshold */
set tapHoldThreshold(threshold: number);
/** Set the pixel range for tapas */
set tapRange(range: number);
/** The element to trigger the events on */
protected el: HTMLElement;
/** Used internally for `taphold` */
protected startPosition: Position;
/** Used internally for `taphold` */
protected endPosition: Position;
/** Used internally for `swipe` */
protected originalCoord: Position;
/** Used internally for `swipe` */
protected finalCoord: Position;
/** Used internally for `swipe` */
protected startEvnt: TouchData | null;
/** Used internally for `taphold` and `singletap` */
protected tapheld: boolean;
/** Used internally for `doubletap` */
protected firstTap: TouchData | null;
/** Used internally for `doubletap` */
protected cooling: boolean;
/** Used internally for `doubletap` and `singletap` */
protected doubletapped: boolean;
/** Used internally for `doubletap` */
protected lastTouch: number;
/** Used internally for `swipe` */
protected hasSwiped: boolean;
/** Used internally for `tap` */
protected tapStarted: boolean;
/** Used internally for `swipe` */
protected swipeStarted: boolean;
/** Used internally for `tap`, `taphold` and `singletap` */
protected startTime: number;
protected holdTimer: number;
protected tapTimer: number;
/** Used internally for `doubletap` */
protected actionTimer: number;
protected settings: Settings;
protected scrollEvents: ScrollEventsService;
constructor(el: HTMLElement, settings?: Settings);
removeEventListeners(): void;
protected getSwipeDir(startPosition: Position, endPosition: Position, hThreshold?: number, vThreshold?: number): string;
protected getPostion(event: TouchEvent | MouseEvent, type?: TouchType, index?: number): Position;
protected getOffset(event: TouchEvent | MouseEvent, type?: TouchType, index?: number): Offset;
protected getTouchData(event: TouchEvent | MouseEvent, withIndex?: boolean, positionType?: TouchType, offsetType?: TouchType): TouchData;
protected addEventListeners(): void;
protected onStartEvent(event: TouchEvent | MouseEvent): boolean;
protected onEndEvent(event: TouchEvent | MouseEvent): boolean;
protected onMoveEvent(event: TouchEvent | MouseEvent): boolean;
/** tapstart Event */
protected tapstart(event: TouchEvent | MouseEvent): boolean;
/** tapmove Event */
protected tapmove(event: TouchEvent | MouseEvent): boolean;
/** tapend Event */
protected tapend(event: TouchEvent | MouseEvent): boolean;
/** taphold Event */
protected taphold(event: TouchEvent | MouseEvent): boolean;
/** doubletap Event */
protected doubletap(event: TouchEvent | MouseEvent): void;
/**
* singletap Event
* This is used in conjuction with doubletap when both events are needed on the same element
*/
protected singletap(event: TouchEvent | MouseEvent): void;
/** tap Event */
protected tap(event: TouchEvent | MouseEvent): void;
/**
* swipe Event
* (also handles swipeup, swiperight, swipedown and swipeleft)
*
* (similar to `touchMove` method in jquery touch events)
*/
protected swipe(event: TouchEvent | MouseEvent): void;
/**
* swipeend Event
* (similar `touchEnd` method in jquery touch events)
*/
protected swipeend(event: TouchEvent | MouseEvent): void;
get isTouchCapable(): boolean;
get startEvent(): ("mousedown" | "touchstart")[];
get endEvent(): ("mouseup" | "touchcancel" | "touchend")[];
get moveEvent(): ("mousemove" | "touchmove")[];
get tapEvent(): ("click" | "tap")[];
get scrollEvent(): ("scroll" | "touchmove")[];
/** Set the X threshold of swipe events */
set swipeThresholdX(threshold: number);
/** Set the Y threshold of swipe events */
set swipeThresholdY(threshold: number);
/** Set the double tap interval */
set doubleTapInt(interval: number);
/** Set the taphold threshold */
set tapHoldThreshold(threshold: number);
/** Set the pixel range for tapas */
set tapRange(range: number);
/** The element to trigger the events on */
protected el: HTMLElement;
/** Used internally for `taphold` */
protected startPosition: Position;
/** Used internally for `taphold` */
protected endPosition: Position;
/** Used internally for `swipe` */
protected originalCoord: Position;
/** Used internally for `swipe` */
protected finalCoord: Position;
/** Used internally for `swipe` */
protected startEvnt: TouchData | null;
/** Used internally for `taphold` and `singletap` */
protected tapheld: boolean;
/** Used internally for `doubletap` */
protected firstTap: TouchData | null;
/** Used internally for `doubletap` */
protected cooling: boolean;
/** Used internally for `doubletap` and `singletap` */
protected doubletapped: boolean;
/** Used internally for `doubletap` */
protected lastTouch: number;
/** Used internally for `swipe` */
protected hasSwiped: boolean;
/** Used internally for `tap` */
protected tapStarted: boolean;
/** Used internally for `swipe` */
protected swipeStarted: boolean;
/** Used internally for `tap`, `taphold` and `singletap` */
protected startTime: number;
protected holdTimer: number;
protected tapTimer: number;
/** Used internally for `doubletap` */
protected actionTimer: number;
protected settings: Settings;
protected scrollEvents: ScrollEventsService;
constructor(el: HTMLElement, settings?: Settings);
removeEventListeners(): void;
protected getSwipeDir(
startPosition: Position,
endPosition: Position,
hThreshold?: number,
vThreshold?: number
): string;
protected getPostion(
event: TouchEvent | MouseEvent,
type?: TouchType,
index?: number
): Position;
protected getOffset(
event: TouchEvent | MouseEvent,
type?: TouchType,
index?: number
): Offset;
protected getTouchData(
event: TouchEvent | MouseEvent,
withIndex?: boolean,
positionType?: TouchType,
offsetType?: TouchType
): TouchData;
protected addEventListeners(): void;
protected onStartEvent(event: TouchEvent | MouseEvent): boolean;
protected onEndEvent(event: TouchEvent | MouseEvent): boolean;
protected onMoveEvent(event: TouchEvent | MouseEvent): boolean;
/** tapstart Event */
protected tapstart(event: TouchEvent | MouseEvent): boolean;
/** tapmove Event */
protected tapmove(event: TouchEvent | MouseEvent): boolean;
/** tapend Event */
protected tapend(event: TouchEvent | MouseEvent): boolean;
/** taphold Event */
protected taphold(event: TouchEvent | MouseEvent): boolean;
/** doubletap Event */
protected doubletap(event: TouchEvent | MouseEvent): void;
/**
* singletap Event
* This is used in conjuction with doubletap when both events are needed on the same element
*/
protected singletap(event: TouchEvent | MouseEvent): void;
/** tap Event */
protected tap(event: TouchEvent | MouseEvent): void;
/**
* swipe Event
* (also handles swipeup, swiperight, swipedown and swipeleft)
*
* (similar to `touchMove` method in jquery touch events)
*/
protected swipe(event: TouchEvent | MouseEvent): void;
/**
* swipeend Event
* (similar `touchEnd` method in jquery touch events)
*/
protected swipeend(event: TouchEvent | MouseEvent): void;
}

@@ -8,507 +8,615 @@ "use strict";

(function (TouchType) {
TouchType[TouchType["DEFAULT"] = 0] = "DEFAULT";
TouchType[TouchType["TARGET"] = 1] = "TARGET";
TouchType[TouchType["CHANGED"] = 2] = "CHANGED";
})(TouchType = exports.TouchType || (exports.TouchType = {}));
TouchType[(TouchType["DEFAULT"] = 0)] = "DEFAULT";
TouchType[(TouchType["TARGET"] = 1)] = "TARGET";
TouchType[(TouchType["CHANGED"] = 2)] = "CHANGED";
})((TouchType = exports.TouchType || (exports.TouchType = {})));
class TouchEventService extends base_touch_events_service_1.BaseTouchEventService {
constructor(el, settings = {
tapPixelRange: 5,
swipeHThreshold: 50,
swipeVThreshold: 50,
tapholdThreshold: 750,
doubletapInterval: 500,
shakeThreshold: 15,
touchCapable: ('ontouchstart' in window),
startevent: ['touchstart'],
endevent: ['touchend'],
moveevent: ['touchmove'],
tapevent: ['tap'],
}) {
super(el);
/** Used internally for `taphold` */
this.startPosition = {
x: 0,
y: 0,
};
/** Used internally for `taphold` */
this.endPosition = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.originalCoord = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.finalCoord = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.startEvnt = null;
/** Used internally for `taphold` and `singletap` */
this.tapheld = false;
/** Used internally for `doubletap` */
this.firstTap = null;
/** Used internally for `doubletap` */
this.cooling = false;
/** Used internally for `doubletap` and `singletap` */
this.doubletapped = false;
/** Used internally for `doubletap` */
this.lastTouch = 0;
/** Used internally for `swipe` */
this.hasSwiped = false;
/** Used internally for `tap` */
this.tapStarted = false;
/** Used internally for `swipe` */
this.swipeStarted = false;
/** Used internally for `tap`, `taphold` and `singletap` */
this.startTime = 0;
// TIMERS:
this.holdTimer = -1;
this.tapTimer = -1;
/** Used internally for `doubletap` */
this.actionTimer = -1;
this.el = el;
// Set settings by device type (if device is touch capable)
settings.startevent = settings.touchCapable ? ['touchstart'] : ['mousedown'];
settings.endevent = settings.touchCapable ? ['touchend'] : ['mouseup'];
settings.moveevent = settings.touchCapable ? ['touchmove'] : ['mousemove'];
settings.tapevent = settings.touchCapable ? ['tap'] : ['click'];
this.settings = settings;
this.scrollEvents = new scroll_events_service_1.ScrollEventsService(this.el);
this.addEventListeners();
constructor(
el,
settings = {
tapPixelRange: 5,
swipeHThreshold: 50,
swipeVThreshold: 50,
tapholdThreshold: 750,
doubletapInterval: 500,
shakeThreshold: 15,
touchCapable: "ontouchstart" in window,
startevent: ["touchstart"],
endevent: ["touchend"],
moveevent: ["touchmove"],
tapevent: ["tap"],
}
// GETTERS:
get isTouchCapable() {
return this.settings.touchCapable;
) {
super(el);
/** Used internally for `taphold` */
this.startPosition = {
x: 0,
y: 0,
};
/** Used internally for `taphold` */
this.endPosition = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.originalCoord = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.finalCoord = {
x: 0,
y: 0,
};
/** Used internally for `swipe` */
this.startEvnt = null;
/** Used internally for `taphold` and `singletap` */
this.tapheld = false;
/** Used internally for `doubletap` */
this.firstTap = null;
/** Used internally for `doubletap` */
this.cooling = false;
/** Used internally for `doubletap` and `singletap` */
this.doubletapped = false;
/** Used internally for `doubletap` */
this.lastTouch = 0;
/** Used internally for `swipe` */
this.hasSwiped = false;
/** Used internally for `tap` */
this.tapStarted = false;
/** Used internally for `swipe` */
this.swipeStarted = false;
/** Used internally for `tap`, `taphold` and `singletap` */
this.startTime = 0;
// TIMERS:
this.holdTimer = -1;
this.tapTimer = -1;
/** Used internally for `doubletap` */
this.actionTimer = -1;
this.el = el;
// Set settings by device type (if device is touch capable)
settings.startevent = settings.touchCapable
? ["touchstart"]
: ["mousedown"];
settings.endevent = settings.touchCapable ? ["touchend"] : ["mouseup"];
settings.moveevent = settings.touchCapable ? ["touchmove"] : ["mousemove"];
settings.tapevent = settings.touchCapable ? ["tap"] : ["click"];
this.settings = settings;
this.scrollEvents = new scroll_events_service_1.ScrollEventsService(
this.el
);
this.addEventListeners();
}
// GETTERS:
get isTouchCapable() {
return this.settings.touchCapable;
}
get startEvent() {
return this.settings.startevent;
}
get endEvent() {
return this.settings.endevent;
}
get moveEvent() {
return this.settings.moveevent;
}
get tapEvent() {
return this.settings.tapevent;
}
get scrollEvent() {
return this.scrollEvents.scrollEvent;
}
// SETTERS:
/** Set the X threshold of swipe events */
set swipeThresholdX(threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
get startEvent() {
return this.settings.startevent;
this.settings.swipeHThreshold = threshold;
}
/** Set the Y threshold of swipe events */
set swipeThresholdY(threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
get endEvent() {
return this.settings.endevent;
this.settings.swipeVThreshold = threshold;
}
/** Set the double tap interval */
set doubleTapInt(interval) {
if (typeof interval !== "number") {
throw new Error("Interval parameter must be a type of number");
}
get moveEvent() {
return this.settings.moveevent;
this.settings.doubletapInterval = interval;
}
/** Set the taphold threshold */
set tapHoldThreshold(threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
get tapEvent() {
return this.settings.tapevent;
this.settings.tapholdThreshold = threshold;
}
/** Set the pixel range for tapas */
set tapRange(range) {
if (typeof range !== "number") {
throw new Error("Ranger parameter must be a type of number");
}
get scrollEvent() {
return this.scrollEvents.scrollEvent;
this.settings.tapPixelRange = range;
}
removeEventListeners() {
for (const eventName of this.settings.startevent) {
this.el.removeEventListener(eventName, this.onStartEvent.bind(this));
}
// SETTERS:
/** Set the X threshold of swipe events */
set swipeThresholdX(threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
}
this.settings.swipeHThreshold = threshold;
for (const eventName of this.settings.moveevent) {
this.el.removeEventListener(eventName, this.onMoveEvent.bind(this));
}
/** Set the Y threshold of swipe events */
set swipeThresholdY(threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
}
this.settings.swipeVThreshold = threshold;
for (const eventName of this.settings.endevent) {
this.el.removeEventListener(eventName, this.onEndEvent.bind(this));
}
/** Set the double tap interval */
set doubleTapInt(interval) {
if (typeof interval !== 'number') {
throw new Error('Interval parameter must be a type of number');
}
this.settings.doubletapInterval = interval;
this.scrollEvents.removeEventListeners();
}
// HELPER METHODS:
getSwipeDir(
startPosition,
endPosition,
hThreshold = this.settings.swipeHThreshold,
vThreshold = this.settings.swipeVThreshold
) {
let swipeDir = "";
if (
startPosition.y > endPosition.y &&
startPosition.y - endPosition.y > vThreshold
) {
swipeDir = "swipeup";
}
/** Set the taphold threshold */
set tapHoldThreshold(threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
}
this.settings.tapholdThreshold = threshold;
if (
startPosition.x < endPosition.x &&
endPosition.x - startPosition.x > hThreshold
) {
swipeDir = "swiperight";
}
/** Set the pixel range for tapas */
set tapRange(range) {
if (typeof range !== 'number') {
throw new Error('Ranger parameter must be a type of number');
}
this.
settings.tapPixelRange = range;
if (
startPosition.y < endPosition.y &&
endPosition.y - startPosition.y > vThreshold
) {
swipeDir = "swipedown";
}
removeEventListeners() {
for (const eventName of this.settings.startevent) {
this.el.removeEventListener(eventName, this.onStartEvent.bind(this));
}
for (const eventName of this.settings.moveevent) {
this.el.removeEventListener(eventName, this.onMoveEvent.bind(this));
}
for (const eventName of this.settings.endevent) {
this.el.removeEventListener(eventName, this.onEndEvent.bind(this));
}
this.scrollEvents.removeEventListeners();
if (
startPosition.x > endPosition.x &&
startPosition.x - endPosition.x > hThreshold
) {
swipeDir = "swipeleft";
}
// HELPER METHODS:
getSwipeDir(startPosition, endPosition, hThreshold = this.settings.swipeHThreshold, vThreshold = this.settings.swipeVThreshold) {
let swipeDir = '';
if (startPosition.y > endPosition.y && (startPosition.y - endPosition.y > vThreshold)) {
swipeDir = 'swipeup';
}
if (startPosition.x < endPosition.x && (endPosition.x - startPosition.x > hThreshold)) {
swipeDir = 'swiperight';
}
if (startPosition.y < endPosition.y && (endPosition.y - startPosition.y > vThreshold)) {
swipeDir = 'swipedown';
}
if (startPosition.x > endPosition.x && (startPosition.x - endPosition.x > hThreshold)) {
swipeDir = 'swipeleft';
}
return swipeDir;
return swipeDir;
}
getPostion(event, type = TouchType.DEFAULT, index = 0) {
let touchesTypes;
switch (type) {
case TouchType.CHANGED:
touchesTypes = event.changedTouches;
break;
case TouchType.TARGET:
touchesTypes = event.targetTouches;
break;
default:
touchesTypes = event.touches;
break;
}
getPostion(event, type = TouchType.DEFAULT, index = 0) {
let touchesTypes;
switch (type) {
case TouchType.CHANGED:
touchesTypes = event.changedTouches;
break;
case TouchType.TARGET:
touchesTypes = event.targetTouches;
break;
default:
touchesTypes = event.touches;
break;
}
const position = {
x: (this.settings.touchCapable) ? touchesTypes[index].pageX : event.pageX,
y: (this.settings.touchCapable) ? touchesTypes[index].pageY : event.pageY,
};
return position;
const position = {
x: this.settings.touchCapable ? touchesTypes[index].pageX : event.pageX,
y: this.settings.touchCapable ? touchesTypes[index].pageY : event.pageY,
};
return position;
}
getOffset(event, type = TouchType.DEFAULT, index = 0) {
const boundingClientRect = this.el.getBoundingClientRect();
let touchesTypes;
switch (type) {
case TouchType.CHANGED:
touchesTypes = event.changedTouches;
break;
case TouchType.TARGET:
touchesTypes = event.targetTouches;
break;
default:
touchesTypes = event.touches;
break;
}
getOffset(event, type = TouchType.DEFAULT, index = 0) {
const boundingClientRect = this.el.getBoundingClientRect();
let touchesTypes;
switch (type) {
case TouchType.CHANGED:
touchesTypes = event.changedTouches;
break;
case TouchType.TARGET:
touchesTypes = event.targetTouches;
break;
default:
touchesTypes = event.touches;
break;
}
const offset = {
x: (this.settings.touchCapable) ? Math.round(touchesTypes[index].pageX - (boundingClientRect ? boundingClientRect.left : 0)) : Math.round(event.pageX - (boundingClientRect ? boundingClientRect.left : 0)),
y: (this.settings.touchCapable) ? Math.round(touchesTypes[index].pageY - (boundingClientRect ? boundingClientRect.top : 0)) : Math.round(event.pageY - (boundingClientRect ? boundingClientRect.top : 0)),
};
return offset;
const offset = {
x: this.settings.touchCapable
? Math.round(
touchesTypes[index].pageX -
(boundingClientRect ? boundingClientRect.left : 0)
)
: Math.round(
event.pageX - (boundingClientRect ? boundingClientRect.left : 0)
),
y: this.settings.touchCapable
? Math.round(
touchesTypes[index].pageY -
(boundingClientRect ? boundingClientRect.top : 0)
)
: Math.round(
event.pageY - (boundingClientRect ? boundingClientRect.top : 0)
),
};
return offset;
}
getTouchData(
event,
withIndex = false,
positionType = TouchType.DEFAULT,
offsetType = TouchType.CHANGED
) {
const touchData = {
position: this.getPostion(event, positionType),
offset: this.getOffset(event, offsetType),
time: Date.now(),
};
if (withIndex) {
touchData.index = utils_service_1.Utils.getElementIndex(event.target);
}
getTouchData(event, withIndex = false, positionType = TouchType.DEFAULT, offsetType = TouchType.CHANGED) {
const touchData = {
position: this.getPostion(event, positionType),
offset: this.getOffset(event, offsetType),
time: Date.now(),
};
if (withIndex) {
touchData.index = utils_service_1.Utils.getElementIndex(event.target);
}
return touchData;
return touchData;
}
addEventListeners() {
for (const eventName of this.settings.startevent) {
this.el.addEventListener(eventName, this.onStartEvent.bind(this));
}
addEventListeners() {
for (const eventName of this.settings.startevent) {
this.el.addEventListener(eventName, this.onStartEvent.bind(this));
}
for (const eventName of this.settings.moveevent) {
this.el.addEventListener(eventName, this.onMoveEvent.bind(this));
}
for (const eventName of this.settings.endevent) {
this.el.addEventListener(eventName, this.onEndEvent.bind(this));
}
for (const eventName of this.settings.moveevent) {
this.el.addEventListener(eventName, this.onMoveEvent.bind(this));
}
// EVENT HANDLERS:
onStartEvent(event) {
if (event.which && event.which !== 1) {
return false;
}
this.startPosition = this.getPostion(event, TouchType.TARGET);
this.endPosition = {
x: this.startPosition.x,
y: this.startPosition.y,
};
this.startTime = Date.now();
// For `doubletap`
this.doubletapped = false;
if (!this.firstTap) {
this.firstTap = this.getTouchData(event, true, TouchType.DEFAULT, TouchType.CHANGED);
}
// For `tap`, `swipe`
this.tapStarted = true;
this.swipeStarted = true;
// For `swipe`
this.originalCoord = this.getPostion(event, TouchType.TARGET);
this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.startEvnt = this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED);
this.tapstart(event);
this.taphold(event);
return true;
for (const eventName of this.settings.endevent) {
this.el.addEventListener(eventName, this.onEndEvent.bind(this));
}
onEndEvent(event) {
this.endPosition = this.getPostion(event, TouchType.CHANGED);
this.tapheld = false;
window.clearTimeout(this.holdTimer);
this.tapend(event);
this.swipeend(event);
this.tap(event);
this.doubletap(event);
this.singletap(event);
this.tapStarted = false;
this.swipeStarted = false;
this.hasSwiped = false;
return true;
}
// EVENT HANDLERS:
onStartEvent(event) {
if (event.which && event.which !== 1) {
return false;
}
onMoveEvent(event) {
this.endPosition = this.getPostion(event, TouchType.TARGET);
this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.tapmove(event);
this.swipe(event);
return true;
this.startPosition = this.getPostion(event, TouchType.TARGET);
this.endPosition = {
x: this.startPosition.x,
y: this.startPosition.y,
};
this.startTime = Date.now();
// For `doubletap`
this.doubletapped = false;
if (!this.firstTap) {
this.firstTap = this.getTouchData(
event,
true,
TouchType.DEFAULT,
TouchType.CHANGED
);
}
// CUSTOM EVENT METHODS:
/** tapstart Event */
tapstart(event) {
this.triggerCustomEvent('tapstart', event, this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED));
return true;
// For `tap`, `swipe`
this.tapStarted = true;
this.swipeStarted = true;
// For `swipe`
this.originalCoord = this.getPostion(event, TouchType.TARGET);
this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.startEvnt = this.getTouchData(
event,
false,
TouchType.DEFAULT,
TouchType.CHANGED
);
this.tapstart(event);
this.taphold(event);
return true;
}
onEndEvent(event) {
this.endPosition = this.getPostion(event, TouchType.CHANGED);
this.tapheld = false;
window.clearTimeout(this.holdTimer);
this.tapend(event);
this.swipeend(event);
this.tap(event);
this.doubletap(event);
this.singletap(event);
this.tapStarted = false;
this.swipeStarted = false;
this.hasSwiped = false;
return true;
}
onMoveEvent(event) {
this.endPosition = this.getPostion(event, TouchType.TARGET);
this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.tapmove(event);
this.swipe(event);
return true;
}
// CUSTOM EVENT METHODS:
/** tapstart Event */
tapstart(event) {
this.triggerCustomEvent(
"tapstart",
event,
this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED)
);
return true;
}
/** tapmove Event */
tapmove(event) {
this.triggerCustomEvent(
"tapmove",
event,
this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED)
);
return true;
}
/** tapend Event */
tapend(event) {
this.triggerCustomEvent(
"tapend",
event,
this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED)
);
return true;
}
/** taphold Event */
taphold(event) {
this.holdTimer = window.setTimeout(() => {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
// helded?
if (
(this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange)
) {
this.tapheld = true;
const endTime = Date.now();
const duration = endTime - this.startTime;
const touchesLength = event.targetTouches
? event.targetTouches.length
: 1;
const touches = [];
for (let i = 0; i < touchesLength; i++) {
const elOffset = this.el.getBoundingClientRect();
const touch = {
position: {
x: this.settings.touchCapable
? event.changedTouches[i].pageX
: event.pageX,
y: this.settings.touchCapable
? event.changedTouches[i].pageY
: event.pageY,
},
offset: {
x: this.settings.touchCapable
? Math.round(
event.changedTouches[i].pageX -
(elOffset ? elOffset.left : 0)
)
: Math.round(event.pageX - (elOffset ? elOffset.left : 0)),
y: this.settings.touchCapable
? Math.round(
event.changedTouches[i].pageY -
(elOffset ? elOffset.top : 0)
)
: Math.round(event.pageY - (elOffset ? elOffset.top : 0)),
},
};
touches.push(touch);
}
const eventName =
touchesLength > 1 ? "taphold" + touchesLength : "taphold";
const touchData = {
touches,
time: Date.now(),
duration,
};
this.triggerCustomEvent(eventName, event, touchData);
}
}, this.settings.tapholdThreshold);
return true;
}
/** doubletap Event */
doubletap(event) {
const now = Date.now();
const lastTouch = Number(this.lastTouch) || now + 1;
const delta = now - lastTouch;
if (this.actionTimer !== -1) {
window.clearTimeout(this.actionTimer);
}
/** tapmove Event */
tapmove(event) {
this.triggerCustomEvent('tapmove', event, this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED));
return true;
if (
delta < this.settings.doubletapInterval &&
delta > 100 &&
this.firstTap &&
utils_service_1.Utils.getElementIndex(event.target) ===
this.firstTap.index
) {
this.doubletapped = true;
window.clearTimeout(this.tapTimer);
const lastTap = this.getTouchData(
event,
true,
TouchType.CHANGED,
TouchType.CHANGED
);
const touchData = {
firstTap: this.firstTap,
secondTap: lastTap,
interval: lastTap.time - this.firstTap.time,
};
if (!this.cooling) {
this.triggerCustomEvent("doubletap", event, touchData);
this.firstTap = null;
}
this.cooling = true;
window.setTimeout(() => {
this.cooling = false;
}, this.settings.doubletapInterval);
} else {
this.actionTimer = window.setTimeout(
() => {
this.firstTap = null;
window.clearTimeout(this.actionTimer);
},
this.settings.doubletapInterval,
[event]
);
}
/** tapend Event */
tapend(event) {
this.triggerCustomEvent('tapend', event, this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED));
return true;
}
/** taphold Event */
taphold(event) {
this.holdTimer = window.setTimeout(() => {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
// helded?
if ((this.startPosition.x === this.endPosition.x
&&
this.startPosition.y === this.endPosition.y)
||
(diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange)) {
this.tapheld = true;
const endTime = Date.now();
const duration = endTime - this.startTime;
const touchesLength = (event.targetTouches) ? event.targetTouches.length : 1;
const touches = new Array();
for (let i = 0; i < touchesLength; i++) {
const elOffset = this.el.getBoundingClientRect();
const touch = {
position: {
x: (this.settings.touchCapable) ? event.changedTouches[i].pageX : event.pageX,
y: (this.settings.touchCapable) ? event.changedTouches[i].pageY : event.pageY,
},
offset: {
x: (this.settings.touchCapable) ? Math.round(event.changedTouches[i].pageX - (elOffset ? elOffset.left : 0)) : Math.round(event.pageX - (elOffset ? elOffset.left : 0)),
y: (this.settings.touchCapable) ? Math.round(event.changedTouches[i].pageY - (elOffset ? elOffset.top : 0)) : Math.round(event.pageY - (elOffset ? elOffset.top : 0)),
},
};
touches.push(touch);
}
const eventName = (touchesLength > 1) ? 'taphold' + touchesLength : 'taphold';
const touchData = {
touches,
time: Date.now(),
duration,
};
this.triggerCustomEvent(eventName, event, touchData);
}
}, this.settings.tapholdThreshold);
return true;
}
/** doubletap Event */
doubletap(event) {
const now = Date.now();
const lastTouch = Number(this.lastTouch) || now + 1;
const delta = now - lastTouch;
if (this.actionTimer !== -1) {
window.clearTimeout(this.actionTimer);
this.lastTouch = now;
}
/**
* singletap Event
* This is used in conjuction with doubletap when both events are needed on the same element
*/
singletap(event) {
this.tapTimer = window.setTimeout(() => {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
if (
!this.doubletapped &&
!this.tapheld &&
((this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange))
) {
const touchData = this.getTouchData(
event,
false,
TouchType.CHANGED,
TouchType.CHANGED
);
// Was it a taphold?
if (touchData.time - this.startTime < this.settings.tapholdThreshold) {
this.triggerCustomEvent("singletap", event, touchData);
}
if (delta < this.settings.doubletapInterval
&&
delta > 100
&&
(this.firstTap
&&
utils_service_1.Utils.getElementIndex(event.target) === this.firstTap.index)) {
this.doubletapped = true;
window.clearTimeout(this.tapTimer);
const lastTap = this.getTouchData(event, true, TouchType.CHANGED, TouchType.CHANGED);
const touchData = {
firstTap: this.firstTap,
secondTap: lastTap,
interval: lastTap.time - this.firstTap.time,
};
if (!this.cooling) {
this.triggerCustomEvent('doubletap', event, touchData);
this.firstTap = null;
}
this.cooling = true;
window.setTimeout(() => {
this.cooling = false;
}, this.settings.doubletapInterval);
}
else {
this.actionTimer = window.setTimeout(() => {
this.firstTap = null;
window.clearTimeout(this.actionTimer);
}, this.settings.doubletapInterval, [event]);
}
this.lastTouch = now;
}
/**
* singletap Event
* This is used in conjuction with doubletap when both events are needed on the same element
*/
singletap(event) {
this.tapTimer = window.setTimeout(() => {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
if (!this.doubletapped
&&
!this.tapheld
&&
(((this.startPosition.x === this.endPosition.x)
&&
(this.startPosition.y === this.endPosition.y))
||
(diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange))) {
const touchData = this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED);
// Was it a taphold?
if ((touchData.time - this.startTime) < this.settings.tapholdThreshold) {
this.triggerCustomEvent('singletap', event, touchData);
}
}
}, this.settings.doubletapInterval);
}
/** tap Event */
tap(event) {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
}
}, this.settings.doubletapInterval);
}
/** tap Event */
tap(event) {
const diffPosition = {
x: this.startPosition.x - this.endPosition.x,
y: this.startPosition.y - this.endPosition.y,
};
if (
this.tapStarted &&
Date.now() - this.startTime < this.settings.tapholdThreshold &&
((this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange))
) {
const touchesLength = event.targetTouches
? event.targetTouches.length
: 1;
const touches = [];
for (let i = 0; i < touchesLength; i++) {
const elOffset = this.el.getBoundingClientRect();
const touch = {
position: {
x: this.settings.touchCapable
? event.changedTouches[i].pageX
: event.pageX,
y: this.settings.touchCapable
? event.changedTouches[i].pageY
: event.pageY,
},
offset: {
x: this.settings.touchCapable
? Math.round(
event.changedTouches[i].pageX - (elOffset ? elOffset.left : 0)
)
: Math.round(event.pageX - (elOffset ? elOffset.left : 0)),
y: this.settings.touchCapable
? Math.round(
event.changedTouches[i].pageY - (elOffset ? elOffset.top : 0)
)
: Math.round(event.pageY - (elOffset ? elOffset.top : 0)),
},
};
if (this.tapStarted
&&
((Date.now() - this.startTime) < this.settings.tapholdThreshold)
&&
((this.startPosition.x === this.endPosition.x
&&
this.startPosition.y === this.endPosition.y)
||
(diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange))) {
const touchesLength = (event.targetTouches) ? event.targetTouches.length : 1;
const touches = new Array();
for (let i = 0; i < touchesLength; i++) {
const elOffset = this.el.getBoundingClientRect();
const touch = {
position: {
x: (this.settings.touchCapable) ? event.changedTouches[i].pageX : event.pageX,
y: (this.settings.touchCapable) ? event.changedTouches[i].pageY : event.pageY,
},
offset: {
x: (this.settings.touchCapable) ? Math.round(event.changedTouches[i].pageX - (elOffset ? elOffset.left : 0)) : Math.round(event.pageX - (elOffset ? elOffset.left : 0)),
y: (this.settings.touchCapable) ? Math.round(event.changedTouches[i].pageY - (elOffset ? elOffset.top : 0)) : Math.round(event.pageY - (elOffset ? elOffset.top : 0)),
},
};
touches.push(touch);
}
const touchData = {
touches,
time: Date.now(),
};
const eventName = (touchesLength > 1) ? 'tap' + touchesLength : 'tap';
this.triggerCustomEvent(eventName, event, touchData);
}
touches.push(touch);
}
const touchData = {
touches,
time: Date.now(),
};
const eventName = touchesLength > 1 ? "tap" + touchesLength : "tap";
this.triggerCustomEvent(eventName, event, touchData);
}
/**
* swipe Event
* (also handles swipeup, swiperight, swipedown and swipeleft)
*
* (similar to `touchMove` method in jquery touch events)
*/
swipe(event) {
const swipeDir = this.getSwipeDir(this.originalCoord, this.finalCoord);
if (swipeDir && this.swipeStarted && this.startEvnt) {
this.originalCoord.x = 0;
this.originalCoord.y = 0;
this.finalCoord.x = 0;
this.finalCoord.y = 0;
this.swipeStarted = false;
const endEvnt = this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED);
// Calculate the swipe amount (normalized):
const xAmount = Math.abs(this.startEvnt.position.x - endEvnt.position.x);
const yAmount = Math.abs(this.startEvnt.position.y - endEvnt.position.y);
const touchData = {
startEvnt: this.startEvnt,
endEvnt,
direction: swipeDir.replace('swipe', ''),
xAmount,
yAmount,
duration: endEvnt.time - this.startEvnt.time,
};
this.hasSwiped = true;
this.triggerCustomEvent('swipe', event, touchData);
this.triggerCustomEvent(swipeDir, event, touchData);
}
}
/**
* swipe Event
* (also handles swipeup, swiperight, swipedown and swipeleft)
*
* (similar to `touchMove` method in jquery touch events)
*/
swipe(event) {
const swipeDir = this.getSwipeDir(this.originalCoord, this.finalCoord);
if (swipeDir && this.swipeStarted && this.startEvnt) {
this.originalCoord.x = 0;
this.originalCoord.y = 0;
this.finalCoord.x = 0;
this.finalCoord.y = 0;
this.swipeStarted = false;
const endEvnt = this.getTouchData(
event,
false,
TouchType.DEFAULT,
TouchType.CHANGED
);
// Calculate the swipe amount (normalized):
const xAmount = Math.abs(this.startEvnt.position.x - endEvnt.position.x);
const yAmount = Math.abs(this.startEvnt.position.y - endEvnt.position.y);
const touchData = {
startEvnt: this.startEvnt,
endEvnt,
direction: swipeDir.replace("swipe", ""),
xAmount,
yAmount,
duration: endEvnt.time - this.startEvnt.time,
};
this.hasSwiped = true;
this.triggerCustomEvent("swipe", event, touchData);
this.triggerCustomEvent(swipeDir, event, touchData);
}
/**
* swipeend Event
* (similar `touchEnd` method in jquery touch events)
*/
swipeend(event) {
const endEvnt = this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED);
if (this.hasSwiped && this.startEvnt) {
const swipeDir = this.getSwipeDir(this.startEvnt.position, endEvnt.position);
// Calculate the swipe amount (normalized):
const xAmount = Math.abs(this.startEvnt.position.x - endEvnt.position.x);
const yAmount = Math.abs(this.startEvnt.position.y - endEvnt.position.y);
const touchData = {
startEvnt: this.startEvnt,
endEvnt,
direction: swipeDir.replace('swipe', ''),
xAmount,
yAmount,
duration: endEvnt.time - this.startEvnt.time,
};
this.triggerCustomEvent('swipeend', event, touchData);
}
}
/**
* swipeend Event
* (similar `touchEnd` method in jquery touch events)
*/
swipeend(event) {
const endEvnt = this.getTouchData(
event,
false,
TouchType.CHANGED,
TouchType.CHANGED
);
if (this.hasSwiped && this.startEvnt) {
const swipeDir = this.getSwipeDir(
this.startEvnt.position,
endEvnt.position
);
// Calculate the swipe amount (normalized):
const xAmount = Math.abs(this.startEvnt.position.x - endEvnt.position.x);
const yAmount = Math.abs(this.startEvnt.position.y - endEvnt.position.y);
const touchData = {
startEvnt: this.startEvnt,
endEvnt,
direction: swipeDir.replace("swipe", ""),
xAmount,
yAmount,
duration: endEvnt.time - this.startEvnt.time,
};
this.triggerCustomEvent("swipeend", event, touchData);
}
}
}
exports.TouchEventService = TouchEventService;

@@ -1,23 +0,23 @@

import { ScrollPosition } from '../types/scroll-position';
import { ScrollPosition } from "../types/scroll-position";
export declare class Utils {
static linear(t: number): number;
static easeInQuad(t: number): number;
static easeOutQuad(t: number): number;
static easeInOutQuad(t: number): number;
static easeInCubic(t: number): number;
static easeOutCubic(t: number): number;
static easeInOutCubic(t: number): number;
static easeInQuart(t: number): number;
static easeOutQuart(t: number): number;
static easeInOutQuart(t: number): number;
static easeInQuint(t: number): number;
static easeOutQuint(t: number): number;
static easeInOutQuint(t: number): number;
static getScrollPosition(element: Element): ScrollPosition;
static isScrollable(element: Element): boolean;
/**
* Similar to JQuerys `$(el).index();`
* @param el
*/
static getElementIndex(el: Element | null): number;
static linear(t: number): number;
static easeInQuad(t: number): number;
static easeOutQuad(t: number): number;
static easeInOutQuad(t: number): number;
static easeInCubic(t: number): number;
static easeOutCubic(t: number): number;
static easeInOutCubic(t: number): number;
static easeInQuart(t: number): number;
static easeOutQuart(t: number): number;
static easeInOutQuart(t: number): number;
static easeInQuint(t: number): number;
static easeOutQuint(t: number): number;
static easeInOutQuint(t: number): number;
static getScrollPosition(element: Element): ScrollPosition;
static isScrollable(element: Element): boolean;
/**
* Similar to JQuerys `$(el).index();`
* @param el
*/
static getElementIndex(el: Element | null): number;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class Utils {
// easings methods, see https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/
static linear(t) {
return t;
// easings methods, see https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/
static linear(t) {
return t;
}
static easeInQuad(t) {
return t * t;
}
static easeOutQuad(t) {
return t * (2 - t);
}
static easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
static easeInCubic(t) {
return t * t * t;
}
static easeOutCubic(t) {
return --t * t * t + 1;
}
static easeInOutCubic(t) {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
}
static easeInQuart(t) {
return t * t * t * t;
}
static easeOutQuart(t) {
return 1 - --t * t * t * t;
}
static easeInOutQuart(t) {
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
}
static easeInQuint(t) {
return t * t * t * t * t;
}
static easeOutQuint(t) {
return 1 + --t * t * t * t * t;
}
static easeInOutQuint(t) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
}
static getScrollPosition(element) {
const scrollPosition = {
/** horizontal: left / right / width */
x: element.scrollTop,
/** vertical: top / bottom / height */
y: element.scrollLeft,
/** horizontal: left / right / width */
maxX: element.scrollWidth - element.clientWidth,
/** vertical: top / bottom / height */
maxY: element.scrollHeight - element.clientHeight,
};
return scrollPosition;
}
static isScrollable(element) {
const scrollPosition = this.getScrollPosition(element);
return scrollPosition.maxX > 0 || scrollPosition.maxY > 0;
}
/**
* Similar to JQuerys `$(el).index();`
* @param el
*/
static getElementIndex(el) {
if (!el) {
return -1;
}
static easeInQuad(t) {
return t * t;
}
static easeOutQuad(t) {
return t * (2 - t);
}
static easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
static easeInCubic(t) {
return t * t * t;
}
static easeOutCubic(t) {
return (--t) * t * t + 1;
}
static easeInOutCubic(t) {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
}
static easeInQuart(t) {
return t * t * t * t;
}
static easeOutQuart(t) {
return 1 - (--t) * t * t * t;
}
static easeInOutQuart(t) {
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
}
static easeInQuint(t) {
return t * t * t * t * t;
}
static easeOutQuint(t) {
return 1 + (--t) * t * t * t * t;
}
static easeInOutQuint(t) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t;
}
static getScrollPosition(element) {
const scrollPosition = {
/** horizontal: left / right / width */
x: element.scrollTop,
/** vertical: top / bottom / height */
y: element.scrollLeft,
/** horizontal: left / right / width */
maxX: element.scrollWidth - element.clientWidth,
/** vertical: top / bottom / height */
maxY: element.scrollHeight - element.clientHeight,
};
return scrollPosition;
}
static isScrollable(element) {
const scrollPosition = this.getScrollPosition(element);
return scrollPosition.maxX > 0 || scrollPosition.maxY > 0;
}
/**
* Similar to JQuerys `$(el).index();`
* @param el
*/
static getElementIndex(el) {
if (!el) {
return -1;
}
let i = 0;
do {
i++;
el = el.previousElementSibling;
} while (el);
return i;
}
let i = 0;
do {
i++;
el = el.previousElementSibling;
} while (el);
return i;
}
}
exports.Utils = Utils;

@@ -1,2 +0,2 @@

export * from './position';
export * from './scroll-position';
export * from "./position";
export * from "./scroll-position";
export interface Position {
x: number;
y: number;
x: number;
y: number;
}

@@ -1,7 +0,7 @@

import { Position } from './position';
import { Position } from "./position";
export interface ScrollPosition extends Position {
/** horizontal: left / right / width */
maxX: number;
/** vertical: top / bottom / height */
maxY: number;
/** horizontal: left / right / width */
maxX: number;
/** vertical: top / bottom / height */
maxY: number;
}

@@ -33,694 +33,1119 @@ "use strict";

exports.default = ($) => {
if (!$) {
console.error('JQuery is required for touch events!');
return;
if (!$) {
console.error("JQuery is required for touch events!");
return;
}
("use strict");
$.attrFn = $.attrFn || {};
let touchCapable = "ontouchstart" in window,
settings = {
tap_pixel_range: 5,
swipe_h_threshold: 50,
swipe_v_threshold: 50,
taphold_threshold: 750,
doubletap_int: 500,
shake_threshold: 15,
touch_capable: touchCapable,
orientation_support:
"orientation" in window && "onorientationchange" in window,
startevent: touchCapable ? "touchstart" : "mousedown",
endevent: touchCapable ? "touchend" : "mouseup",
moveevent: touchCapable ? "touchmove" : "mousemove",
tapevent: touchCapable ? "tap" : "click",
scrollevent: touchCapable ? "touchmove" : "scroll",
hold_timer: undefined,
tap_timer: undefined,
};
// Declare touch namespace:
$.touch = {};
// Convenience functions:
$.isTouchCapable = function () {
return settings.touch_capable;
};
$.getStartEvent = function () {
return settings.startevent;
};
$.getEndEvent = function () {
return settings.endevent;
};
$.getMoveEvent = function () {
return settings.moveevent;
};
$.getTapEvent = function () {
return settings.tapevent;
};
$.getScrollEvent = function () {
return settings.scrollevent;
};
// SETTERS:
// Set the X threshold of swipe events:
$.touch.setSwipeThresholdX = function (threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
'use strict';
$.attrFn = $.attrFn || {};
let touchCapable = ('ontouchstart' in window), settings = {
tap_pixel_range: 5,
swipe_h_threshold: 50,
swipe_v_threshold: 50,
taphold_threshold: 750,
doubletap_int: 500,
shake_threshold: 15,
touch_capable: touchCapable,
orientation_support: ('orientation' in window && 'onorientationchange' in window),
startevent: (touchCapable) ? 'touchstart' : 'mousedown',
endevent: (touchCapable) ? 'touchend' : 'mouseup',
moveevent: (touchCapable) ? 'touchmove' : 'mousemove',
tapevent: (touchCapable) ? 'tap' : 'click',
scrollevent: (touchCapable) ? 'touchmove' : 'scroll',
hold_timer: undefined,
tap_timer: undefined,
};
// Declare touch namespace:
$.touch = {};
// Convenience functions:
$.isTouchCapable = function () { return settings.touch_capable; };
$.getStartEvent = function () { return settings.startevent; };
$.getEndEvent = function () { return settings.endevent; };
$.getMoveEvent = function () { return settings.moveevent; };
$.getTapEvent = function () { return settings.tapevent; };
$.getScrollEvent = function () { return settings.scrollevent; };
// SETTERS:
// Set the X threshold of swipe events:
$.touch.setSwipeThresholdX = function (threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
settings.swipe_h_threshold = threshold;
};
// Set the Y threshold of swipe events:
$.touch.setSwipeThresholdY = function (threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
settings.swipe_v_threshold = threshold;
};
// Set the double tap interval:
$.touch.setDoubleTapInt = function (interval) {
if (typeof interval !== "number") {
throw new Error("Interval parameter must be a type of number");
}
settings.doubletap_int = interval;
};
// Set the taphold threshold:
$.touch.setTapHoldThreshold = function (threshold) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
settings.taphold_threshold = threshold;
};
// Set the pixel range for tapas:
$.touch.setTapRange = function (range) {
if (typeof range !== "number") {
throw new Error("Ranger parameter must be a type of number");
}
settings.tap_pixel_range = range;
};
// Add Event shortcuts:
$.each(
[
"tapstart",
"tapend",
"tapmove",
"tap",
"singletap",
"doubletap",
"taphold",
"swipe",
"swipeup",
"swiperight",
"swipedown",
"swipeleft",
"swipeend",
"scrollstart",
"scrollend",
"orientationchange",
"tap2",
"taphold2",
],
function (i, name) {
$.fn[name] = function (fn) {
return fn ? this.on(name, fn) : this.trigger(name);
};
$.attrFn[name] = true;
}
);
// tapstart Event:
$.event.special.tapstart = {
setup: function () {
var thisObject = this,
$this = $(thisObject);
$this.on(settings.startevent, function tapStartFunc(e) {
$this.data("callee", tapStartFunc);
if (e.which && e.which !== 1) {
return false;
}
settings.swipe_h_threshold = threshold;
};
// Set the Y threshold of swipe events:
$.touch.setSwipeThresholdY = function (threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
}
settings.swipe_v_threshold = threshold;
};
// Set the double tap interval:
$.touch.setDoubleTapInt = function (interval) {
if (typeof interval !== 'number') {
throw new Error('Interval parameter must be a type of number');
}
settings.doubletap_int = interval;
};
// Set the taphold threshold:
$.touch.setTapHoldThreshold = function (threshold) {
if (typeof threshold !== 'number') {
throw new Error('Threshold parameter must be a type of number');
}
settings.taphold_threshold = threshold;
};
// Set the pixel range for tapas:
$.touch.setTapRange = function (range) {
if (typeof range !== 'number') {
throw new Error('Ranger parameter must be a type of number');
}
settings.tap_pixel_range = range;
};
// Add Event shortcuts:
$.each(['tapstart', 'tapend', 'tapmove', 'tap', 'singletap', 'doubletap', 'taphold', 'swipe', 'swipeup', 'swiperight', 'swipedown', 'swipeleft', 'swipeend', 'scrollstart', 'scrollend', 'orientationchange', 'tap2', 'taphold2'], function (i, name) {
$.fn[name] = function (fn) {
return fn ? this.on(name, fn) : this.trigger(name);
var origEvent = e.originalEvent,
touchData = {
position: {
x: settings.touch_capable ? origEvent.touches[0].pageX : e.pageX,
y: settings.touch_capable ? origEvent.touches[0].pageY : e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
time: Date.now(),
target: e.target,
};
triggerCustomEvent(thisObject, "tapstart", e, touchData);
return true;
});
},
remove: function () {
$(this).off(settings.startevent, $(this).data.callee);
},
};
// tapmove Event:
$.event.special.tapmove = {
setup: function () {
var thisObject = this,
$this = $(thisObject);
$this.on(settings.moveevent, function tapMoveFunc(e) {
$this.data("callee", tapMoveFunc);
var origEvent = e.originalEvent,
touchData = {
position: {
x: settings.touch_capable ? origEvent.touches[0].pageX : e.pageX,
y: settings.touch_capable ? origEvent.touches[0].pageY : e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
time: Date.now(),
target: e.target,
};
triggerCustomEvent(thisObject, "tapmove", e, touchData);
return true;
});
},
remove: function () {
$(this).off(settings.moveevent, $(this).data.callee);
},
};
// tapend Event:
$.event.special.tapend = {
setup: function () {
var thisObject = this,
$this = $(thisObject);
$this.on(settings.endevent, function tapEndFunc(e) {
// Touch event data:
$this.data("callee", tapEndFunc);
var origEvent = e.originalEvent;
var touchData = {
position: {
x: settings.touch_capable
? origEvent.changedTouches[0].pageX
: e.pageX,
y: settings.touch_capable
? origEvent.changedTouches[0].pageY
: e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0)),
},
time: Date.now(),
target: e.target,
};
$.attrFn[name] = true;
});
// tapstart Event:
$.event.special.tapstart = {
setup: function () {
var thisObject = this, $this = $(thisObject);
$this.on(settings.startevent, function tapStartFunc(e) {
$this.data('callee', tapStartFunc);
if (e.which && e.which !== 1) {
return false;
}
var origEvent = e.originalEvent, touchData = {
'position': {
'x': ((settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX),
'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target
};
triggerCustomEvent(thisObject, 'tapstart', e, touchData);
return true;
});
triggerCustomEvent(thisObject, "tapend", e, touchData);
return true;
});
},
remove: function () {
$(this).off(settings.endevent, $(this).data.callee);
},
};
// taphold Event:
$.event.special.taphold = {
setup: function () {
var thisObject = this,
$this = $(thisObject),
origTarget,
start_pos = {
x: 0,
y: 0,
},
remove: function () {
$(this).off(settings.startevent, $(this).data.callee);
}
};
// tapmove Event:
$.event.special.tapmove = {
setup: function () {
var thisObject = this, $this = $(thisObject);
$this.on(settings.moveevent, function tapMoveFunc(e) {
$this.data('callee', tapMoveFunc);
var origEvent = e.originalEvent, touchData = {
'position': {
'x': ((settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX),
'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
end_x = 0,
end_y = 0;
$this
.on(settings.startevent, function tapHoldFunc1(e) {
if (e.which && e.which !== 1) {
return false;
} else {
$this.data("tapheld", false);
origTarget = e.target;
var origEvent = e.originalEvent;
var start_time = Date.now();
start_pos.x = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageX
: e.pageX;
start_pos.y = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageY
: e.pageY;
end_x = start_pos.x;
end_y = start_pos.y;
// Get the element's threshold:
var ele_threshold = $this.parent().data("threshold")
? $this.parent().data("threshold")
: $this.data("threshold"),
threshold =
typeof ele_threshold !== "undefined" &&
ele_threshold !== false &&
parseInt(ele_threshold)
? parseInt(ele_threshold)
: settings.taphold_threshold;
settings.hold_timer = window.setTimeout(function () {
var diff_x = start_pos.x - end_x,
diff_y = start_pos.y - end_y;
if (
e.target == origTarget &&
((start_pos.x == end_x && start_pos.y == end_y) ||
(diff_x >= -settings.tap_pixel_range &&
diff_x <= settings.tap_pixel_range &&
diff_y >= -settings.tap_pixel_range &&
diff_y <= settings.tap_pixel_range))
) {
$this.data("tapheld", true);
var end_time = Date.now();
var duration = end_time - start_time,
touches = e.originalEvent.targetTouches
? e.originalEvent.targetTouches
: [e],
touchData = [];
for (var i = 0; i < touches.length; i++) {
var touch = {
position: {
x: settings.touch_capable
? origEvent.changedTouches[i].pageX
: e.pageX,
y: settings.touch_capable
? origEvent.changedTouches[i].pageY
: e.pageY,
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[i].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[i].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
'time': Date.now(),
'target': e.target
};
triggerCustomEvent(thisObject, 'tapmove', e, touchData);
return true;
});
},
remove: function () {
$(this).off(settings.moveevent, $(this).data.callee);
}
};
// tapend Event:
$.event.special.tapend = {
setup: function () {
var thisObject = this, $this = $(thisObject);
$this.on(settings.endevent, function tapEndFunc(e) {
// Touch event data:
$this.data('callee', tapEndFunc);
time: Date.now(),
target: e.target,
duration: duration,
};
touchData.push(touch);
}
var evt_name = touches.length == 2 ? "taphold2" : "taphold";
$this.data("callee1", tapHoldFunc1);
triggerCustomEvent(thisObject, evt_name, e, touchData);
}
}, threshold);
return true;
}
})
.on(settings.endevent, function tapHoldFunc2() {
$this.data("callee2", tapHoldFunc2);
$this.data("tapheld", false);
window.clearTimeout(settings.hold_timer);
})
.on(settings.moveevent, function tapHoldFunc3(e) {
$this.data("callee3", tapHoldFunc3);
end_x = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageX
: e.pageX;
end_y = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageY
: e.pageY;
});
},
remove: function () {
$(this)
.off(settings.startevent, $(this).data.callee1)
.off(settings.endevent, $(this).data.callee2)
.off(settings.moveevent, $(this).data.callee3);
},
};
// doubletap Event:
$.event.special.doubletap = {
setup: function () {
var thisObject = this,
$this = $(thisObject),
action,
firstTap = null,
origEvent,
cooling = false;
$this
.on(settings.startevent, function doubleTapFunc1(e) {
if (e.which && e.which !== 1) {
return false;
}
$this.data("doubletapped", false);
$this.data("callee1", doubleTapFunc1);
origEvent = e.originalEvent;
if (!firstTap) {
firstTap = {
position: {
x: settings.touch_capable
? origEvent.touches[0].pageX
: e.pageX,
y: settings.touch_capable
? origEvent.touches[0].pageY
: e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
time: Date.now(),
target: e.target,
element: e.originalEvent.srcElement,
index: $(e.target).index(),
};
}
return true;
})
.on(settings.endevent, function doubleTapFunc2(e) {
var now = Date.now();
var lastTouch = $this.data("lastTouch") || now + 1;
var delta = now - lastTouch;
window.clearTimeout(action);
$this.data("callee2", doubleTapFunc2);
if (
delta < settings.doubletap_int &&
$(e.target).index() == firstTap.index &&
delta > 100
) {
$this.data("doubletapped", true);
window.clearTimeout(settings.tap_timer);
// Now get the current event:
var lastTap = {
position: {
x: settings.touch_capable
? e.originalEvent.changedTouches[0].pageX
: e.pageX,
y: settings.touch_capable
? e.originalEvent.changedTouches[0].pageY
: e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
time: Date.now(),
target: e.target,
element: e.originalEvent.srcElement,
index: $(e.target).index(),
};
var touchData = {
firstTap: firstTap,
secondTap: lastTap,
interval: lastTap.time - firstTap.time,
};
if (!cooling) {
triggerCustomEvent(thisObject, "doubletap", e, touchData);
firstTap = null;
}
cooling = true;
} else {
$this.data("lastTouch", now);
action = window.setTimeout(
function () {
firstTap = null;
window.clearTimeout(action);
},
settings.doubletap_int,
[e]
);
}
$this.data("lastTouch", now);
});
},
remove: function () {
$(this)
.off(settings.startevent, $(this).data.callee1)
.off(settings.endevent, $(this).data.callee2);
},
};
// singletap Event:
// This is used in conjuction with doubletap when both events are needed on the same element
$.event.special.singletap = {
setup: function () {
var thisObject = this,
$this = $(thisObject),
origTarget = null,
startTime = null,
start_pos = {
x: 0,
y: 0,
};
$this
.on(settings.startevent, function singleTapFunc1(e) {
if (e.which && e.which !== 1) {
return false;
} else {
startTime = Date.now();
origTarget = e.target;
$this.data("callee1", singleTapFunc1);
// Get the start x and y position:
start_pos.x = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageX
: e.pageX;
start_pos.y = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageY
: e.pageY;
return true;
}
})
.on(settings.endevent, function singleTapFunc2(e) {
$this.data("callee2", singleTapFunc2);
if (e.target === origTarget) {
// Get the end point:
var end_pos_x = e.originalEvent.changedTouches
? e.originalEvent.changedTouches[0].pageX
: e.pageX,
end_pos_y = e.originalEvent.changedTouches
? e.originalEvent.changedTouches[0].pageY
: e.pageY;
// We need to check if it was a taphold:
settings.tap_timer = window.setTimeout(function () {
var diff_x = start_pos.x - end_pos_x,
diff_y = start_pos.y - end_pos_y;
if (
!$this.data("doubletapped") &&
!$this.data("tapheld") &&
((start_pos.x == end_pos_x && start_pos.y == end_pos_y) ||
(diff_x >= -settings.tap_pixel_range &&
diff_x <= settings.tap_pixel_range &&
diff_y >= -settings.tap_pixel_range &&
diff_y <= settings.tap_pixel_range))
) {
var origEvent = e.originalEvent;
var touchData = {
'position': {
'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX : e.pageX,
'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target
position: {
x: settings.touch_capable
? origEvent.changedTouches[0].pageX
: e.pageX,
y: settings.touch_capable
? origEvent.changedTouches[0].pageY
: e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
time: Date.now(),
target: e.target,
};
triggerCustomEvent(thisObject, 'tapend', e, touchData);
return true;
});
},
remove: function () {
$(this).off(settings.endevent, $(this).data.callee);
}
};
// taphold Event:
$.event.special.taphold = {
setup: function () {
var thisObject = this, $this = $(thisObject), origTarget, start_pos = {
x: 0,
y: 0
}, end_x = 0, end_y = 0;
$this.on(settings.startevent, function tapHoldFunc1(e) {
if (e.which && e.which !== 1) {
return false;
// Was it a taphold?
if (touchData.time - startTime < settings.taphold_threshold) {
triggerCustomEvent(thisObject, "singletap", e, touchData);
}
else {
$this.data('tapheld', false);
origTarget = e.target;
var origEvent = e.originalEvent;
var start_time = Date.now();
start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
end_x = start_pos.x;
end_y = start_pos.y;
// Get the element's threshold:
var ele_threshold = ($this.parent().data('threshold')) ? $this.parent().data('threshold') : $this.data('threshold'), threshold = (typeof ele_threshold !== 'undefined' && ele_threshold !== false && parseInt(ele_threshold)) ? parseInt(ele_threshold) : settings.taphold_threshold;
settings.hold_timer = window.setTimeout(function () {
var diff_x = (start_pos.x - end_x), diff_y = (start_pos.y - end_y);
if (e.target == origTarget && ((start_pos.x == end_x && start_pos.y == end_y) || (diff_x >= -(settings.tap_pixel_range) && diff_x <= settings.tap_pixel_range && diff_y >= -(settings.tap_pixel_range) && diff_y <= settings.tap_pixel_range))) {
$this.data('tapheld', true);
var end_time = Date.now();
var duration = end_time - start_time, touches = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches : [e], touchData = [];
for (var i = 0; i < touches.length; i++) {
var touch = {
'position': {
'x': (settings.touch_capable) ? origEvent.changedTouches[i].pageX : e.pageX,
'y': (settings.touch_capable) ? origEvent.changedTouches[i].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[i].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[i].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target,
'duration': duration
};
touchData.push(touch);
}
var evt_name = (touches.length == 2) ? 'taphold2' : 'taphold';
$this.data('callee1', tapHoldFunc1);
triggerCustomEvent(thisObject, evt_name, e, touchData);
}
}, threshold);
return true;
}
}).on(settings.endevent, function tapHoldFunc2() {
$this.data('callee2', tapHoldFunc2);
$this.data('tapheld', false);
window.clearTimeout(settings.hold_timer);
})
.on(settings.moveevent, function tapHoldFunc3(e) {
$this.data('callee3', tapHoldFunc3);
end_x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
end_y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
});
}
}, settings.doubletap_int);
}
});
},
remove: function () {
$(this)
.off(settings.startevent, $(this).data.callee1)
.off(settings.endevent, $(this).data.callee2);
},
};
// tap Event:
$.event.special.tap = {
setup: function () {
var thisObject = this,
$this = $(thisObject),
started = false,
origTarget = null,
start_time,
start_pos = {
x: 0,
y: 0,
},
remove: function () {
$(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2).off(settings.moveevent, $(this).data.callee3);
}
};
// doubletap Event:
$.event.special.doubletap = {
setup: function () {
var thisObject = this, $this = $(thisObject), action, firstTap = null, origEvent, cooling = false;
$this.on(settings.startevent, function doubleTapFunc1(e) {
if (e.which && e.which !== 1) {
return false;
}
$this.data('doubletapped', false);
$this.data('callee1', doubleTapFunc1);
origEvent = e.originalEvent;
if (!firstTap) {
firstTap = {
'position': {
'x': (settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX,
'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target,
'element': e.originalEvent.srcElement,
'index': $(e.target).index()
};
}
return true;
}).on(settings.endevent, function doubleTapFunc2(e) {
var now = Date.now();
var lastTouch = $this.data('lastTouch') || now + 1;
var delta = now - lastTouch;
window.clearTimeout(action);
$this.data('callee2', doubleTapFunc2);
if (delta < settings.doubletap_int && ($(e.target).index() == firstTap.index) && delta > 100) {
$this.data('doubletapped', true);
window.clearTimeout(settings.tap_timer);
// Now get the current event:
var lastTap = {
'position': {
'x': (settings.touch_capable) ? e.originalEvent.changedTouches[0].pageX : e.pageX,
'y': (settings.touch_capable) ? e.originalEvent.changedTouches[0].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target,
'element': e.originalEvent.srcElement,
'index': $(e.target).index()
};
var touchData = {
'firstTap': firstTap,
'secondTap': lastTap,
'interval': lastTap.time - firstTap.time
};
if (!cooling) {
triggerCustomEvent(thisObject, 'doubletap', e, touchData);
firstTap = null;
}
cooling = true;
}
else {
$this.data('lastTouch', now);
action = window.setTimeout(function () {
firstTap = null;
window.clearTimeout(action);
}, settings.doubletap_int, [e]);
}
$this.data('lastTouch', now);
});
touches;
$this
.on(settings.startevent, function tapFunc1(e) {
$this.data("callee1", tapFunc1);
if (e.which && e.which !== 1) {
return false;
} else {
started = true;
start_pos.x = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageX
: e.pageX;
start_pos.y = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageY
: e.pageY;
start_time = Date.now();
origTarget = e.target;
touches = e.originalEvent.targetTouches
? e.originalEvent.targetTouches
: [e];
return true;
}
})
.on(settings.endevent, function tapFunc2(e) {
$this.data("callee2", tapFunc2);
// Only trigger if they've started, and the target matches:
var end_x = e.originalEvent.targetTouches
? e.originalEvent.changedTouches[0].pageX
: e.pageX,
end_y = e.originalEvent.targetTouches
? e.originalEvent.changedTouches[0].pageY
: e.pageY,
diff_x = start_pos.x - end_x,
diff_y = start_pos.y - end_y;
if (
origTarget == e.target &&
started &&
Date.now() - start_time < settings.taphold_threshold &&
((start_pos.x == end_x && start_pos.y == end_y) ||
(diff_x >= -settings.tap_pixel_range &&
diff_x <= settings.tap_pixel_range &&
diff_y >= -settings.tap_pixel_range &&
diff_y <= settings.tap_pixel_range))
) {
var origEvent = e.originalEvent;
var touchData = [];
for (var i = 0; i < touches.length; i++) {
var touch = {
position: {
x: settings.touch_capable
? origEvent.changedTouches[i].pageX
: e.pageX,
y: settings.touch_capable
? origEvent.changedTouches[i].pageY
: e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[i].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[i].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
time: Date.now(),
target: e.target,
};
touchData.push(touch);
}
var evt_name = touches.length == 2 ? "tap2" : "tap";
triggerCustomEvent(thisObject, evt_name, e, touchData);
}
});
},
remove: function () {
$(this)
.off(settings.startevent, $(this).data.callee1)
.off(settings.endevent, $(this).data.callee2);
},
};
// swipe Event (also handles swipeup, swiperight, swipedown and swipeleft):
$.event.special.swipe = {
setup: function () {
var thisObject = this,
$this = $(thisObject),
started = false,
hasSwiped = false,
originalCoord = {
x: 0,
y: 0,
},
remove: function () {
$(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);
}
};
// singletap Event:
// This is used in conjuction with doubletap when both events are needed on the same element
$.event.special.singletap = {
setup: function () {
var thisObject = this, $this = $(thisObject), origTarget = null, startTime = null, start_pos = {
x: 0,
y: 0
};
$this.on(settings.startevent, function singleTapFunc1(e) {
if (e.which && e.which !== 1) {
return false;
}
else {
startTime = Date.now();
origTarget = e.target;
$this.data('callee1', singleTapFunc1);
// Get the start x and y position:
start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
return true;
}
}).on(settings.endevent, function singleTapFunc2(e) {
$this.data('callee2', singleTapFunc2);
if (e.target === origTarget) {
// Get the end point:
var end_pos_x = (e.originalEvent.changedTouches) ? e.originalEvent.changedTouches[0].pageX : e.pageX, end_pos_y = (e.originalEvent.changedTouches) ? e.originalEvent.changedTouches[0].pageY : e.pageY;
// We need to check if it was a taphold:
settings.tap_timer = window.setTimeout(function () {
var diff_x = (start_pos.x - end_pos_x), diff_y = (start_pos.y - end_pos_y);
if (!$this.data('doubletapped') && !$this.data('tapheld') && (((start_pos.x == end_pos_x) && (start_pos.y == end_pos_y)) || (diff_x >= -(settings.tap_pixel_range) && diff_x <= settings.tap_pixel_range && diff_y >= -(settings.tap_pixel_range) && diff_y <= settings.tap_pixel_range))) {
var origEvent = e.originalEvent;
var touchData = {
'position': {
'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX : e.pageX,
'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target
};
// Was it a taphold?
if ((touchData.time - startTime) < settings.taphold_threshold) {
triggerCustomEvent(thisObject, 'singletap', e, touchData);
}
}
}, settings.doubletap_int);
}
});
finalCoord = {
x: 0,
y: 0,
},
remove: function () {
$(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);
startEvnt;
// Screen touched, store the original coordinate
function touchStart(e) {
$this = $(e.currentTarget);
$this.data("callee1", touchStart);
originalCoord.x = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageX
: e.pageX;
originalCoord.y = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageY
: e.pageY;
finalCoord.x = originalCoord.x;
finalCoord.y = originalCoord.y;
started = true;
var origEvent = e.originalEvent;
// Read event data into our startEvt:
startEvnt = {
position: {
x: settings.touch_capable ? origEvent.touches[0].pageX : e.pageX,
y: settings.touch_capable ? origEvent.touches[0].pageY : e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0)),
},
time: Date.now(),
target: e.target,
};
}
// Store coordinates as finger is swiping
function touchMove(e) {
$this = $(e.currentTarget);
$this.data("callee2", touchMove);
finalCoord.x = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageX
: e.pageX;
finalCoord.y = e.originalEvent.targetTouches
? e.originalEvent.targetTouches[0].pageY
: e.pageY;
var swipedir;
// We need to check if the element to which the event was bound contains a data-xthreshold | data-vthreshold:
var ele_x_threshold = $this.parent().data("xthreshold")
? $this.parent().data("xthreshold")
: $this.data("xthreshold"),
ele_y_threshold = $this.parent().data("ythreshold")
? $this.parent().data("ythreshold")
: $this.data("ythreshold"),
h_threshold =
typeof ele_x_threshold !== "undefined" &&
ele_x_threshold !== false &&
parseInt(ele_x_threshold)
? parseInt(ele_x_threshold)
: settings.swipe_h_threshold,
v_threshold =
typeof ele_y_threshold !== "undefined" &&
ele_y_threshold !== false &&
parseInt(ele_y_threshold)
? parseInt(ele_y_threshold)
: settings.swipe_v_threshold;
if (
originalCoord.y > finalCoord.y &&
originalCoord.y - finalCoord.y > v_threshold
) {
swipedir = "swipeup";
}
};
// tap Event:
$.event.special.tap = {
setup: function () {
var thisObject = this, $this = $(thisObject), started = false, origTarget = null, start_time, start_pos = {
x: 0,
y: 0
}, touches;
$this.on(settings.startevent, function tapFunc1(e) {
$this.data('callee1', tapFunc1);
if (e.which && e.which !== 1) {
return false;
}
else {
started = true;
start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
start_time = Date.now();
origTarget = e.target;
touches = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches : [e];
return true;
}
}).on(settings.endevent, function tapFunc2(e) {
$this.data('callee2', tapFunc2);
// Only trigger if they've started, and the target matches:
var end_x = (e.originalEvent.targetTouches) ? e.originalEvent.changedTouches[0].pageX : e.pageX, end_y = (e.originalEvent.targetTouches) ? e.originalEvent.changedTouches[0].pageY : e.pageY, diff_x = (start_pos.x - end_x), diff_y = (start_pos.y - end_y);
if (origTarget == e.target && started && ((Date.now() - start_time) < settings.taphold_threshold) && ((start_pos.x == end_x && start_pos.y == end_y) || (diff_x >= -(settings.tap_pixel_range) && diff_x <= settings.tap_pixel_range && diff_y >= -(settings.tap_pixel_range) && diff_y <= settings.tap_pixel_range))) {
var origEvent = e.originalEvent;
var touchData = [];
for (var i = 0; i < touches.length; i++) {
var touch = {
'position': {
'x': (settings.touch_capable) ? origEvent.changedTouches[i].pageX : e.pageX,
'y': (settings.touch_capable) ? origEvent.changedTouches[i].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[i].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[i].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target
};
touchData.push(touch);
}
var evt_name = (touches.length == 2) ? 'tap2' : 'tap';
triggerCustomEvent(thisObject, evt_name, e, touchData);
}
});
},
remove: function () {
$(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);
if (
originalCoord.x < finalCoord.x &&
finalCoord.x - originalCoord.x > h_threshold
) {
swipedir = "swiperight";
}
};
// swipe Event (also handles swipeup, swiperight, swipedown and swipeleft):
$.event.special.swipe = {
setup: function () {
var thisObject = this, $this = $(thisObject), started = false, hasSwiped = false, originalCoord = {
x: 0,
y: 0
}, finalCoord = {
x: 0,
y: 0
}, startEvnt;
// Screen touched, store the original coordinate
function touchStart(e) {
$this = $(e.currentTarget);
$this.data('callee1', touchStart);
originalCoord.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
originalCoord.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
finalCoord.x = originalCoord.x;
finalCoord.y = originalCoord.y;
started = true;
var origEvent = e.originalEvent;
// Read event data into our startEvt:
startEvnt = {
'position': {
'x': (settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX,
'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target
};
}
// Store coordinates as finger is swiping
function touchMove(e) {
$this = $(e.currentTarget);
$this.data('callee2', touchMove);
finalCoord.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
finalCoord.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
var swipedir;
// We need to check if the element to which the event was bound contains a data-xthreshold | data-vthreshold:
var ele_x_threshold = ($this.parent().data('xthreshold')) ? $this.parent().data('xthreshold') : $this.data('xthreshold'), ele_y_threshold = ($this.parent().data('ythreshold')) ? $this.parent().data('ythreshold') : $this.data('ythreshold'), h_threshold = (typeof ele_x_threshold !== 'undefined' && ele_x_threshold !== false && parseInt(ele_x_threshold)) ? parseInt(ele_x_threshold) : settings.swipe_h_threshold, v_threshold = (typeof ele_y_threshold !== 'undefined' && ele_y_threshold !== false && parseInt(ele_y_threshold)) ? parseInt(ele_y_threshold) : settings.swipe_v_threshold;
if (originalCoord.y > finalCoord.y && (originalCoord.y - finalCoord.y > v_threshold)) {
swipedir = 'swipeup';
}
if (originalCoord.x < finalCoord.x && (finalCoord.x - originalCoord.x > h_threshold)) {
swipedir = 'swiperight';
}
if (originalCoord.y < finalCoord.y && (finalCoord.y - originalCoord.y > v_threshold)) {
swipedir = 'swipedown';
}
if (originalCoord.x > finalCoord.x && (originalCoord.x - finalCoord.x > h_threshold)) {
swipedir = 'swipeleft';
}
if (swipedir != undefined && started) {
originalCoord.x = 0;
originalCoord.y = 0;
finalCoord.x = 0;
finalCoord.y = 0;
started = false;
// Read event data into our endEvnt:
var origEvent = e.originalEvent;
var endEvnt = {
'position': {
'x': (settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX,
'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target
};
// Calculate the swipe amount (normalized):
var xAmount = Math.abs(startEvnt.position.x - endEvnt.position.x), yAmount = Math.abs(startEvnt.position.y - endEvnt.position.y);
var touchData = {
'startEvnt': startEvnt,
'endEvnt': endEvnt,
'direction': swipedir.replace('swipe', ''),
'xAmount': xAmount,
'yAmount': yAmount,
'duration': endEvnt.time - startEvnt.time
};
hasSwiped = true;
$this.trigger('swipe', touchData).trigger(swipedir, touchData);
}
}
function touchEnd(e) {
$this = $(e.currentTarget);
var swipedir = "";
$this.data('callee3', touchEnd);
if (hasSwiped) {
// We need to check if the element to which the event was bound contains a data-xthreshold | data-vthreshold:
var ele_x_threshold = $this.data('xthreshold'), ele_y_threshold = $this.data('ythreshold'), h_threshold = (typeof ele_x_threshold !== 'undefined' && ele_x_threshold !== false && parseInt(ele_x_threshold)) ? parseInt(ele_x_threshold) : settings.swipe_h_threshold, v_threshold = (typeof ele_y_threshold !== 'undefined' && ele_y_threshold !== false && parseInt(ele_y_threshold)) ? parseInt(ele_y_threshold) : settings.swipe_v_threshold;
var origEvent = e.originalEvent;
var endEvnt = {
'position': {
'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX : e.pageX,
'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY : e.pageY
},
'offset': {
'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
},
'time': Date.now(),
'target': e.target
};
// Read event data into our endEvnt:
if (startEvnt.position.y > endEvnt.position.y && (startEvnt.position.y - endEvnt.position.y > v_threshold)) {
swipedir = 'swipeup';
}
if (startEvnt.position.x < endEvnt.position.x && (endEvnt.position.x - startEvnt.position.x > h_threshold)) {
swipedir = 'swiperight';
}
if (startEvnt.position.y < endEvnt.position.y && (endEvnt.position.y - startEvnt.position.y > v_threshold)) {
swipedir = 'swipedown';
}
if (startEvnt.position.x > endEvnt.position.x && (startEvnt.position.x - endEvnt.position.x > h_threshold)) {
swipedir = 'swipeleft';
}
// Calculate the swipe amount (normalized):
var xAmount = Math.abs(startEvnt.position.x - endEvnt.position.x), yAmount = Math.abs(startEvnt.position.y - endEvnt.position.y);
var touchData = {
'startEvnt': startEvnt,
'endEvnt': endEvnt,
'direction': swipedir.replace('swipe', ''),
'xAmount': xAmount,
'yAmount': yAmount,
'duration': endEvnt.time - startEvnt.time
};
$this.trigger('swipeend', touchData);
}
started = false;
hasSwiped = false;
}
$this.on(settings.startevent, touchStart);
$this.on(settings.moveevent, touchMove);
$this.on(settings.endevent, touchEnd);
},
remove: function () {
$(this).off(settings.startevent, $(this).data.callee1).off(settings.moveevent, $(this).data.callee2).off(settings.endevent, $(this).data.callee3);
if (
originalCoord.y < finalCoord.y &&
finalCoord.y - originalCoord.y > v_threshold
) {
swipedir = "swipedown";
}
};
// scrollstart Event (also handles scrollend):
$.event.special.scrollstart = {
setup: function () {
var thisObject = this, $this = $(thisObject), scrolling, timer;
function trigger(event, state) {
scrolling = state;
triggerCustomEvent(thisObject, scrolling ? 'scrollstart' : 'scrollend', event);
}
// iPhone triggers scroll after a small delay; use touchmove instead
$this.on(settings.scrollevent, function scrollFunc(event) {
$this.data('callee', scrollFunc);
if (!scrolling) {
trigger(event, true);
}
clearTimeout(timer);
timer = setTimeout(function () {
trigger(event, false);
}, 50);
});
},
remove: function () {
$(this).off(settings.scrollevent, $(this).data.callee);
if (
originalCoord.x > finalCoord.x &&
originalCoord.x - finalCoord.x > h_threshold
) {
swipedir = "swipeleft";
}
};
// This is the orientation change (largely borrowed from jQuery Mobile):
var win = $(window), get_orientation, last_orientation, initial_orientation_is_landscape, initial_orientation_is_default, portrait_map = {
'0': true,
'180': true
};
if (settings.orientation_support) {
var ww = window.innerWidth || win.width(), wh = window.innerHeight || win.height(), landscape_threshold = 50;
initial_orientation_is_landscape = ww > wh && (ww - wh) > landscape_threshold;
initial_orientation_is_default = portrait_map[window.orientation];
if ((initial_orientation_is_landscape && initial_orientation_is_default) || (!initial_orientation_is_landscape && !initial_orientation_is_default)) {
portrait_map = {
'-90': true,
'90': true
};
if (swipedir != undefined && started) {
originalCoord.x = 0;
originalCoord.y = 0;
finalCoord.x = 0;
finalCoord.y = 0;
started = false;
// Read event data into our endEvnt:
var origEvent = e.originalEvent;
var endEvnt = {
position: {
x: settings.touch_capable ? origEvent.touches[0].pageX : e.pageX,
y: settings.touch_capable ? origEvent.touches[0].pageY : e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
time: Date.now(),
target: e.target,
};
// Calculate the swipe amount (normalized):
var xAmount = Math.abs(startEvnt.position.x - endEvnt.position.x),
yAmount = Math.abs(startEvnt.position.y - endEvnt.position.y);
var touchData = {
startEvnt: startEvnt,
endEvnt: endEvnt,
direction: swipedir.replace("swipe", ""),
xAmount: xAmount,
yAmount: yAmount,
duration: endEvnt.time - startEvnt.time,
};
hasSwiped = true;
$this.trigger("swipe", touchData).trigger(swipedir, touchData);
}
}
$.event.special.orientationchange = {
setup: function () {
// If the event is supported natively, return false so that jQuery
// will on to the event using DOM methods.
if (settings.orientation_support) {
return false;
}
// Get the current orientation to avoid initial double-triggering.
last_orientation = get_orientation();
win.on('throttledresize', handler);
return true;
},
teardown: function () {
if (settings.orientation_support) {
return false;
}
win.off('throttledresize', handler);
return true;
},
add: function (handleObj) {
// Save a reference to the bound event handler.
var old_handler = handleObj.handler;
handleObj.handler = function (event) {
event.orientation = get_orientation();
return old_handler.apply(this, arguments);
};
}
function touchEnd(e) {
$this = $(e.currentTarget);
var swipedir = "";
$this.data("callee3", touchEnd);
if (hasSwiped) {
// We need to check if the element to which the event was bound contains a data-xthreshold | data-vthreshold:
var ele_x_threshold = $this.data("xthreshold"),
ele_y_threshold = $this.data("ythreshold"),
h_threshold =
typeof ele_x_threshold !== "undefined" &&
ele_x_threshold !== false &&
parseInt(ele_x_threshold)
? parseInt(ele_x_threshold)
: settings.swipe_h_threshold,
v_threshold =
typeof ele_y_threshold !== "undefined" &&
ele_y_threshold !== false &&
parseInt(ele_y_threshold)
? parseInt(ele_y_threshold)
: settings.swipe_v_threshold;
var origEvent = e.originalEvent;
var endEvnt = {
position: {
x: settings.touch_capable
? origEvent.changedTouches[0].pageX
: e.pageX,
y: settings.touch_capable
? origEvent.changedTouches[0].pageY
: e.pageY,
},
offset: {
x: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageX -
($this.offset() ? $this.offset().left : 0)
)
: Math.round(
e.pageX - ($this.offset() ? $this.offset().left : 0)
),
y: settings.touch_capable
? Math.round(
origEvent.changedTouches[0].pageY -
($this.offset() ? $this.offset().top : 0)
)
: Math.round(
e.pageY - ($this.offset() ? $this.offset().top : 0)
),
},
time: Date.now(),
target: e.target,
};
// Read event data into our endEvnt:
if (
startEvnt.position.y > endEvnt.position.y &&
startEvnt.position.y - endEvnt.position.y > v_threshold
) {
swipedir = "swipeup";
}
if (
startEvnt.position.x < endEvnt.position.x &&
endEvnt.position.x - startEvnt.position.x > h_threshold
) {
swipedir = "swiperight";
}
if (
startEvnt.position.y < endEvnt.position.y &&
endEvnt.position.y - startEvnt.position.y > v_threshold
) {
swipedir = "swipedown";
}
if (
startEvnt.position.x > endEvnt.position.x &&
startEvnt.position.x - endEvnt.position.x > h_threshold
) {
swipedir = "swipeleft";
}
// Calculate the swipe amount (normalized):
var xAmount = Math.abs(startEvnt.position.x - endEvnt.position.x),
yAmount = Math.abs(startEvnt.position.y - endEvnt.position.y);
var touchData = {
startEvnt: startEvnt,
endEvnt: endEvnt,
direction: swipedir.replace("swipe", ""),
xAmount: xAmount,
yAmount: yAmount,
duration: endEvnt.time - startEvnt.time,
};
$this.trigger("swipeend", touchData);
}
started = false;
hasSwiped = false;
}
$this.on(settings.startevent, touchStart);
$this.on(settings.moveevent, touchMove);
$this.on(settings.endevent, touchEnd);
},
remove: function () {
$(this)
.off(settings.startevent, $(this).data.callee1)
.off(settings.moveevent, $(this).data.callee2)
.off(settings.endevent, $(this).data.callee3);
},
};
// scrollstart Event (also handles scrollend):
$.event.special.scrollstart = {
setup: function () {
var thisObject = this,
$this = $(thisObject),
scrolling,
timer;
function trigger(event, state) {
scrolling = state;
triggerCustomEvent(
thisObject,
scrolling ? "scrollstart" : "scrollend",
event
);
}
// iPhone triggers scroll after a small delay; use touchmove instead
$this.on(settings.scrollevent, function scrollFunc(event) {
$this.data("callee", scrollFunc);
if (!scrolling) {
trigger(event, true);
}
clearTimeout(timer);
timer = setTimeout(function () {
trigger(event, false);
}, 50);
});
},
remove: function () {
$(this).off(settings.scrollevent, $(this).data.callee);
},
};
// This is the orientation change (largely borrowed from jQuery Mobile):
var win = $(window),
get_orientation,
last_orientation,
initial_orientation_is_landscape,
initial_orientation_is_default,
portrait_map = {
"0": true,
"180": true,
};
// If the event is not supported natively, this handler will be bound to
// the window resize event to simulate the orientationchange event.
function handler() {
// Get the current orientation.
var orientation = get_orientation();
if (orientation !== last_orientation) {
// The orientation has changed, so trigger the orientationchange event.
last_orientation = orientation;
win.trigger("orientationchange");
}
if (settings.orientation_support) {
var ww = window.innerWidth || win.width(),
wh = window.innerHeight || win.height(),
landscape_threshold = 50;
initial_orientation_is_landscape = ww > wh && ww - wh > landscape_threshold;
initial_orientation_is_default = portrait_map[window.orientation];
if (
(initial_orientation_is_landscape && initial_orientation_is_default) ||
(!initial_orientation_is_landscape && !initial_orientation_is_default)
) {
portrait_map = {
"-90": true,
"90": true,
};
}
$.event.special.orientationchange.orientation = get_orientation = function () {
var isPortrait = true, elem = document.documentElement;
if (settings.orientation_support) {
isPortrait = portrait_map[window.orientation];
}
$.event.special.orientationchange = {
setup: function () {
// If the event is supported natively, return false so that jQuery
// will on to the event using DOM methods.
if (settings.orientation_support) {
return false;
}
// Get the current orientation to avoid initial double-triggering.
last_orientation = get_orientation();
win.on("throttledresize", handler);
return true;
},
teardown: function () {
if (settings.orientation_support) {
return false;
}
win.off("throttledresize", handler);
return true;
},
add: function (handleObj) {
// Save a reference to the bound event handler.
var old_handler = handleObj.handler;
handleObj.handler = function (event) {
event.orientation = get_orientation();
return old_handler.apply(this, arguments);
};
},
};
// If the event is not supported natively, this handler will be bound to
// the window resize event to simulate the orientationchange event.
function handler() {
// Get the current orientation.
var orientation = get_orientation();
if (orientation !== last_orientation) {
// The orientation has changed, so trigger the orientationchange event.
last_orientation = orientation;
win.trigger("orientationchange");
}
}
$.event.special.orientationchange.orientation = get_orientation = function () {
var isPortrait = true,
elem = document.documentElement;
if (settings.orientation_support) {
isPortrait = portrait_map[window.orientation];
} else {
isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
}
return isPortrait ? "portrait" : "landscape";
};
// throttle Handler:
$.event.special.throttledresize = {
setup: function () {
$(this).on("resize", throttle_handler);
},
teardown: function () {
$(this).off("resize", throttle_handler);
},
};
var throttle = 250,
throttle_handler = function () {
curr = Date.now();
diff = curr - lastCall;
if (diff >= throttle) {
lastCall = curr;
$(this).trigger("throttledresize");
} else {
if (heldCall) {
window.clearTimeout(heldCall);
}
else {
isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
}
return isPortrait ? 'portrait' : 'landscape';
};
// throttle Handler:
$.event.special.throttledresize = {
// Promise a held call will still execute
heldCall = window.setTimeout(handler, throttle - diff);
}
},
lastCall = 0,
heldCall,
curr,
diff;
// Trigger a custom event:
function triggerCustomEvent(obj, eventType, event, touchData) {
var originalType = event.type;
event.type = eventType;
$.event.dispatch.call(obj, event, touchData);
event.type = originalType;
}
// Correctly on anything we've overloaded:
$.each(
{
scrollend: "scrollstart",
swipeup: "swipe",
swiperight: "swipe",
swipedown: "swipe",
swipeleft: "swipe",
swipeend: "swipe",
tap2: "tap",
taphold2: "taphold",
},
function (e, srcE) {
$.event.special[e] = {
setup: function () {
$(this).on('resize', throttle_handler);
$(this).on(srcE, $.noop);
},
teardown: function () {
$(this).off('resize', throttle_handler);
}
};
var throttle = 250, throttle_handler = function () {
curr = Date.now();
diff = curr - lastCall;
if (diff >= throttle) {
lastCall = curr;
$(this).trigger('throttledresize');
}
else {
if (heldCall) {
window.clearTimeout(heldCall);
}
// Promise a held call will still execute
heldCall = window.setTimeout(handler, throttle - diff);
}
}, lastCall = 0, heldCall, curr, diff;
// Trigger a custom event:
function triggerCustomEvent(obj, eventType, event, touchData) {
var originalType = event.type;
event.type = eventType;
$.event.dispatch.call(obj, event, touchData);
event.type = originalType;
};
}
// Correctly on anything we've overloaded:
$.each({
scrollend: 'scrollstart',
swipeup: 'swipe',
swiperight: 'swipe',
swipedown: 'swipe',
swipeleft: 'swipe',
swipeend: 'swipe',
tap2: 'tap',
taphold2: 'taphold'
}, function (e, srcE) {
$.event.special[e] = {
setup: function () {
$(this).on(srcE, $.noop);
}
};
});
return $;
);
return $;
};

@@ -1,1 +0,1 @@

export * from './jquery.module';
export * from "./jquery.module";
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./jquery.module"));
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -10,3 +12,5 @@ const jquery_1 = __importDefault(require("jquery"));

*/
const _jquery_touch_events_1 = __importDefault(require("./_jquery-touch-events"));
const _jquery_touch_events_1 = __importDefault(
require("./_jquery-touch-events")
);
// tslint:disable-next-line:variable-name

@@ -13,0 +17,0 @@ const JQuery = _jquery_touch_events_1.default(jquery_1.default);

{
"name": "@ribajs/extras",
"description": "Extras module for Riba.js",
"version": "1.9.0-alpha.0",
"version": "1.9.0-alpha.1",
"author": "Pascal Garber <pascal@artandcode.studio>",

@@ -31,28 +31,32 @@ "contributors": [],

"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.0",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-export-default-from": "^7.8.3",
"@babel/plugin-proposal-object-rest-spread": "^7.9.5",
"@babel/cli": "^7.10.4",
"@babel/core": "^7.10.4",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-proposal-export-default-from": "^7.10.4",
"@babel/plugin-proposal-object-rest-spread": "^7.10.4",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.9.5",
"@babel/preset-typescript": "^7.9.0",
"@babel/runtime-corejs3": "^7.9.2",
"@types/jest": "^25.2.1",
"@typescript-eslint/eslint-plugin": "^2.29.0",
"@typescript-eslint/parser": "^2.29.0",
"@babel/preset-env": "^7.10.4",
"@babel/preset-typescript": "^7.10.4",
"@babel/runtime-corejs3": "^7.10.4",
"@ribajs/eslint-config": "1.9.0-alpha.1",
"@types/jest": "^26.0.4",
"@typescript-eslint/eslint-plugin": "^3.6.0",
"@typescript-eslint/parser": "^3.6.0",
"babel-loader": "^8.1.0",
"babel-plugin-array-includes": "^2.0.3",
"core-js": "^3.6.5",
"eslint": "^6.8.0",
"jest": "^25.4.0",
"eslint": "^7.4.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"jest": "^26.1.0",
"jest-extended": "^0.11.5",
"ts-jest": "^25.4.0",
"typescript": "^3.8.3",
"webpack": "^5.0.0-beta.15",
"webpack-cli": "^3.3.11"
"prettier": "^2.0.5",
"ts-jest": "^26.1.1",
"typescript": "^3.9.6",
"webpack": "^5.0.0-beta.22",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"@ribajs/core": "1.9.0-alpha.0",
"@ribajs/utils": "1.9.0-alpha.0"
"@ribajs/core": "1.9.0-alpha.1",
"@ribajs/utils": "1.9.0-alpha.1"
},

@@ -59,0 +63,0 @@ "bugs": {

@@ -1,3 +0,3 @@

import { Binder } from '@ribajs/core';
import { debounce } from '@ribajs/utils/src/control';
import { Binder } from "@ribajs/core";
import { debounce } from "@ribajs/utils/src/control";

@@ -18,3 +18,3 @@ const DEFAULT_OFFSET = 10;

export const dataScrollPositionYBinder: Binder<string> = {
name: 'data-scroll-position-y',
name: "data-scroll-position-y",
customData: {},

@@ -26,10 +26,15 @@ bind() {

this.customData.onScroll = () => {
if (this.customData.elementSelector === 'window') {
if (this.customData.elementSelector === "window") {
const element = this.customData.watchScrollOnElement as Window;
if (element.scrollY <= 0 + this.customData.offsetTop) {
this.el.dataset.scrollPositionY = 'top';
} else if ((element.innerHeight + element.pageYOffset + this.customData.offsetBottom) >= document.body.offsetHeight) {
this.el.dataset.scrollPositionY = 'bottom';
this.el.dataset.scrollPositionY = "top";
} else if (
element.innerHeight +
element.pageYOffset +
this.customData.offsetBottom >=
document.body.offsetHeight
) {
this.el.dataset.scrollPositionY = "bottom";
} else {
this.el.dataset.scrollPositionY = 'scrolled';
this.el.dataset.scrollPositionY = "scrolled";
}

@@ -39,25 +44,32 @@ } else {

if (element.scrollTop <= 0 + this.customData.offsetTop) {
this.el.dataset.scrollPositionY = 'top';
} else if ((element.scrollTop + this.customData.offsetBottom) >= element.scrollHeight - element.clientHeight) {
this.el.dataset.scrollPositionY = 'bottom';
this.el.dataset.scrollPositionY = "top";
} else if (
element.scrollTop + this.customData.offsetBottom >=
element.scrollHeight - element.clientHeight
) {
this.el.dataset.scrollPositionY = "bottom";
} else {
this.el.dataset.scrollPositionY = 'scrolled';
this.el.dataset.scrollPositionY = "scrolled";
}
}
};
},
routine(el: HTMLElement, elementSelector = 'window') {
routine(el: HTMLElement, elementSelector = "window") {
// Remove old scroll event
if (this.customData.watchScrollOnElement) {
this.customData.watchScrollOnElement.removeEventListener('scroll', debounce.bind(this, this.customData.onScroll.bind(this)));
this.customData.watchScrollOnElement.removeEventListener(
"scroll",
debounce.bind(this, this.customData.onScroll.bind(this))
);
}
// Set new element to watch for the scroll event
if (elementSelector === 'window') {
if (elementSelector === "window") {
this.customData.watchScrollOnElement = window;
} else if (elementSelector === 'this') {
} else if (elementSelector === "this") {
this.customData.watchScrollOnElement = this.el;
} else {
this.customData.watchScrollOnElement = document.querySelector(elementSelector);
this.customData.watchScrollOnElement = document.querySelector(
elementSelector
);
}

@@ -68,7 +80,13 @@

// console.debug('addEventListener', this.customData.watchScrollOnElement);
this.customData.watchScrollOnElement.addEventListener('scroll', debounce(this.customData.onScroll.bind(this)), { passive: true });
this.customData.watchScrollOnElement.addEventListener(
"scroll",
debounce(this.customData.onScroll.bind(this)),
{ passive: true }
);
}
this.customData.offsetTop = Number(this.el.dataset.offsetTop) || DEFAULT_OFFSET;
this.customData.offsetBottom = Number(this.el.dataset.offsetBottom) || DEFAULT_OFFSET;
this.customData.offsetTop =
Number(this.el.dataset.offsetTop) || DEFAULT_OFFSET;
this.customData.offsetBottom =
Number(this.el.dataset.offsetBottom) || DEFAULT_OFFSET;
this.customData.elementSelector = elementSelector;

@@ -82,5 +100,8 @@

if (this.customData.watchScrollOnElement) {
this.customData.watchScrollOnElement.removeEventListener('scroll', debounce(this.customData.onScroll.bind(this)));
this.customData.watchScrollOnElement.removeEventListener(
"scroll",
debounce(this.customData.onScroll.bind(this))
);
}
},
};

@@ -1,5 +0,6 @@

export { dataScrollPositionYBinder } from './data-scroll-position-y.binder';
export { touchEventsBinder } from './touch-events.binder';
export { scrollEventsBinder } from './scroll-events.binder';
export { autoscrollBinder } from './scrollbar-autoscroll.binder';
export { scrollbarDraggableBinder } from './scrollbar-draggable.binder';
export { dataScrollPositionYBinder } from "./data-scroll-position-y.binder";
export { touchEventsBinder } from "./touch-events.binder";
export { scrollEventsBinder } from "./scroll-events.binder";
export { autoscrollBinder } from "./scrollbar-autoscroll.binder";
export { scrollbarDraggableBinder } from "./scrollbar-draggable.binder";
export { syncElementPropertyBinder } from "./sync-element-property.binder";

@@ -1,6 +0,6 @@

import { Binder } from '@ribajs/core';
import { ScrollEventsService } from '../services/touch-events/scroll-events.service';
import { Binder } from "@ribajs/core";
import { ScrollEventsService } from "../services/touch-events/scroll-events.service";
export const scrollEventsBinder: Binder<string> = {
name: 'scroll-events',
name: "scroll-events",
bind(el) {

@@ -18,4 +18,4 @@ if (!this.customData) {

routine() {
// nothing
// nothing
},
};

@@ -1,4 +0,4 @@

import { Binder } from '@ribajs/core';
import { isString } from '@ribajs/utils/src/type';
import { Autoscroll, AutoscrollOptions } from '../services/autoscroll.service';
import { Binder } from "@ribajs/core";
import { isString } from "@ribajs/utils/src/type";
import { Autoscroll, AutoscrollOptions } from "../services/autoscroll.service";

@@ -9,7 +9,7 @@ /**

export const autoscrollBinder: Binder<AutoscrollOptions> = {
name: 'autoscroll',
name: "autoscroll",
routine(el: HTMLElement, options: AutoscrollOptions) {
this.customData = this.customData || {};
if (options && options.width && isString(options.width)) {
if (options.width === '100vw') {
if (options.width === "100vw") {
el.style.width = options.width;

@@ -16,0 +16,0 @@ } else {

@@ -1,3 +0,3 @@

import { Binder } from '@ribajs/core';
import { Dragscroll, DragscrollOptions } from '../services/dragscroll.service';
import { Binder } from "@ribajs/core";
import { Dragscroll, DragscrollOptions } from "../services/dragscroll.service";

@@ -8,3 +8,3 @@ /**

export const scrollbarDraggableBinder: Binder<DragscrollOptions> = {
name: 'scrollbar-draggable',
name: "scrollbar-draggable",
routine(el: HTMLElement, options: DragscrollOptions) {

@@ -11,0 +11,0 @@ this.customData = this.customData || {};

@@ -1,6 +0,6 @@

import { Binder } from '@ribajs/core';
import { TouchEventsService } from '../services/touch-events/touch-events.service';
import { Binder } from "@ribajs/core";
import { TouchEventsService } from "../services/touch-events/touch-events.service";
export const touchEventsBinder: Binder<string> = {
name: 'touch-events',
name: "touch-events",
bind(el) {

@@ -18,4 +18,4 @@ if (!this.customData) {

routine() {
// nothing
// nothing
},
};

@@ -1,5 +0,5 @@

import { RibaModule } from '@ribajs/core';
import * as binders from './binders';
import { RibaModule } from "@ribajs/core";
import * as binders from "./binders";
// import * as formatters from './formatters';
import * as services from './services';
import * as services from "./services";
// import * as components from './components';

@@ -6,0 +6,0 @@

@@ -1,4 +0,4 @@

export * from './services';
export * from './binders';
export * from './types';
export * from './extras.module';
export * from "./services";
export * from "./binders";
export * from "./types";
export * from "./extras.module";

@@ -1,6 +0,6 @@

import { Utils as ExtraUtils } from './utils.service';
import { Gameloop } from './gameloop.service';
import { Utils as ExtraUtils } from "./utils.service";
import { Gameloop } from "./gameloop.service";
export interface AutoscrollOptions {
angle?: 'vertical' | 'horizontal';
angle?: "vertical" | "horizontal";
direction?: 1 | -1;

@@ -13,5 +13,4 @@ velocity?: number;

export class Autoscroll {
protected touchCapable = "ontouchstart" in window;
protected touchCapable = ('ontouchstart' in window);
protected direction = 1;

@@ -33,3 +32,3 @@

protected angle: 'horizontal' | 'vertical' = 'horizontal';
protected angle: "horizontal" | "vertical" = "horizontal";

@@ -46,3 +45,6 @@ protected pauseOnHover = true;

this.angle = this.options.angle || this.angle;
this.pauseOnHover = typeof(this.options.pauseOnHover) === 'boolean' ? this.options.pauseOnHover : this.pauseOnHover;
this.pauseOnHover =
typeof this.options.pauseOnHover === "boolean"
? this.options.pauseOnHover
: this.pauseOnHover;

@@ -52,3 +54,5 @@ this.limit = this.getLimit(this.el);

window.addEventListener('resize', this.onResize.bind(this), {passive: true});
window.addEventListener("resize", this.onResize.bind(this), {
passive: true,
});

@@ -63,26 +67,54 @@ if (this.direction === -1) {

this.el.addEventListener('mouseenter', this.onMouseIn.bind(this), {passive: true});
this.el.addEventListener('mouseover', this.onMouseIn.bind(this), {passive: true});
this.el.addEventListener('focusin', this.onMouseIn.bind(this), {passive: true});
this.el.addEventListener('touchstart', this.onMouseIn.bind(this), {passive: true});
this.el.addEventListener("mouseenter", this.onMouseIn.bind(this), {
passive: true,
});
this.el.addEventListener("mouseover", this.onMouseIn.bind(this), {
passive: true,
});
this.el.addEventListener("focusin", this.onMouseIn.bind(this), {
passive: true,
});
this.el.addEventListener("touchstart", this.onMouseIn.bind(this), {
passive: true,
});
this.el.addEventListener('mouseleave', this.onMouseOut.bind(this), {passive: true});
this.el.addEventListener('focusout', this.onMouseOut.bind(this), {passive: true});
this.el.addEventListener("mouseleave", this.onMouseOut.bind(this), {
passive: true,
});
this.el.addEventListener("focusout", this.onMouseOut.bind(this), {
passive: true,
});
this.el.addEventListener('mouseup', this.onMouseUp.bind(this), {passive: true});
this.el.addEventListener('touchend', this.onMouseUp.bind(this), {passive: true});
this.el.addEventListener("mouseup", this.onMouseUp.bind(this), {
passive: true,
});
this.el.addEventListener("touchend", this.onMouseUp.bind(this), {
passive: true,
});
if (this.touchCapable) {
this.el.addEventListener('scroll', this.onMouseUp.bind(this), {passive: true});
this.el.addEventListener('scrollend', this.onMouseUp.bind(this), {passive: true});
this.el.addEventListener("scroll", this.onMouseUp.bind(this), {
passive: true,
});
this.el.addEventListener("scrollend", this.onMouseUp.bind(this), {
passive: true,
});
// See ScrollEventsService for "scrollended" event
this.el.addEventListener('scrollended', this.onMouseUp.bind(this), {passive: true});
this.el.addEventListener("scrollended", this.onMouseUp.bind(this), {
passive: true,
});
} else {
this.el.addEventListener('scroll', this.onScroll.bind(this), {passive: true});
this.el.addEventListener('scrollend', this.onScroll.bind(this), {passive: true});
this.el.addEventListener('scrollended', this.onScroll.bind(this), {passive: true});
this.el.addEventListener("scroll", this.onScroll.bind(this), {
passive: true,
});
this.el.addEventListener("scrollend", this.onScroll.bind(this), {
passive: true,
});
this.el.addEventListener("scrollended", this.onScroll.bind(this), {
passive: true,
});
}
Gameloop.events.on('render', this.render.bind(this));
Gameloop.events.on('update', this.updateMove.bind(this));
Gameloop.events.on("render", this.render.bind(this));
Gameloop.events.on("update", this.updateMove.bind(this));

@@ -105,3 +137,3 @@ Gameloop.startLoop({ maxFPS: 60 });

public pause() {
this.el.style.scrollBehavior = '';
this.el.style.scrollBehavior = "";
this._pause = true;

@@ -122,3 +154,3 @@ }

// Disable smooth scrolling on autoscroll if set
this.el.style.scrollBehavior = 'auto';
this.el.style.scrollBehavior = "auto";
}, delay);

@@ -128,27 +160,27 @@ }

protected removeEventListeners() {
window.removeEventListener('resize', this.onResize.bind(this));
window.removeEventListener("resize", this.onResize.bind(this));
this.el.removeEventListener('mouseenter', this.onMouseIn.bind(this));
this.el.removeEventListener('mouseover', this.onMouseIn.bind(this));
this.el.removeEventListener('focusin', this.onMouseIn.bind(this));
this.el.removeEventListener('touchstart', this.onMouseIn.bind(this));
this.el.removeEventListener("mouseenter", this.onMouseIn.bind(this));
this.el.removeEventListener("mouseover", this.onMouseIn.bind(this));
this.el.removeEventListener("focusin", this.onMouseIn.bind(this));
this.el.removeEventListener("touchstart", this.onMouseIn.bind(this));
this.el.removeEventListener('mouseleave', this.onMouseOut.bind(this));
this.el.removeEventListener('focusout', this.onMouseOut.bind(this));
this.el.removeEventListener("mouseleave", this.onMouseOut.bind(this));
this.el.removeEventListener("focusout", this.onMouseOut.bind(this));
this.el.removeEventListener('mouseup', this.onMouseUp.bind(this));
this.el.removeEventListener('touchend', this.onMouseUp.bind(this));
this.el.removeEventListener("mouseup", this.onMouseUp.bind(this));
this.el.removeEventListener("touchend", this.onMouseUp.bind(this));
if (this.touchCapable) {
this.el.removeEventListener('scroll', this.onMouseUp.bind(this));
this.el.removeEventListener('scrollend', this.onMouseUp.bind(this));
this.el.removeEventListener('scrollended', this.onMouseUp.bind(this));
this.el.removeEventListener("scroll", this.onMouseUp.bind(this));
this.el.removeEventListener("scrollend", this.onMouseUp.bind(this));
this.el.removeEventListener("scrollended", this.onMouseUp.bind(this));
} else {
this.el.removeEventListener('scroll', this.onScroll.bind(this));
this.el.removeEventListener('scrollend', this.onScroll.bind(this));
this.el.removeEventListener('scrollended', this.onScroll.bind(this));
this.el.removeEventListener("scroll", this.onScroll.bind(this));
this.el.removeEventListener("scrollend", this.onScroll.bind(this));
this.el.removeEventListener("scrollended", this.onScroll.bind(this));
}
Gameloop.events.off('render', this.render.bind(this));
Gameloop.events.off('update', this.updateMove.bind(this));
Gameloop.events.off("render", this.render.bind(this));
Gameloop.events.off("update", this.updateMove.bind(this));
}

@@ -187,3 +219,5 @@

protected getPosition() {
return (this.angle === 'vertical' ? this.el.scrollTop : this.el.scrollLeft) || 0;
return (
(this.angle === "vertical" ? this.el.scrollTop : this.el.scrollLeft) || 0
);
}

@@ -196,3 +230,5 @@

protected getLimit(el: HTMLElement) {
return this.angle === 'vertical' ? ExtraUtils.getScrollPosition(el).maxY : ExtraUtils.getScrollPosition(el).maxX;
return this.angle === "vertical"
? ExtraUtils.getScrollPosition(el).maxY
: ExtraUtils.getScrollPosition(el).maxX;
}

@@ -210,3 +246,3 @@

* https://isaacsukin.com/news/2015/01/detailed-explanation-javascript-game-loops-and-timing
*
*
* Without this the scrollbar scrolls smooth, need to find out why.

@@ -228,3 +264,3 @@ */

this.lastMove = this.move;
const append = ((this.velocity * this.direction) * delta);
const append = this.velocity * this.direction * delta;
this.move += append;

@@ -243,3 +279,3 @@

protected scroll(move: number) {
if (this.angle === 'vertical') {
if (this.angle === "vertical") {
this.el.scrollTop = move;

@@ -250,3 +286,2 @@ } else {

}
}

@@ -1,2 +0,2 @@

import { Utils } from './utils.service';
import { Utils } from "./utils.service";

@@ -17,5 +17,8 @@ export interface DragscrollOptions {

protected pushed = false;
protected touchCapable = ('ontouchstart' in window);
protected touchCapable = "ontouchstart" in window;
constructor(el: HTMLElement, options: DragscrollOptions = { detectGlobalMove: true }) {
constructor(
el: HTMLElement,
options: DragscrollOptions = { detectGlobalMove: true }
) {
this.el = el;

@@ -29,20 +32,34 @@ this.options = options;

el.removeEventListener('mousedown', this.onMouseDown.bind(this), false);
el.addEventListener('mousedown', this.onMouseDown.bind(this), {passive: true});
el.removeEventListener("mousedown", this.onMouseDown.bind(this), false);
el.addEventListener("mousedown", this.onMouseDown.bind(this), {
passive: true,
});
window.addEventListener('resize', this.checkDraggable.bind(this));
window.addEventListener("resize", this.checkDraggable.bind(this));
// Use global move if your element does not use the full width / height
if (this.options.detectGlobalMove) {
window.removeEventListener('mouseup', this.onMouseUp.bind(this), false);
window.removeEventListener('mousemove', this.onMouseMove.bind(this), false);
window.removeEventListener("mouseup", this.onMouseUp.bind(this), false);
window.removeEventListener(
"mousemove",
this.onMouseMove.bind(this),
false
);
window.addEventListener('mouseup', this.onMouseUp.bind(this), {passive: true});
window.addEventListener('mousemove', this.onMouseMove.bind(this), {passive: true});
window.addEventListener("mouseup", this.onMouseUp.bind(this), {
passive: true,
});
window.addEventListener("mousemove", this.onMouseMove.bind(this), {
passive: true,
});
} else {
el.removeEventListener('mouseup', this.onMouseUp.bind(this), false);
el.removeEventListener('mousemove', this.onMouseMove.bind(this), false);
el.removeEventListener("mouseup", this.onMouseUp.bind(this), false);
el.removeEventListener("mousemove", this.onMouseMove.bind(this), false);
el.addEventListener('mouseup', this.onMouseUp.bind(this), {passive: true});
el.addEventListener('mousemove', this.onMouseMove.bind(this), {passive: true});
el.addEventListener("mouseup", this.onMouseUp.bind(this), {
passive: true,
});
el.addEventListener("mousemove", this.onMouseMove.bind(this), {
passive: true,
});
}

@@ -56,3 +73,3 @@

this.removeEventListeners();
this.el.classList.remove('draggable');
this.el.classList.remove("draggable");
}

@@ -62,10 +79,10 @@

if (Utils.isScrollable(this.el)) {
this.el.classList.add('draggable');
this.el.classList.add("draggable");
return true;
}
this.el.classList.remove('draggable');
this.el.classList.remove("draggable");
return false;
}
protected onMouseDown <EventListener>(e: MouseEvent) {
protected onMouseDown<EventListener>(e: MouseEvent) {
this.pushed = true;

@@ -76,12 +93,14 @@ this.lastClientX = e.clientX;

protected onMouseUp <EventListener>() {
protected onMouseUp<EventListener>() {
this.pushed = false;
}
protected onMouseMove <EventListener>(e: MouseEvent) {
protected onMouseMove<EventListener>(e: MouseEvent) {
let newScrollX = 0;
let newScrollY = 0;
if (this.pushed) {
this.el.scrollLeft -= newScrollX = (- this.lastClientX + (this.lastClientX = e.clientX));
this.el.scrollTop -= newScrollY = (- this.lastClientY + (this.lastClientY = e.clientY));
this.el.scrollLeft -= newScrollX =
-this.lastClientX + (this.lastClientX = e.clientX);
this.el.scrollTop -= newScrollY =
-this.lastClientY + (this.lastClientY = e.clientY);
if (this.el === document.body) {

@@ -98,8 +117,15 @@ if (document.documentElement) {

protected removeEventListeners() {
window.removeEventListener('resize', this.checkDraggable);
this.el.removeEventListener('mousedown', this.onMouseDown.bind(this), false);
this.el.removeEventListener('mouseup', this.onMouseUp.bind(this), false);
this.el.removeEventListener('mousemove', this.onMouseMove.bind(this), false);
window.removeEventListener("resize", this.checkDraggable);
this.el.removeEventListener(
"mousedown",
this.onMouseDown.bind(this),
false
);
this.el.removeEventListener("mouseup", this.onMouseUp.bind(this), false);
this.el.removeEventListener(
"mousemove",
this.onMouseMove.bind(this),
false
);
}
}

@@ -1,2 +0,2 @@

import { EventDispatcher } from '@ribajs/core';
import { EventDispatcher } from "@ribajs/core";

@@ -12,5 +12,4 @@ export interface GameloopOptions {

export class Gameloop {
public static events = new EventDispatcher("gameloop");
public static events = new EventDispatcher('gameloop');
public static maxFPS = 60;

@@ -23,5 +22,4 @@

public static startLoop(options: GameloopOptions = {}) {
this.setOptions(options);
this.setOptions(options);
if (!this.loopStarted) {

@@ -51,3 +49,4 @@ this.loopStarted = true;

protected static setOptions(options: GameloopOptions) {
this.maxFPS = typeof(options.maxFPS) === 'number' ? options.maxFPS : this.maxFPS;
this.maxFPS =
typeof options.maxFPS === "number" ? options.maxFPS : this.maxFPS;
}

@@ -60,5 +59,4 @@

protected static loop(timestamp: number) {
// Throttle the frame rate.
if (timestamp < this.lastFrameTimeMs + (1000 / this.maxFPS)) {
if (timestamp < this.lastFrameTimeMs + 1000 / this.maxFPS) {
this.frameID = requestAnimationFrame(this.loop.bind(this));

@@ -100,15 +98,15 @@ return;

protected static begin(timestamp: number, delta: number) {
this.events.trigger('begin', timestamp, delta);
this.events.trigger("begin", timestamp, delta);
}
protected static render(interp: number) {
this.events.trigger('render', interp);
this.events.trigger("render", interp);
}
protected static update(delta: number) {
this.events.trigger('update', delta);
this.events.trigger("update", delta);
}
protected static end(delta: number) {
this.events.trigger('end', delta);
this.events.trigger("end", delta);
}

@@ -123,3 +121,2 @@

}
}

@@ -1,7 +0,7 @@

export * from './autoscroll.service';
export * from './dragscroll.service';
export * from './fullscreen.service';
export * from './gameloop.service';
export * from './touch-events/scroll-events.service';
export * from './touch-events/touch-events.service';
export * from './utils.service';
export * from "./autoscroll.service";
export * from "./dragscroll.service";
export * from "./fullscreen.service";
export * from "./gameloop.service";
export * from "./touch-events/scroll-events.service";
export * from "./touch-events/touch-events.service";
export * from "./utils.service";
export abstract class BaseTouchEventsService {
protected touchCapable = ('ontouchstart' in window);
protected touchCapable = "ontouchstart" in window;
/** The element to trigger the events on */

@@ -12,3 +12,7 @@ protected el: HTMLElement;

protected triggerCustomEvent(eventName: string, originalEvent: Event, extraParameters: any = {}) {
protected triggerCustomEvent(
eventName: string,
originalEvent: Event,
extraParameters: any = {}
) {
extraParameters.originalEvent = originalEvent;

@@ -22,3 +26,2 @@ extraParameters.target = originalEvent.target;

}
}
// import { Utils as ExtraUtils } from '../utils.service';
import { BaseTouchEventsService } from './base-touch-events.service';
import { BaseTouchEventsService } from "./base-touch-events.service";
export class ScrollEventsService extends BaseTouchEventsService {
public isScrolling = false;
protected _scrollEvent: Array<'touchmove' | 'scroll' | 'scrollend'>;
protected _scrollEvent: Array<"touchmove" | "scroll" | "scrollend">;

@@ -19,3 +18,5 @@ /** The element to trigger the events on */

// Watch also native scrollend to not trigger scrollended before scrollend was triggered
this._scrollEvent = this.touchCapable ? ['touchmove', 'scrollend', 'scroll'] : ['scroll', 'scrollend'];
this._scrollEvent = this.touchCapable
? ["touchmove", "scrollend", "scroll"]
: ["scroll", "scrollend"];
this.addEventListeners();

@@ -34,3 +35,6 @@ }

for (const eventName of this._scrollEvent) {
this.el.removeEventListener<any>(eventName, this.onScrollEvent.bind(this));
this.el.removeEventListener<any>(
eventName,
this.onScrollEvent.bind(this)
);
}

@@ -41,3 +45,5 @@ }

for (const eventName of this._scrollEvent) {
this.el.addEventListener<any>(eventName, this.onScrollEvent.bind(this), {passive: true});
this.el.addEventListener<any>(eventName, this.onScrollEvent.bind(this), {
passive: true,
});
}

@@ -64,3 +70,3 @@ }

this.isScrolling = true;
this.triggerCustomEvent('scrollstart', event, {});
this.triggerCustomEvent("scrollstart", event, {});
}

@@ -75,3 +81,3 @@

this.scrollTimer = window.setTimeout(() => {
this.triggerCustomEvent('scrollended', event, {});
this.triggerCustomEvent("scrollended", event, {});
this.isScrolling = false;

@@ -78,0 +84,0 @@ }, 200);

@@ -1,6 +0,6 @@

import { Utils as ExtraUtils } from '../utils.service';
import { Position } from '../../types';
import { Utils as ExtraUtils } from "../utils.service";
import { Position } from "../../types";
// import { ScrollEventsService } from './scroll-events.service';
import { BaseTouchEventsService } from './base-touch-events.service';
import { BaseTouchEventsService } from "./base-touch-events.service";

@@ -44,6 +44,6 @@ /**

startevent: Array<'touchstart' | 'mousedown'>;
endevent: Array<'touchend' | 'touchcancel' | 'mouseup'>;
moveevent: Array<'touchmove' | 'mousemove'>;
tapevent: Array<'tap' | 'click'>;
startevent: Array<"touchstart" | "mousedown">;
endevent: Array<"touchend" | "touchcancel" | "mouseup">;
moveevent: Array<"touchmove" | "mousemove">;
tapevent: Array<"tap" | "click">;
}

@@ -70,3 +70,2 @@

export class TouchEventsService extends BaseTouchEventsService {
// GETTERS:

@@ -101,4 +100,6 @@

/** Set the X threshold of swipe events */
public set swipeThresholdX( threshold: number ) {
if ( typeof threshold !== 'number' ) { throw new Error('Threshold parameter must be a type of number'); }
public set swipeThresholdX(threshold: number) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
this.settings.swipeHThreshold = threshold;

@@ -108,4 +109,6 @@ }

/** Set the Y threshold of swipe events */
public set swipeThresholdY( threshold: number ) {
if ( typeof threshold !== 'number' ) { throw new Error('Threshold parameter must be a type of number'); }
public set swipeThresholdY(threshold: number) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
this.settings.swipeVThreshold = threshold;

@@ -115,4 +118,6 @@ }

/** Set the double tap interval */
public set doubleTapInt( interval: number ) {
if ( typeof interval !== 'number' ) { throw new Error('Interval parameter must be a type of number'); }
public set doubleTapInt(interval: number) {
if (typeof interval !== "number") {
throw new Error("Interval parameter must be a type of number");
}
this.settings.doubletapInterval = interval;

@@ -122,4 +127,6 @@ }

/** Set the taphold threshold */
public set tapHoldThreshold( threshold: number ) {
if ( typeof threshold !== 'number' ) { throw new Error('Threshold parameter must be a type of number'); }
public set tapHoldThreshold(threshold: number) {
if (typeof threshold !== "number") {
throw new Error("Threshold parameter must be a type of number");
}
this.settings.tapholdThreshold = threshold;

@@ -129,6 +136,7 @@ }

/** Set the pixel range for tapas */
public set tapRange( range: number ) {
if ( typeof range !== 'number' ) { throw new Error('Ranger parameter must be a type of number'); }
this.
settings.tapPixelRange = range;
public set tapRange(range: number) {
if (typeof range !== "number") {
throw new Error("Ranger parameter must be a type of number");
}
this.settings.tapPixelRange = range;
}

@@ -207,16 +215,19 @@

constructor(el: HTMLElement, settings: Settings = {
tapPixelRange: 5,
swipeHThreshold: 50,
swipeVThreshold: 50,
tapholdThreshold: 750,
doubletapInterval: 500,
shakeThreshold: 15,
touchCapable: ('ontouchstart' in window),
constructor(
el: HTMLElement,
settings: Settings = {
tapPixelRange: 5,
swipeHThreshold: 50,
swipeVThreshold: 50,
tapholdThreshold: 750,
doubletapInterval: 500,
shakeThreshold: 15,
touchCapable: "ontouchstart" in window,
startevent: ['touchstart'],
endevent: ['touchend'],
moveevent: ['touchmove'],
tapevent: ['tap'],
}) {
startevent: ["touchstart"],
endevent: ["touchend"],
moveevent: ["touchmove"],
tapevent: ["tap"],
}
) {
super(el);

@@ -226,6 +237,8 @@ this.el = el;

// Set settings by device type (if device is touch capable)
settings.startevent = settings.touchCapable ? ['touchstart'] : ['mousedown'];
settings.endevent = settings.touchCapable ? ['touchend'] : ['mouseup'];
settings.moveevent = settings.touchCapable ? ['touchmove'] : ['mousemove'];
settings.tapevent = settings.touchCapable ? ['tap'] : ['click'];
settings.startevent = settings.touchCapable
? ["touchstart"]
: ["mousedown"];
settings.endevent = settings.touchCapable ? ["touchend"] : ["mouseup"];
settings.moveevent = settings.touchCapable ? ["touchmove"] : ["mousemove"];
settings.tapevent = settings.touchCapable ? ["tap"] : ["click"];

@@ -259,15 +272,32 @@ this.settings = settings;

protected getSwipeDir(startPosition: Position, endPosition: Position, hThreshold: number = this.settings.swipeHThreshold, vThreshold: number = this.settings.swipeVThreshold) {
let swipeDir = '';
if (startPosition.y > endPosition.y && (startPosition.y - endPosition.y > vThreshold)) {
swipeDir = 'swipeup';
protected getSwipeDir(
startPosition: Position,
endPosition: Position,
hThreshold: number = this.settings.swipeHThreshold,
vThreshold: number = this.settings.swipeVThreshold
) {
let swipeDir = "";
if (
startPosition.y > endPosition.y &&
startPosition.y - endPosition.y > vThreshold
) {
swipeDir = "swipeup";
}
if (startPosition.x < endPosition.x && (endPosition.x - startPosition.x > hThreshold)) {
swipeDir = 'swiperight';
if (
startPosition.x < endPosition.x &&
endPosition.x - startPosition.x > hThreshold
) {
swipeDir = "swiperight";
}
if (startPosition.y < endPosition.y && (endPosition.y - startPosition.y > vThreshold)) {
swipeDir = 'swipedown';
if (
startPosition.y < endPosition.y &&
endPosition.y - startPosition.y > vThreshold
) {
swipeDir = "swipedown";
}
if (startPosition.x > endPosition.x && (startPosition.x - endPosition.x > hThreshold)) {
swipeDir = 'swipeleft';
if (
startPosition.x > endPosition.x &&
startPosition.x - endPosition.x > hThreshold
) {
swipeDir = "swipeleft";
}

@@ -277,3 +307,7 @@ return swipeDir;

protected getPostion(event: TouchEvent | MouseEvent, type: TouchType = TouchType.DEFAULT, index = 0): Position {
protected getPostion(
event: TouchEvent | MouseEvent,
type: TouchType = TouchType.DEFAULT,
index = 0
): Position {
let touchesTypes: TouchList;

@@ -292,4 +326,8 @@ switch (type) {

const position = {
x: (this.settings.touchCapable) ? touchesTypes[index].pageX : (event as MouseEvent).pageX,
y: (this.settings.touchCapable) ? touchesTypes[index].pageY : (event as MouseEvent).pageY,
x: this.settings.touchCapable
? touchesTypes[index].pageX
: (event as MouseEvent).pageX,
y: this.settings.touchCapable
? touchesTypes[index].pageY
: (event as MouseEvent).pageY,
};

@@ -299,3 +337,7 @@ return position;

protected getOffset(event: TouchEvent | MouseEvent, type: TouchType = TouchType.DEFAULT, index = 0): Offset {
protected getOffset(
event: TouchEvent | MouseEvent,
type: TouchType = TouchType.DEFAULT,
index = 0
): Offset {
const boundingClientRect = this.el.getBoundingClientRect();

@@ -315,4 +357,20 @@ let touchesTypes: TouchList;

const offset = {
x: (this.settings.touchCapable) ? Math.round(touchesTypes[index].pageX - (boundingClientRect ? boundingClientRect.left : 0)) : Math.round((event as any as MouseEvent).pageX - (boundingClientRect ? boundingClientRect.left : 0)),
y: (this.settings.touchCapable) ? Math.round(touchesTypes[index].pageY - (boundingClientRect ? boundingClientRect.top : 0)) : Math.round((event as any as MouseEvent).pageY - (boundingClientRect ? boundingClientRect.top : 0)),
x: this.settings.touchCapable
? Math.round(
touchesTypes[index].pageX -
(boundingClientRect ? boundingClientRect.left : 0)
)
: Math.round(
((event as any) as MouseEvent).pageX -
(boundingClientRect ? boundingClientRect.left : 0)
),
y: this.settings.touchCapable
? Math.round(
touchesTypes[index].pageY -
(boundingClientRect ? boundingClientRect.top : 0)
)
: Math.round(
((event as any) as MouseEvent).pageY -
(boundingClientRect ? boundingClientRect.top : 0)
),
};

@@ -322,3 +380,8 @@ return offset;

protected getTouchData(event: TouchEvent | MouseEvent, withIndex = false, positionType = TouchType.DEFAULT, offsetType = TouchType.CHANGED): TouchData {
protected getTouchData(
event: TouchEvent | MouseEvent,
withIndex = false,
positionType = TouchType.DEFAULT,
offsetType = TouchType.CHANGED
): TouchData {
const touchData: TouchData = {

@@ -330,3 +393,5 @@ position: this.getPostion(event, positionType),

if (withIndex) {
touchData.index = ExtraUtils.getElementIndex(event.target as Element | null);
touchData.index = ExtraUtils.getElementIndex(
event.target as Element | null
);
}

@@ -338,9 +403,15 @@ return touchData;

for (const eventName of this.settings.startevent) {
this.el.addEventListener<any>(eventName, this.onStartEvent.bind(this), {passive: true});
this.el.addEventListener<any>(eventName, this.onStartEvent.bind(this), {
passive: true,
});
}
for (const eventName of this.settings.moveevent) {
this.el.addEventListener<any>(eventName, this.onMoveEvent.bind(this), {passive: true});
this.el.addEventListener<any>(eventName, this.onMoveEvent.bind(this), {
passive: true,
});
}
for (const eventName of this.settings.endevent) {
this.el.addEventListener<any>(eventName, this.onEndEvent.bind(this), {passive: true});
this.el.addEventListener<any>(eventName, this.onEndEvent.bind(this), {
passive: true,
});
}

@@ -365,3 +436,8 @@ }

if (!this.firstTap) {
this.firstTap = this.getTouchData(event, true, TouchType.DEFAULT, TouchType.CHANGED);
this.firstTap = this.getTouchData(
event,
true,
TouchType.DEFAULT,
TouchType.CHANGED
);
}

@@ -376,3 +452,8 @@

this.finalCoord = this.getPostion(event, TouchType.TARGET);
this.startEvnt = this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED);
this.startEvnt = this.getTouchData(
event,
false,
TouchType.DEFAULT,
TouchType.CHANGED
);

@@ -414,3 +495,7 @@ this.tapstart(event);

protected tapstart(event: TouchEvent | MouseEvent) {
this.triggerCustomEvent('tapstart', event, this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED));
this.triggerCustomEvent(
"tapstart",
event,
this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED)
);
return true;

@@ -421,3 +506,7 @@ }

protected tapmove(event: TouchEvent | MouseEvent) {
this.triggerCustomEvent('tapmove', event, this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED));
this.triggerCustomEvent(
"tapmove",
event,
this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED)
);
return true;

@@ -428,3 +517,7 @@ }

protected tapend(event: TouchEvent | MouseEvent) {
this.triggerCustomEvent('tapend', event, this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED));
this.triggerCustomEvent(
"tapend",
event,
this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED)
);
return true;

@@ -443,17 +536,8 @@ }

if (
(
this.startPosition.x === this.endPosition.x
&&
this.startPosition.y === this.endPosition.y
)
||
(
diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange
)
(this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange)
) {

@@ -463,3 +547,5 @@ this.tapheld = true;

const duration = endTime - this.startTime;
const touchesLength: number = ((event as TouchEvent).targetTouches) ? (event as TouchEvent).targetTouches.length : 1;
const touchesLength: number = (event as TouchEvent).targetTouches
? (event as TouchEvent).targetTouches.length
: 1;
const touches = new Array<Partial<TouchData>>();

@@ -471,8 +557,26 @@

position: {
x: (this.settings.touchCapable) ? (event as TouchEvent).changedTouches[i].pageX : (event as MouseEvent).pageX,
y: (this.settings.touchCapable) ? (event as TouchEvent).changedTouches[i].pageY : (event as MouseEvent).pageY,
x: this.settings.touchCapable
? (event as TouchEvent).changedTouches[i].pageX
: (event as MouseEvent).pageX,
y: this.settings.touchCapable
? (event as TouchEvent).changedTouches[i].pageY
: (event as MouseEvent).pageY,
},
offset: {
x: (this.settings.touchCapable) ? Math.round((event as TouchEvent).changedTouches[i].pageX - (elOffset ? elOffset.left : 0)) : Math.round((event as MouseEvent).pageX - (elOffset ? elOffset.left : 0)),
y: (this.settings.touchCapable) ? Math.round((event as TouchEvent).changedTouches[i].pageY - (elOffset ? elOffset.top : 0)) : Math.round((event as MouseEvent).pageY - (elOffset ? elOffset.top : 0)),
x: this.settings.touchCapable
? Math.round(
(event as TouchEvent).changedTouches[i].pageX -
(elOffset ? elOffset.left : 0)
)
: Math.round(
(event as MouseEvent).pageX - (elOffset ? elOffset.left : 0)
),
y: this.settings.touchCapable
? Math.round(
(event as TouchEvent).changedTouches[i].pageY -
(elOffset ? elOffset.top : 0)
)
: Math.round(
(event as MouseEvent).pageY - (elOffset ? elOffset.top : 0)
),
},

@@ -483,3 +587,4 @@ };

}
const eventName = (touchesLength > 1) ? 'taphold' + touchesLength : 'taphold';
const eventName =
touchesLength > 1 ? "taphold" + touchesLength : "taphold";

@@ -494,3 +599,2 @@ const touchData = {

}
}, this.settings.tapholdThreshold);

@@ -511,15 +615,16 @@

if (
delta < this.settings.doubletapInterval
&&
delta > 100
&&
(
this.firstTap
&&
ExtraUtils.getElementIndex(event.target as Element | null) === this.firstTap.index
)
delta < this.settings.doubletapInterval &&
delta > 100 &&
this.firstTap &&
ExtraUtils.getElementIndex(event.target as Element | null) ===
this.firstTap.index
) {
this.doubletapped = true;
window.clearTimeout(this.tapTimer);
const lastTap: TouchData = this.getTouchData(event, true, TouchType.CHANGED, TouchType.CHANGED);
const lastTap: TouchData = this.getTouchData(
event,
true,
TouchType.CHANGED,
TouchType.CHANGED
);
const touchData = {

@@ -531,3 +636,3 @@ firstTap: this.firstTap,

if (!this.cooling) {
this.triggerCustomEvent('doubletap', event, touchData);
this.triggerCustomEvent("doubletap", event, touchData);
this.firstTap = null;

@@ -540,6 +645,10 @@ }

} else {
this.actionTimer = window.setTimeout(() => {
this.firstTap = null;
window.clearTimeout(this.actionTimer);
}, this.settings.doubletapInterval, [event]);
this.actionTimer = window.setTimeout(
() => {
this.firstTap = null;
window.clearTimeout(this.actionTimer);
},
this.settings.doubletapInterval,
[event]
);
}

@@ -560,33 +669,21 @@ this.lastTouch = now;

if (
!this.doubletapped
&&
!this.tapheld
&&
(
(
(
this.startPosition.x === this.endPosition.x
)
&&
(
this.startPosition.y === this.endPosition.y
)
)
||
(
diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange
)
)
!this.doubletapped &&
!this.tapheld &&
((this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange))
) {
const touchData: TouchData = this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED);
const touchData: TouchData = this.getTouchData(
event,
false,
TouchType.CHANGED,
TouchType.CHANGED
);
// Was it a taphold?
if ((touchData.time - this.startTime) < this.settings.tapholdThreshold) {
this.triggerCustomEvent('singletap', event, touchData);
if (touchData.time - this.startTime < this.settings.tapholdThreshold) {
this.triggerCustomEvent("singletap", event, touchData);
}

@@ -605,27 +702,14 @@ }

if (
this.tapStarted
&&
(
(Date.now() - this.startTime) < this.settings.tapholdThreshold
)
&&
(
(
this.startPosition.x === this.endPosition.x
&&
this.startPosition.y === this.endPosition.y
)
||
(
diffPosition.x >= -this.settings.tapPixelRange
&&
diffPosition.x <= this.settings.tapPixelRange
&&
diffPosition.y >= -this.settings.tapPixelRange
&&
diffPosition.y <= this.settings.tapPixelRange
)
)
this.tapStarted &&
Date.now() - this.startTime < this.settings.tapholdThreshold &&
((this.startPosition.x === this.endPosition.x &&
this.startPosition.y === this.endPosition.y) ||
(diffPosition.x >= -this.settings.tapPixelRange &&
diffPosition.x <= this.settings.tapPixelRange &&
diffPosition.y >= -this.settings.tapPixelRange &&
diffPosition.y <= this.settings.tapPixelRange))
) {
const touchesLength: number = ((event as TouchEvent).targetTouches) ? (event as TouchEvent).targetTouches.length : 1;
const touchesLength: number = (event as TouchEvent).targetTouches
? (event as TouchEvent).targetTouches.length
: 1;
const touches = new Array<Partial<TouchData>>();

@@ -637,8 +721,26 @@

position: {
x: (this.settings.touchCapable) ? (event as TouchEvent).changedTouches[i].pageX : (event as MouseEvent).pageX,
y: (this.settings.touchCapable) ? (event as TouchEvent).changedTouches[i].pageY : (event as MouseEvent).pageY,
x: this.settings.touchCapable
? (event as TouchEvent).changedTouches[i].pageX
: (event as MouseEvent).pageX,
y: this.settings.touchCapable
? (event as TouchEvent).changedTouches[i].pageY
: (event as MouseEvent).pageY,
},
offset: {
x: (this.settings.touchCapable) ? Math.round((event as TouchEvent).changedTouches[i].pageX - (elOffset ? elOffset.left : 0)) : Math.round((event as MouseEvent).pageX - (elOffset ? elOffset.left : 0)),
y: (this.settings.touchCapable) ? Math.round((event as TouchEvent).changedTouches[i].pageY - (elOffset ? elOffset.top : 0)) : Math.round((event as MouseEvent).pageY - (elOffset ? elOffset.top : 0)),
x: this.settings.touchCapable
? Math.round(
(event as TouchEvent).changedTouches[i].pageX -
(elOffset ? elOffset.left : 0)
)
: Math.round(
(event as MouseEvent).pageX - (elOffset ? elOffset.left : 0)
),
y: this.settings.touchCapable
? Math.round(
(event as TouchEvent).changedTouches[i].pageY -
(elOffset ? elOffset.top : 0)
)
: Math.round(
(event as MouseEvent).pageY - (elOffset ? elOffset.top : 0)
),
},

@@ -655,3 +757,3 @@ };

const eventName = (touchesLength > 1) ? 'tap' + touchesLength : 'tap';
const eventName = touchesLength > 1 ? "tap" + touchesLength : "tap";
this.triggerCustomEvent(eventName, event, touchData);

@@ -677,3 +779,8 @@ }

const endEvnt: TouchData = this.getTouchData(event, false, TouchType.DEFAULT, TouchType.CHANGED);
const endEvnt: TouchData = this.getTouchData(
event,
false,
TouchType.DEFAULT,
TouchType.CHANGED
);

@@ -687,3 +794,3 @@ // Calculate the swipe amount (normalized):

endEvnt,
direction: swipeDir.replace('swipe', ''),
direction: swipeDir.replace("swipe", ""),
xAmount,

@@ -694,3 +801,3 @@ yAmount,

this.hasSwiped = true;
this.triggerCustomEvent('swipe', event, touchData);
this.triggerCustomEvent("swipe", event, touchData);
this.triggerCustomEvent(swipeDir, event, touchData);

@@ -705,5 +812,13 @@ }

protected swipeend(event: TouchEvent | MouseEvent) {
const endEvnt: TouchData = this.getTouchData(event, false, TouchType.CHANGED, TouchType.CHANGED);
const endEvnt: TouchData = this.getTouchData(
event,
false,
TouchType.CHANGED,
TouchType.CHANGED
);
if (this.hasSwiped && this.startEvnt) {
const swipeDir = this.getSwipeDir(this.startEvnt.position, endEvnt.position);
const swipeDir = this.getSwipeDir(
this.startEvnt.position,
endEvnt.position
);

@@ -717,3 +832,3 @@ // Calculate the swipe amount (normalized):

endEvnt,
direction: swipeDir.replace('swipe', ''),
direction: swipeDir.replace("swipe", ""),
xAmount,

@@ -723,7 +838,5 @@ yAmount,

};
this.triggerCustomEvent('swipeend', event, touchData);
this.triggerCustomEvent("swipeend", event, touchData);
}
}
}

@@ -1,5 +0,4 @@

import { ScrollPosition } from '../types/scroll-position';
import { ScrollPosition } from "../types/scroll-position";
export class Utils {
// easings methods, see https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/

@@ -23,3 +22,3 @@

public static easeOutCubic(t: number) {
return (--t) * t * t + 1;
return --t * t * t + 1;
}

@@ -33,6 +32,6 @@ public static easeInOutCubic(t: number) {

public static easeOutQuart(t: number) {
return 1 - (--t) * t * t * t;
return 1 - --t * t * t * t;
}
public static easeInOutQuart(t: number) {
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
}

@@ -43,6 +42,6 @@ public static easeInQuint(t: number) {

public static easeOutQuint(t: number) {
return 1 + (--t) * t * t * t * t;
return 1 + --t * t * t * t * t;
}
public static easeInOutQuint(t: number) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t;
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
}

@@ -49,0 +48,0 @@

@@ -1,2 +0,2 @@

export * from './position';
export * from './scroll-position';
export * from "./position";
export * from "./scroll-position";

@@ -1,2 +0,2 @@

import { Position } from './position';
import { Position } from "./position";

@@ -3,0 +3,0 @@ export interface ScrollPosition extends Position {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc