UNPKG

hold-event

Version:

Provides key hold-start, holding, hold-end and other events.

199 lines (191 loc) 7 kB
/*! * hold-event * https://github.com/yomotsu/hold-event * (c) 2020 @yomotsu * Released under the MIT License. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.holdEvent = {})); })(this, (function (exports) { 'use strict'; exports.HOLD_EVENT_TYPE = void 0; (function (HOLD_EVENT_TYPE) { HOLD_EVENT_TYPE["HOLD_START"] = "holdStart"; HOLD_EVENT_TYPE["HOLD_END"] = "holdEnd"; HOLD_EVENT_TYPE["HOLDING"] = "holding"; })(exports.HOLD_EVENT_TYPE || (exports.HOLD_EVENT_TYPE = {})); class EventDispatcher { constructor() { this._listeners = {}; } addEventListener(type, listener) { const listeners = this._listeners; if (listeners[type] === undefined) listeners[type] = []; if (listeners[type].indexOf(listener) === -1) listeners[type].push(listener); } removeEventListener(type, listener) { const listeners = this._listeners; const listenerArray = listeners[type]; if (listenerArray !== undefined) { const index = listenerArray.indexOf(listener); if (index !== -1) listenerArray.splice(index, 1); } } dispatchEvent(event) { const listeners = this._listeners; const listenerArray = listeners[event.type]; if (listenerArray !== undefined) { event.target = this; const array = listenerArray.slice(0); for (let i = 0, l = array.length; i < l; i++) { array[i].call(this, event); } } } } class Hold extends EventDispatcher { constructor(holdIntervalDelay) { super(); this._enabled = true; this._holding = false; this._intervalId = -1; this._deltaTime = 0; this._elapsedTime = 0; this._lastTime = 0; this._holdStart = (event) => { if (!this._enabled) return; if (this._holding) return; this._deltaTime = 0; this._elapsedTime = 0; this._lastTime = performance.now(); this.dispatchEvent({ type: exports.HOLD_EVENT_TYPE.HOLD_START, deltaTime: this._deltaTime, elapsedTime: this._elapsedTime, originalEvent: event, }); this._holding = true; const cb = () => { this._intervalId = !!this.holdIntervalDelay ? window.setTimeout(cb, this.holdIntervalDelay) : window.requestAnimationFrame(cb); const now = performance.now(); this._deltaTime = now - this._lastTime; this._elapsedTime += this._deltaTime; this._lastTime = performance.now(); this.dispatchEvent({ type: exports.HOLD_EVENT_TYPE.HOLDING, deltaTime: this._deltaTime, elapsedTime: this._elapsedTime, originalEvent: event }); }; this._intervalId = !!this.holdIntervalDelay ? window.setTimeout(cb, this.holdIntervalDelay) : window.requestAnimationFrame(cb); }; this._holdEnd = (event) => { if (!this._enabled) return; if (!this._holding) return; const now = performance.now(); this._deltaTime = now - this._lastTime; this._elapsedTime += this._deltaTime; this._lastTime = performance.now(); this.dispatchEvent({ type: exports.HOLD_EVENT_TYPE.HOLD_END, deltaTime: this._deltaTime, elapsedTime: this._elapsedTime, originalEvent: event, }); window.clearTimeout(this._intervalId); window.cancelAnimationFrame(this._intervalId); this._holding = false; }; this.holdIntervalDelay = holdIntervalDelay; } get enabled() { return this._enabled; } set enabled(enabled) { if (this._enabled === enabled) return; this._enabled = enabled; if (!this._enabled) this._holdEnd(); } get holding() { return this._holding; } } class ElementHold extends Hold { constructor(element, holdIntervalDelay) { super(holdIntervalDelay); this._activePointerIds = []; const holdStart = (event) => { this._holdStart(event); }; const holdEnd = (event) => { this._activePointerIds.length = 0; this._holdEnd(event); }; const onPointerDown = (event) => { this._activePointerIds.push(event.pointerId); holdStart(event); }; const onPointerUp = (event) => { const pointerIndex = this._activePointerIds.indexOf(event.pointerId); if (pointerIndex === -1) return; this._activePointerIds.splice(pointerIndex, 1); if (this._activePointerIds.length === 0) holdEnd(event); }; element.addEventListener('pointerdown', onPointerDown); document.addEventListener('pointerup', onPointerUp); window.addEventListener('blur', holdEnd); } } class KeyboardKeyHold extends Hold { constructor(code, holdIntervalDelay) { if (typeof code !== 'string') { console.error('KeyboardKeyHold: the first argument has to be a KeyboardEvent.code string.'); return; } super(holdIntervalDelay); this._holdStart = this._holdStart.bind(this); this._holdEnd = this._holdEnd.bind(this); const onKeydown = (event) => { if (isInputEvent(event)) return; if (event.code !== code) return; this._holdStart(event); }; const onKeyup = (event) => { if (event.code !== code) return; this._holdEnd(event); }; document.addEventListener('keydown', onKeydown); document.addEventListener('keyup', onKeyup); window.addEventListener('blur', this._holdEnd); } } function isInputEvent(event) { const target = event.target; return (target.tagName === 'INPUT' || target.tagName === 'SELECT' || target.tagName === 'TEXTAREA' || target.isContentEditable); } exports.ElementHold = ElementHold; exports.KeyboardKeyHold = KeyboardKeyHold; }));