117 lines
4.3 KiB
JavaScript
117 lines
4.3 KiB
JavaScript
/**
|
|
* Product Discount Countdown Module
|
|
*
|
|
* This script initializes countdown timers on the product page.
|
|
* It handles the initial page load and the dynamic updates that occur
|
|
* when a customer changes a product combination (attribute).
|
|
*/
|
|
|
|
// A global array to keep track of our active timer intervals.
|
|
// This is crucial for cleanup when the product block is updated via AJAX.
|
|
let productCountdownIntervals = [];
|
|
|
|
/**
|
|
* Scans the DOM for countdown containers and initializes them.
|
|
* This function is designed to be called on page load and after AJAX updates.
|
|
*/
|
|
function initializeProductCountdowns() {
|
|
// 1. Clear any previously running timers.
|
|
// This prevents multiple timers from running after a product combination change.
|
|
productCountdownIntervals.forEach(intervalId => clearInterval(intervalId));
|
|
productCountdownIntervals = [];
|
|
|
|
// 2. Find all countdown containers on the page that need to be processed.
|
|
const countdownContainers = document.querySelectorAll('.product-countdown-container');
|
|
|
|
countdownContainers.forEach(container => {
|
|
// Check if this specific container has already been initialized to avoid race conditions.
|
|
if (container.dataset.initialized === 'true') {
|
|
return;
|
|
}
|
|
|
|
const timerElement = container.querySelector('.countdown-timer');
|
|
if (!timerElement) return;
|
|
|
|
// Mark as initialized
|
|
container.dataset.initialized = 'true';
|
|
|
|
const targetTimestamp = parseInt(container.dataset.timestamp, 10);
|
|
const onExpireAction = container.dataset.onExpire;
|
|
const expiredText = container.dataset.expiredText;
|
|
|
|
// Get translated units from hidden spans
|
|
const units = {
|
|
day: container.querySelector('[data-unit="day"]').textContent,
|
|
days: container.querySelector('[data-unit="days"]').textContent,
|
|
hr: container.querySelector('[data-unit="hr"]').textContent,
|
|
min: container.querySelector('[data-unit="min"]').textContent,
|
|
sec: container.querySelector('[data-unit="sec"]').textContent
|
|
};
|
|
|
|
function updateTimer() {
|
|
const now = Math.floor(new Date().getTime() / 1000);
|
|
const diff = targetTimestamp - now;
|
|
|
|
if (diff <= 0) {
|
|
clearInterval(interval);
|
|
handleExpiry();
|
|
return;
|
|
}
|
|
|
|
const d = Math.floor(diff / (60 * 60 * 24));
|
|
const h = Math.floor((diff % (60 * 60 * 24)) / (60 * 60));
|
|
const m = Math.floor((diff % (60 * 60)) / 60);
|
|
const s = Math.floor(diff % 60);
|
|
|
|
const parts = [];
|
|
if (d > 0) {
|
|
parts.push(`${d} ${d > 1 ? units.days : units.day}`);
|
|
}
|
|
// Always show hours, minutes, and seconds for a better countdown experience
|
|
parts.push(`${String(h).padStart(2, '0')}${units.hr}`);
|
|
parts.push(`${String(m).padStart(2, '0')}${units.min}`);
|
|
parts.push(`${String(s).padStart(2, '0')}${units.sec}`);
|
|
|
|
timerElement.textContent = parts.join(' ');
|
|
}
|
|
|
|
function handleExpiry() {
|
|
switch (onExpireAction) {
|
|
case 'reload':
|
|
location.reload();
|
|
break;
|
|
case 'message':
|
|
container.querySelector('.countdown-wrapper').innerHTML = `<span class="badge badge-secondary">${expiredText}</span>`;
|
|
break;
|
|
case 'hide':
|
|
default:
|
|
container.style.display = 'none';
|
|
break;
|
|
}
|
|
}
|
|
|
|
const interval = setInterval(updateTimer, 1000);
|
|
// Add the new interval ID to our global array for tracking.
|
|
productCountdownIntervals.push(interval);
|
|
updateTimer(); // Initial call to display the timer immediately
|
|
});
|
|
}
|
|
|
|
// --- Event Listeners ---
|
|
|
|
// 1. Run the initializer on the initial page load.
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
initializeProductCountdowns();
|
|
});
|
|
|
|
// 2. Run the initializer whenever PrestaShop updates the product block via AJAX.
|
|
// The `prestashop` object is globally available in modern themes.
|
|
if (typeof prestashop !== 'undefined') {
|
|
prestashop.on('updateProduct', (data) => {
|
|
// We use a small timeout to ensure the DOM has been fully updated by PrestaShop's scripts
|
|
// before our script runs and looks for the new container. 100ms is usually safe.
|
|
setTimeout(() => {
|
|
initializeProductCountdowns();
|
|
}, 100);
|
|
});
|
|
} |