MTGRandom/core/jquery.longpress.min.js
2026-07-29 19:51:07 -04:00

9 lines
5.2 KiB
JavaScript

/**
* Copyright (c) 2025
* @Version : 2.0.1
* @Author : https://salarizadi.ir
* @Repository : https://github.com/salarizadi/longpress
* @Description: A jQuery plugin for handling long press events on both mobile and desktop devices.
*/
!function(e){"use strict";const o=new WeakMap;e.fn.longPress=function(i){const n=e.extend({holdTime:500,maxHoldTime:null,holdClass:"holding",onHoldStart:()=>{},onHold:()=>{},onHoldEnd:()=>{},onMaxHold:()=>{},onClick:()=>{},progressBar:!1,progressBarClass:"button-hold-progress",throttleProgress:16,touchMoveThreshold:3,preventContextMenu:!0,enableSwipe:!1,onSwipe:()=>{}},i);return this.each((function(){const i=e(this),t={isHolding:!1,holdStartTime:null,initialTouch:null,initialMouse:null,animationFrameId:null,originalStyles:{},$progressBar:null,cleanup:null,promiseChain:Promise.resolve(),lastProgress:0,holdTimeout:null,rightClickHolding:!1,isSwiping:!1,isScrolling:!1,touchStartTime:null,hasMoved:!1,clickHandled:!1};["user-select","-webkit-user-select","touch-action","position"].forEach((e=>{t.originalStyles[e]=i.css(e)})),n.progressBar&&(t.$progressBar=e("<div>",{class:n.progressBarClass,css:{width:"0%",height:"3px",position:"absolute",bottom:"0",left:"0",backgroundColor:"#4CAF50",transition:"width 0.05s linear"}}),"static"===i.css("position")&&i.css("position","relative"),i.append(t.$progressBar)),i.css({"user-select":"none","-webkit-user-select":"none","touch-action":"pan-x pan-y"});const s=async(e,...o)=>{try{await t.promiseChain,t.promiseChain=t.promiseChain.then((()=>Promise.resolve(e.call(i,...o)))).catch((e=>console.error("LongPress callback error:",e)))}catch(e){console.error("LongPress callback execution error:",e)}},l=()=>{if(!t.isHolding)return;const e=Date.now()-t.holdStartTime,o=n.maxHoldTime?Math.min(e/n.maxHoldTime*100,100):Math.min(e/100*2,100);if(Math.abs(o-t.lastProgress)>=.5&&(t.lastProgress=o,t.$progressBar&&t.$progressBar.css("width",`${o}%`),s(n.onHold,null,o,e)),n.maxHoldTime&&e>=n.maxHoldTime)return s(n.onMaxHold),void a();t.animationFrameId=requestAnimationFrame(l)},a=async function(e){if(!t.isHolding)return;clearTimeout(t.holdTimeout);const o=Date.now()-t.holdStartTime,l=t.touchStartTime?Date.now()-t.touchStartTime:0;t.isHolding=!1;const a=t.hasMoved,r=t.isScrolling;cancelAnimationFrame(t.animationFrameId),i.removeClass(n.holdClass),t.$progressBar&&t.$progressBar.css("width","0%"),!t.clickHandled&&!a&&!r&&l<200?(t.clickHandled=!0,await s(n.onClick,e,o)):o>=n.holdTime&&(!r||!n.enableSwipe&&o>=n.holdTime)&&(e&&e.cancelable&&e.preventDefault(),await s(n.onHoldEnd,e,o)),t.initialTouch=null,t.initialMouse=null,t.rightClickHolding=!1,t.isSwiping=!1,t.hasMoved=!1,t.isScrolling=!1,setTimeout((()=>{t.isHolding||(t.touchStartTime=null,t.clickHandled=!1)}),500)},r=function(e,o=!1){if(t.isHolding)return;t.holdTimeout&&clearTimeout(t.holdTimeout);const a=e.touches?e.touches[0]:e;if("mousedown"===e.type||o){if(t.touchStartTime&&Date.now()-t.touchStartTime<500)return;t.initialMouse={x:a.pageX,y:a.pageY},t.rightClickHolding=o,t.touchStartTime=Date.now()}else t.initialTouch={x:a.pageX,y:a.pageY},t.touchStartTime=Date.now();t.isHolding=!0,t.holdStartTime=Date.now(),t.lastProgress=0,t.hasMoved=!1,t.isScrolling=!1,t.clickHandled=!1,i.addClass(n.holdClass),t.holdTimeout=setTimeout((async()=>{t.isHolding&&!t.hasMoved&&(e&&e.cancelable&&e.preventDefault(),await s(n.onHoldStart,e),t.isHolding&&l())}),n.holdTime),o&&e.preventDefault()};i.on("mousedown.longpress",r).on("touchstart.longpress",r).on("mousemove.longpress",(function(e){if(!t.isHolding||!t.initialMouse)return;const o=n.touchMoveThreshold,i=e.pageX-t.initialMouse.x,r=e.pageY-t.initialMouse.y,c=Math.abs(i),d=Math.abs(r),u=Date.now()-t.holdStartTime;if((c>o||d>o)&&(t.hasMoved=!0),n.enableSwipe&&t.hasMoved){let l="";c>d?l=i>0?"right":"left":d>o&&(l=r>0?"down":"up"),l&&(t.isSwiping=!0,s(n.onSwipe,e,l,{deltaX:i,deltaY:r}),a(e))}n.enableSwipe&&t.hasMoved||!(u>=n.holdTime)||(l(),(c>3*o||d>3*o)&&a(e))})).on("touchmove.longpress",(function(e){if(!t.isHolding||!t.initialTouch)return;const o=n.touchMoveThreshold,i=e.touches[0],r=i.pageX-t.initialTouch.x,c=i.pageY-t.initialTouch.y,d=Math.abs(r),u=Math.abs(c),h=Date.now()-t.holdStartTime;if((d>o||u>o)&&(t.hasMoved=!0),n.enableSwipe&&t.hasMoved){let i="";if(d>u)return i=r>0?"right":"left",t.isSwiping=!0,s(n.onSwipe,e,i,{deltaX:r,deltaY:c}),void a(e);if(u>o)return i=c>0?"down":"up",u>1.5*o?(t.isSwiping=!0,t.isScrolling=!1,s(n.onSwipe,e,i,{deltaX:r,deltaY:c}),void a(e)):void(t.isScrolling=!0)}else if(u>d&&u>o)return void(t.isScrolling=!0);!n.enableSwipe&&h>=n.holdTime&&l()})).on("contextmenu.longpress",(function(e){return n.preventContextMenu&&e.cancelable&&(e.preventDefault(),e.stopPropagation()),t.isHolding||r(e,!0),!1}));const c=e(document);c.on("mouseup.longpress touchend.longpress touchcancel.longpress",(e=>{t.isHolding&&a(e)})).on("mouseleave.longpress",(o=>{!t.isHolding||null!==o.relatedTarget&&e.contains(document.documentElement,o.relatedTarget)||a(o)})).on("visibilitychange.longpress",(()=>{document.hidden&&a()})),t.cleanup=()=>{a(),clearTimeout(t.holdTimeout),i.off(".longpress").css(t.originalStyles),t.$progressBar&&t.$progressBar.remove(),c.off(".longpress"),o.delete(i[0])},o.set(i[0],t)}))},e.fn.longPressDestroy=function(){return this.each((function(){const e=o.get(this);e&&e.cleanup&&e.cleanup()}))}}(jQuery);