PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.14
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.14
3.3.2 3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 All 157 releases
notificationx / assets / public / js / nx-countdown.js

nx-countdown.js in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.2.14, at assets/public/js/nx-countdown.js

154 lines 6.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * NotificationX Countdown Timer — Elementor Widget
3 *
4 * Hooks into elementorFrontend so the timer runs in both the live
5 * editor preview and on the public-facing frontend.
6 */
7
8 /* global elementorFrontend, localStorage */
9 (function ($) {
10 'use strict';
11
12 // Track active intervals so re-renders in the editor don't leak timers
13 var activeIntervals = {};
14
15 var NXCountdown = function NXCountdown($scope) {
16 var $wrapper = $scope.find('.nx-countdown-wrapper').eq(0);
17 if (!$wrapper.length) return;
18
19 var widgetId = $wrapper.data('countdown-id') || '';
20 var countdownType= $wrapper.data('countdown-type') || 'due_date';
21 var expireType = $wrapper.data('expire-type') || 'none';
22 var expireTitle = $wrapper.data('expiry-title') || '';
23 var expireText = $wrapper.data('expiry-text') || '';
24 var redirectUrl = $wrapper.data('redirect-url') || '';
25 var evergreenTime= parseInt($wrapper.data('evergreen-time') || 0, 10); // seconds
26 var recurring = $wrapper.data('evergreen-recurring');
27 var recurringStop= $wrapper.data('evergreen-recurring-stop') || '';
28
29 var $list = $scope.find('#nx-countdown-' + widgetId);
30 var $daysEl = $list.find('[data-days]');
31 var $hoursEl = $list.find('[data-hours]');
32 var $minutesEl = $list.find('[data-minutes]');
33 var $secondsEl = $list.find('[data-seconds]');
34
35 // Clear any previous interval for this widget (editor re-renders)
36 if (activeIntervals[widgetId]) {
37 clearInterval(activeIntervals[widgetId]);
38 delete activeIntervals[widgetId];
39 }
40
41 var targetTime;
42 var intervalId;
43
44 // ── Determine target timestamp ────────────────────────────────────
45 if (countdownType === 'evergreen') {
46 var storageKeyTime = 'nx_countdown_evergreen_time_' + widgetId;
47 var storageKeyInterval = 'nx_countdown_evergreen_interval_' + widgetId;
48 var storedTime = localStorage.getItem(storageKeyTime);
49 var storedInterval = localStorage.getItem(storageKeyInterval);
50 var HOUR_MS = 60 * 60 * 1000;
51
52 // Reset if the evergreen duration changed or no stored value
53 if (storedTime === null || storedInterval === null || parseInt(storedInterval, 10) !== evergreenTime) {
54 storedTime = Date.now() + evergreenTime * 1000;
55 localStorage.setItem(storageKeyInterval, String(evergreenTime));
56 localStorage.setItem(storageKeyTime, String(storedTime));
57 }
58
59 storedTime = parseInt(storedTime, 10);
60
61 if (recurring !== undefined && recurring !== false) {
62 var recurringAfterMs = parseFloat(recurring) * HOUR_MS;
63 // If enough time has passed, restart
64 if (storedTime + recurringAfterMs < Date.now()) {
65 storedTime = Date.now() + evergreenTime * 1000;
66 localStorage.setItem(storageKeyTime, String(storedTime));
67 }
68 // Cap at the recurring stop time
69 if (recurringStop) {
70 var stopTs = new Date(recurringStop).getTime();
71 if (!isNaN(stopTs) && stopTs < storedTime) {
72 storedTime = stopTs;
73 }
74 }
75 }
76
77 targetTime = storedTime;
78
79 } else {
80 // due_date — date string is stored on the <ul> element
81 var dateStr = $list.data('date') || '';
82 targetTime = dateStr ? new Date(dateStr).getTime() : 0;
83 }
84
85 // ── Expiry handler ────────────────────────────────────────────────
86 function handleExpiry() {
87 clearInterval(intervalId);
88 delete activeIntervals[widgetId];
89
90 if (expireType === 'text') {
91 $list.html(
92 '<div class="nx-countdown-finish-message">' +
93 '<h4 class="nx-expiry-title">' + expireTitle + '</h4>' +
94 '<div class="nx-expiry-text">' + expireText + '</div>' +
95 '</div>'
96 );
97 } else if (expireType === 'url') {
98 if (typeof elementorFrontend !== 'undefined' && elementorFrontend.isEditMode()) {
99 $list.html('<p>Page will redirect to the given URL on the frontend.</p>');
100 } else {
101 window.location.href = redirectUrl;
102 }
103 }
104 // 'none' — do nothing
105 }
106
107 // ── Pad helper ────────────────────────────────────────────────────
108 function pad(n) {
109 return String(n).padStart(2, '0');
110 }
111
112 // ── Tick ──────────────────────────────────────────────────────────
113 function tick() {
114 var now = Date.now();
115 var diff = targetTime - now;
116
117 if (diff <= 0) {
118 // Show zeros then handle expiry
119 if ($daysEl.length) $daysEl.text('00');
120 if ($hoursEl.length) $hoursEl.text('00');
121 if ($minutesEl.length) $minutesEl.text('00');
122 if ($secondsEl.length) $secondsEl.text('00');
123 handleExpiry();
124 return;
125 }
126
127 var days = Math.floor(diff / (1000 * 60 * 60 * 24));
128 var hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
129 var minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
130 var seconds = Math.floor((diff % (1000 * 60)) / 1000);
131
132 if ($daysEl.length) $daysEl.text(pad(days));
133 if ($hoursEl.length) $hoursEl.text(pad(hours));
134 if ($minutesEl.length) $minutesEl.text(pad(minutes));
135 if ($secondsEl.length) $secondsEl.text(pad(seconds));
136 }
137
138 if (!targetTime) return;
139
140 tick(); // immediate first render
141 intervalId = setInterval(tick, 1000);
142 activeIntervals[widgetId] = intervalId;
143 };
144
145 // Register with Elementor — fires in BOTH editor preview and frontend
146 $(window).on('elementor/frontend/init', function () {
147 elementorFrontend.hooks.addAction(
148 'frontend/element_ready/nx-countdown-timer.default',
149 NXCountdown
150 );
151 });
152
153 }(jQuery));
154