@pageblock/attributes-countdown
Version:
Create customizable countdown timers for Webflow with no-code.
19 lines (18 loc) • 8.44 kB
JavaScript
/**
* @pageblock/attributes-countdown v0.1.8
* Create customizable countdown timers for Webflow with no-code.
*
* @author PageBlock
* @license MIT
* @preserve
*/
/**
* @pageblock/attributes-countdown v0.1.8
* Create customizable countdown timers for Webflow with no-code.
*
* @author PageBlock
* @license MIT
* @preserve
*/
!function(t){"use strict";const e="pb_countdown_",n={COMPLETE:"countdown:complete",PAUSE:"countdown:pause",RESUME:"countdown:resume"};class o{constructor(t={}){this.debug=t.debug||!1,this.countdowns=new Map,this.init()}log(...t){this.debug&&console.log("[Countdown]",...t)}validateConfig(t){const e=[];return t.storageKey&&!t.id&&e.push("ID is required when storage is enabled"),t.expiresDaily&&(t.messageTarget||t.storageKey)&&e.push("Daily countdown cannot use message target or storage features"),t.endDate&&isNaN(new Date(t.endDate).getTime())&&e.push("Invalid end date format"),e}init(){document.querySelectorAll("[data-pb-countdown]").forEach((t=>this.setupCountdown(t)))}setupCountdown(t){try{if(!t)return void console.error("Invalid countdown element");if(t.hasAttribute("data-pb-countdown-freeze")&&t.setAttribute("data-pb-countdown-store",""),t.hasAttribute("data-pb-countdown-daily")&&(t.hasAttribute("data-pb-countdown-message-target")||t.hasAttribute("data-pb-countdown-store"))&&(console.warn("Daily countdown cannot use message target or storage features"),t.removeAttribute("data-pb-countdown-message-target"),t.removeAttribute("data-pb-countdown-store")),(t.hasAttribute("data-pb-countdown-store")||t.hasAttribute("data-pb-countdown-freeze"))&&!t.hasAttribute("data-pb-countdown-id"))return void console.error("Storage/freeze enabled but no ID provided. Add data-pb-countdown-id attribute.");const e=this.parseConfig(t),n=new Date;let o=this.getEndTime(e,n);if(!o||isNaN(o.getTime()))return void console.error("Invalid end time configuration. Please check your date format or minutes value.");if(e.showDate){const o=new Date(e.showDate);if(isNaN(o.getTime()))return void console.error("Invalid show date configuration. Please use a valid date format.");n<o&&(t.style.display="none")}const a={element:t,config:e,endTime:o,timer:null,displayElement:t.querySelector("[data-pb-countdown-display]"),unitElements:{days:t.querySelector('[data-pb-countdown-unit="days"] [data-pb-countdown-display]'),hours:t.querySelector('[data-pb-countdown-unit="hours"] [data-pb-countdown-display]'),minutes:t.querySelector('[data-pb-countdown-unit="minutes"] [data-pb-countdown-display]'),seconds:t.querySelector('[data-pb-countdown-unit="seconds"] [data-pb-countdown-display]')}};if(!a.displayElement&&!Object.values(a.unitElements).some((t=>t)))return void console.error("No display elements found");this.countdowns.set(t,a),this.startCountdown(a)}catch(t){console.error("Error setting up countdown:",t)}}parseConfig(t){return{settings:JSON.parse(t.getAttribute("data-pb-countdown-settings")||"{}"),endDate:t.getAttribute("data-pb-countdown-end"),startDate:t.getAttribute("data-pb-countdown-start"),showDate:t.getAttribute("data-pb-countdown-show"),hideOnComplete:null!==t.getAttribute("data-pb-countdown-hide"),showTarget:t.getAttribute("data-pb-countdown-show-target"),messageTarget:t.getAttribute("data-pb-countdown-message-target"),expiresDaily:null!==t.getAttribute("data-pb-countdown-daily"),minutes:parseInt(t.getAttribute("data-pb-countdown-minutes"))||null,storageKey:null!==t.getAttribute("data-pb-countdown-store"),id:t.getAttribute("data-pb-countdown-id"),freeze:null!==t.getAttribute("data-pb-countdown-freeze")}}getEndTime(t,e){let n;return t.storageKey&&t.id&&(n=this.getStoredEndTime(t.id,e)),n&&!isNaN(n.getTime())||(n=this.calculateEndTime(t,e),t.storageKey&&t.id&&n&&this.storeEndTime(t.id,e,n)),n}getStoredEndTime(t,n){try{const o=localStorage.getItem(`${e}${t}`);if(o){const a=JSON.parse(o),s=new Date(a.endTime);return n>=s?(localStorage.removeItem(`${e}${t}`),null):s}}catch(t){console.warn("Error reading stored countdown data:",t)}return null}storeEndTime(t,n,o){try{localStorage.setItem(`${e}${t}`,JSON.stringify({startTime:n.toISOString(),endTime:o.toISOString()}))}catch(t){console.warn("Error storing countdown data:",t)}}calculateEndTime(t,e){if(t.minutes)return new Date(e.getTime()+6e4*t.minutes);if(t.expiresDaily){const t=new Date(e);return t.setHours(23,59,59,999),t}if(t.endDate){const e=new Date(t.endDate);return isNaN(e.getTime())?null:e}return new Date(e.getTime()+864e5)}startCountdown(t){const e=()=>{const e=new Date,n=t.endTime-e;if(n<0)return void this.handleCountdownEnd(t);const o=this.calculateTimeUnits(n);this.updateDisplay(t,o),t.config.freeze&&t.config.storageKey&&t.config.id&&this.storeFrozenState(t.config.id,o)};if(t.config.freeze&&t.config.storageKey&&t.config.id){const e=this.getFrozenState(t.config.id);if(e){const n=24*e.days*60*60+60*e.hours*60+60*e.minutes+e.seconds;t.endTime=new Date((new Date).getTime()+1e3*n),this.updateDisplay(t,e)}}e(),t.timer=setInterval(e,1e3)}calculateTimeUnits(t){return{days:Math.floor(t/864e5),hours:Math.floor(t%864e5/36e5),minutes:Math.floor(t%36e5/6e4),seconds:Math.floor(t%6e4/1e3)}}updateDisplay(t,e){const{days:n,hours:o,minutes:a,seconds:s}=e;if(Object.values(t.unitElements).some((t=>t)))t.unitElements.days&&(t.unitElements.days.textContent=n.toString().padStart(2,"0")),t.unitElements.hours&&(t.unitElements.hours.textContent=o.toString().padStart(2,"0")),t.unitElements.minutes&&(t.unitElements.minutes.textContent=a.toString().padStart(2,"0")),t.unitElements.seconds&&(t.unitElements.seconds.textContent=s.toString().padStart(2,"0"));else if(t.displayElement){let e="";n>0&&(e=`${n.toString().padStart(2,"0")}:`),e+=`${o.toString().padStart(2,"0")}:${a.toString().padStart(2,"0")}:${s.toString().padStart(2,"0")}`,t.displayElement.textContent=e}else console.warn("No display elements found for countdown. Please add either a [data-pb-countdown-display] element or individual unit elements.")}handleCountdownEnd(t){if(clearInterval(t.timer),t.config.hideOnComplete&&(t.element.style.display="none"),t.config.showTarget){const e=document.querySelector(t.config.showTarget);e&&(e.style.display="block",t.element.style.display="none")}if(t.config.messageTarget&&!t.config.expiresDaily){const e=document.querySelector(t.config.messageTarget);e&&(e.style.display="block")}if(t.config.storageKey&&t.config.id)try{t.config.freeze||localStorage.removeItem(`${e}${t.config.id}`)}catch(t){this.log("Error clearing stored countdown:",t)}t.config.expiresDaily?(t.endTime=new Date,t.endTime.setHours(23,59,59,999),this.startCountdown(t)):this.countdowns.delete(t.element),t.element.dispatchEvent(new CustomEvent("countdown:complete",{detail:{countdown:t}}))}pauseCountdown(t){const e=Array.from(this.countdowns.values()).find((e=>e.config.id===t));e&&(clearInterval(e.timer),e.pausedAt=new Date,this.log(`Paused countdown: ${t}`),e.element.dispatchEvent(new CustomEvent(n.PAUSE,{detail:{countdown:e}})))}resumeCountdown(t){const e=Array.from(this.countdowns.values()).find((e=>e.config.id===t));if(e&&e.pausedAt){const o=new Date-e.pausedAt;e.endTime=new Date(e.endTime.getTime()+o),delete e.pausedAt,this.startCountdown(e),this.log(`Resumed countdown: ${t}`),e.element.dispatchEvent(new CustomEvent(n.RESUME,{detail:{countdown:e}}))}}storeFrozenState(t,n){try{localStorage.setItem(`${e}${t}_frozen`,JSON.stringify(n))}catch(t){console.warn("Error storing frozen state:",t)}}getFrozenState(t){try{const n=localStorage.getItem(`${e}${t}_frozen`);if(n)return JSON.parse(n)}catch(t){console.warn("Error reading frozen state:",t)}return null}destroy(){this.countdowns.forEach((t=>{if(clearInterval(t.timer),t.config.storageKey&&t.config.id)try{t.config.freeze||localStorage.removeItem(`${e}${t.config.id}`)}catch(t){this.log("Error clearing stored countdown:",t)}t.element.removeEventListener(n.COMPLETE,null),t.element.removeEventListener(n.PAUSE,null),t.element.removeEventListener(n.RESUME,null),t.displayElement=null,t.unitElements=null})),this.countdowns.clear(),this.log("All countdowns destroyed")}}if("undefined"!=typeof window){window.PageBlockUtils||(window.PageBlockUtils={}),window.PageBlockUtils.Countdown=o;const t=()=>{window.PageBlockUtils.countdownInstance||(window.PageBlockUtils.countdownInstance=new o({debug:!1}))};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",t):t()}t.Countdown=o}(this.PageBlockUtils=this.PageBlockUtils||{});
//# sourceMappingURL=index.js.map