import dom from '../scripts/dom'; import { Events } from 'jellyfin-apiclient'; function getTouches(e) { return e.changedTouches || e.targetTouches || e.touches; } class TouchHelper { constructor(elem, options) { options = options || {}; let touchTarget; let touchStartX; let touchStartY; let lastDeltaX; let lastDeltaY; let thresholdYMet; const self = this; const swipeXThreshold = options.swipeXThreshold || 50; const swipeYThreshold = options.swipeYThreshold || 50; const swipeXMaxY = 30; const excludeTagNames = options.ignoreTagNames || []; const touchStart = function (e) { const touch = getTouches(e)[0]; touchTarget = null; touchStartX = 0; touchStartY = 0; lastDeltaX = null; lastDeltaY = null; thresholdYMet = false; if (touch) { const currentTouchTarget = touch.target; if (dom.parentWithTag(currentTouchTarget, excludeTagNames)) { return; } touchTarget = currentTouchTarget; touchStartX = touch.clientX; touchStartY = touch.clientY; } }; const touchEnd = function (e) { const isTouchMove = e.type === 'touchmove'; if (touchTarget) { const touch = getTouches(e)[0]; let deltaX; let deltaY; let clientX; let clientY; if (touch) { clientX = touch.clientX || 0; clientY = touch.clientY || 0; deltaX = clientX - (touchStartX || 0); deltaY = clientY - (touchStartY || 0); } else { deltaX = 0; deltaY = 0; } const currentDeltaX = lastDeltaX == null ? deltaX : (deltaX - lastDeltaX); const currentDeltaY = lastDeltaY == null ? deltaY : (deltaY - lastDeltaY); lastDeltaX = deltaX; lastDeltaY = deltaY; if (deltaX > swipeXThreshold && Math.abs(deltaY) < swipeXMaxY) { Events.trigger(self, 'swiperight', [touchTarget]); } else if (deltaX < (0 - swipeXThreshold) && Math.abs(deltaY) < swipeXMaxY) { Events.trigger(self, 'swipeleft', [touchTarget]); } else if ((deltaY < (0 - swipeYThreshold) || thresholdYMet) && Math.abs(deltaX) < swipeXMaxY) { thresholdYMet = true; Events.trigger(self, 'swipeup', [touchTarget, { deltaY: deltaY, deltaX: deltaX, clientX: clientX, clientY: clientY, currentDeltaX: currentDeltaX, currentDeltaY: currentDeltaY }]); } else if ((deltaY > swipeYThreshold || thresholdYMet) && Math.abs(deltaX) < swipeXMaxY) { thresholdYMet = true; Events.trigger(self, 'swipedown', [touchTarget, { deltaY: deltaY, deltaX: deltaX, clientX: clientX, clientY: clientY, currentDeltaX: currentDeltaX, currentDeltaY: currentDeltaY }]); } if (isTouchMove && options.preventDefaultOnMove) { e.preventDefault(); } } if (!isTouchMove) { touchTarget = null; touchStartX = 0; touchStartY = 0; lastDeltaX = null; lastDeltaY = null; thresholdYMet = false; } }; this.touchStart = touchStart; this.touchEnd = touchEnd; dom.addEventListener(elem, 'touchstart', touchStart, { passive: true }); if (options.triggerOnMove) { dom.addEventListener(elem, 'touchmove', touchEnd, { passive: !options.preventDefaultOnMove }); } dom.addEventListener(elem, 'touchend', touchEnd, { passive: true }); dom.addEventListener(elem, 'touchcancel', touchEnd, { passive: true }); } destroy() { const elem = this.elem; if (elem) { const touchStart = this.touchStart; const touchEnd = this.touchEnd; dom.removeEventListener(elem, 'touchstart', touchStart, { passive: true }); dom.removeEventListener(elem, 'touchmove', touchEnd, { passive: true }); dom.removeEventListener(elem, 'touchend', touchEnd, { passive: true }); dom.removeEventListener(elem, 'touchcancel', touchEnd, { passive: true }); } this.touchStart = null; this.touchEnd = null; this.elem = null; } } export default TouchHelper;