countdown-8.x-1.8/js/lib/countdown.min.js
js/lib/countdown.min.js
/*!
* CountdownTimer v1.0.0-alpha2 — Drupal Countdown module.
* https://drupal.org/project/countdown
* (c) 2025 Mahyar SBT
* @license GPL-2.0-or-later
*/
!function(t,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():t.CountdownTimer=e()}("undefined"!=typeof self?self:this,(function(){"use strict";const t=1e3,e=6e4,s=36e5,i=864e5,n={milliseconds:1,hundredths:10,tenths:100,seconds:1e3,minutes:6e4},r={ISO:/^\d{4}-\d{2}-\d{2}[T\s]/,RELATIVE:/(?:(\d+)d)?(?:\s*(\d+)h)?(?:\s*(\d+)m)?(?:\s*(\d+)s)?/,TIME:/^(?:(\d{1,2}):)?(?:(\d{1,2}):)?(\d{1,2})(?:[:.](\d{1,3}))?$/,NUMERIC:/^\d+$/},o=t=>t<10?"0"+t:String(t),a=(n,o=Date.now())=>{if(null==n)return 0;if("number"==typeof n)return n>31536e6?Math.max(0,n-o):Math.abs(n);if(n instanceof Date)return Math.max(0,n.getTime()-o);if("object"==typeof n){const{days:r=0,hours:o=0,minutes:a=0,seconds:h=0,milliseconds:c=0}=n;return Math.abs(r*i+o*s+a*e+h*t+c)}if("string"==typeof n){let h;if(r.TIME.test(n)){h=n.match(r.TIME);const[,i,o,a,c]=h,m=i&&o?parseInt(i,10):0,u=i&&o?parseInt(o,10):i?parseInt(i,10):0,l=parseInt(a,10),f=c?parseInt(c.padEnd(3,"0"),10):0;return m*s+u*e+l*t+f}if((h=n.match(r.RELATIVE))&&(h[1]||h[2]||h[3]||h[4]))return parseInt(h[1]||0,10)*i+parseInt(h[2]||0,10)*s+parseInt(h[3]||0,10)*e+parseInt(h[4]||0,10)*t;if(r.ISO.test(n)){const t=Date.parse(n);return isNaN(t)?0:Math.max(0,t-o)}if(r.NUMERIC.test(n))return a(parseInt(n,10),o)}return 0};class h{constructor(){this._listeners=new Map}on(t,e){const s=this._listeners.get(t)||[];return s.push(e),this._listeners.set(t,s),()=>this.off(t,e)}off(t,e){const s=this._listeners.get(t);if(s){const t=s.indexOf(e);t>-1&&s.splice(t,1)}}emit(t,e){const s=this._listeners.get(t);s&&s.slice().forEach((t=>t(e)))}clear(){this._listeners.clear()}}class c{constructor(t={}){this.config={selector:null,mode:"countdown",start:"00:10",target:"00:00",duration:null,precision:"seconds",driftCompensation:!0,offset:0,autoStart:!0,benchmark:!1,debug:!1,onStart:null,onPause:null,onResume:null,onStop:null,onReset:null,onComplete:null,onTick:null,...t},this.config.effect&&!this.config.style&&(this.config.style=this.config.effect),n[this.config.precision]||(this.config.precision="seconds"),this._events=new h,this._element=null,this._benchmarkData=null,this._styleRenderer=null,this._resetState(),this.config.selector&&(this._element=document.querySelector(this.config.selector)),this._parseConfig(),this.config.benchmark&&(this._benchmarkData={ticks:0,totalDrift:0,maxDrift:0}),this.config.autoStart&&this.start()}_resetState(){this.state={running:!1,paused:!1,startTime:0,pauseTime:0,targetMs:0,timerId:null,nextTick:0}}_parseConfig(){const{mode:e,start:s,target:i,duration:n}=this.config;"countdown"===e?this.state.targetMs=null!==n?n*t:a(s):i&&"00:00"!==i?this.state.targetMs=a(i):null!==n&&(this.state.targetMs=n*t),this.config.offset&&(this.state.targetMs+=this.config.offset)}start(t){if(this.state.running)return this;t&&(Object.assign(this.config,t),this._parseConfig()),this.config.selector&&!this._element&&(this._element=document.querySelector(this.config.selector));const e=Date.now(),s=n[this.config.precision];if(this.state.paused){const t=e-this.state.pauseTime;this.state.startTime+=t,this.state.nextTick+=t}else{const t=e-e%s;this.state.startTime=t,this.state.nextTick=t}return this.state.running=!0,this.state.paused=!1,this._tick(),this.config.driftCompensation?this._scheduleTick(s):this.state.timerId=setInterval((()=>this._tick()),s),this._emit("start",this.getTime()),this.config.onStart&&this.config.onStart(this.getTime(),this),this}_scheduleTick(t){const e=()=>{if(!this.state.running)return;const s=Date.now()-this.state.nextTick;if(this._benchmarkData&&(this._benchmarkData.totalDrift+=Math.abs(s),this._benchmarkData.maxDrift=Math.max(this._benchmarkData.maxDrift,Math.abs(s)),this._benchmarkData.ticks++),s>t){const e=Math.floor(s/t);for(let t=0;t<e;t++)this._tick();this.state.nextTick+=(e+1)*t}else this._tick(),this.state.nextTick+=t;this.state.timerId=setTimeout(e,Math.max(0,this.state.nextTick-Date.now()))};this.state.timerId=setTimeout(e,Math.max(0,this.state.nextTick-Date.now()))}_tick(){this.config.selector&&!this._element&&(this._element=document.querySelector(this.config.selector));const t=this.getElapsed(),e="countdown"===this.config.mode?Math.max(0,this.state.targetMs-t):t;if(this._checkCompletion(e))return;const s=this.formatTime(),i=this.getTime();if(this.config.style&&c._styles&&c._styles.has(this.config.style)){if(!this._styleRenderer){const t=c._styles.get(this.config.style);this._styleRenderer=new t(this,this.config.styleOptions)}this._element&&this._styleRenderer.render&&this._styleRenderer.render(s,i)}else this._element&&(this._element.textContent=s);this.config.debug&&console.log("[CountdownTimer]",s,i),this._emit("tick",i),this.config.onTick&&this.config.onTick(i,this)}_checkCompletion(t){return!!("countdown"===this.config.mode?t<=0&&this.state.running:this.state.targetMs>0&&t>=this.state.targetMs&&this.state.running)&&(this.stop(),this._emit("complete",this.getTime()),this.config.onComplete&&this.config.onComplete(this.getTime(),this),!0)}stop(){return this.state.running||this.state.paused?(this._clearTimer(),this._resetState(),this._emit("stop",this.getTime()),this.config.onStop&&this.config.onStop(this.getTime(),this),this):this}pause(){return!this.state.running||this.state.paused||(this._clearTimer(),this.state.running=!1,this.state.paused=!0,this.state.pauseTime=Date.now(),this._emit("pause",this.getTime()),this.config.onPause&&this.config.onPause(this.getTime(),this)),this}resume(){if(!this.state.paused)return this;const t=Date.now(),e=n[this.config.precision],s=t-this.state.pauseTime;return this.state.startTime+=s,this.state.nextTick=t+e,this.state.running=!0,this.state.paused=!1,this.config.driftCompensation?this._scheduleTick(e):this.state.timerId=setInterval((()=>this._tick()),e),this._emit("resume",this.getTime()),this.config.onResume&&this.config.onResume(this.getTime(),this),this}reset(t){const e=this.state.running;return this.stop(),t&&(Object.assign(this.config,t),this._parseConfig()),this._emit("reset",this.getTime()),this.config.onReset&&this.config.onReset(this.getTime(),this),(e||this.config.autoStart)&&this.start(),this}formatTime(t){t||(t=c.TEMPLATES[this.config.precision]||"HH:MM:SS");const e=this.getTime();if(!e)return"00:00:00";const s=this._getFormattedValues(e);return t.replace(c.FORMAT_REGEX,(t=>s[t]||t))}_getFormattedValues(t){return{DD:o(t.days||0),D:String(t.days||0),HH:o(t.hours||0),H:String(t.hours||0),MM:o(t.minutes||0),M:String(t.minutes||0),SS:o(t.seconds||0),S:String(t.seconds||0),mmm:(e=t.milliseconds||0,e<10?"00"+e:e<100?"0"+e:String(e)),mm:o(t.hundredths||0),m:String(t.tenths||0)};var e}getElapsed(){if(!this.state.startTime)return 0;const t=this.state.paused?this.state.pauseTime:Date.now();return Math.max(0,t-this.state.startTime)}getRemaining(){return"countdown"===this.config.mode?Math.max(0,this.state.targetMs-this.getElapsed()):0}getTime(){return(n=>{const r=Math.abs(n),o=Math.floor(r/i),a=Math.floor(r%i/s),h=Math.floor(r%s/e),c=Math.floor(r%e/t),m=Math.floor(r%t);return{days:o,hours:a,minutes:h,seconds:c,milliseconds:m,tenths:Math.floor(m/100),hundredths:Math.floor(m/10)}})("countdown"===this.config.mode?this.getRemaining():this.getElapsed())}isRunning(){return this.state.running}isPaused(){return this.state.paused}on(t,e){return this._events.on(t,e)}off(t,e){return this._events.off(t,e),this}getBenchmark(){if(!this._benchmarkData)return null;const{ticks:t,totalDrift:e,maxDrift:s}=this._benchmarkData;return{ticks:t,avgDrift:t>0?e/t:0,maxDrift:s,accuracy:t>0?100*(1-e/t/n[this.config.precision]):100}}_emit(t,e){this._events.emit(t,e)}_clearTimer(){this.state.timerId&&(this.config.driftCompensation?clearTimeout(this.state.timerId):clearInterval(this.state.timerId),this.state.timerId=null)}destroy(){this._styleRenderer&&"function"==typeof this._styleRenderer.destroy&&(this._styleRenderer.destroy(),this._styleRenderer=null),this.stop(),this._events.clear(),this.config=null,this.state=null,this._events=null,this._element=null,this._benchmarkData=null}static async testAccuracy(t=60){return new Promise((e=>{const s=1e3*t,i=new c({mode:"countup",precision:"milliseconds",benchmark:!0,autoStart:!0});setTimeout((()=>{i.stop();const t=i.getElapsed(),n=Math.abs(t-s);e({expected:s,actual:t,drift:n,accuracy:(100-n/s*100).toFixed(4)+"%",benchmark:i.getBenchmark()})}),s)}))}}return c.FORMAT_REGEX=/DD|D|HH|H|MM|M|SS|S|mmm|mm|m/g,c.TEMPLATES={milliseconds:"HH:MM:SS.mmm",hundredths:"HH:MM:SS.mm",tenths:"HH:MM:SS.m",seconds:"HH:MM:SS",minutes:"HH:MM"},c._styles=new Map,c.registerStyle=function(t,e){t&&"function"==typeof e&&c._styles.set(t,e)},c.registerEffect=c.registerStyle,c}));
