110 lines
3.1 KiB
JavaScript
110 lines
3.1 KiB
JavaScript
(() => {
|
|
function pad2(value) {
|
|
return String(value).padStart(2, "0");
|
|
}
|
|
|
|
function splitCountdown(ms) {
|
|
const totalSeconds = Math.max(0, Math.floor(ms / 1000));
|
|
const days = Math.floor(totalSeconds / 86400);
|
|
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
const seconds = totalSeconds % 60;
|
|
return { days, hours, minutes, seconds };
|
|
}
|
|
|
|
function setAnimatedValue(node, nextValue) {
|
|
if (!node) {
|
|
return;
|
|
}
|
|
if (node.textContent === nextValue) {
|
|
return;
|
|
}
|
|
node.textContent = nextValue;
|
|
node.classList.remove("is-updated");
|
|
void node.offsetWidth;
|
|
node.classList.add("is-updated");
|
|
}
|
|
|
|
function initTimer(widget) {
|
|
const targetIso = widget.dataset.countdownTarget;
|
|
const startedLabel = widget.dataset.countdownStarted || "";
|
|
const toggle = widget.querySelector("[data-countdown-toggle]");
|
|
const popover = widget.querySelector("[data-countdown-popover]");
|
|
const subline = widget.querySelector("[data-countdown-subline]");
|
|
const daysNode = widget.querySelector("[data-countdown-days]");
|
|
const hoursNode = widget.querySelector("[data-countdown-hours]");
|
|
const minutesNode = widget.querySelector("[data-countdown-minutes]");
|
|
const secondsNode = widget.querySelector("[data-countdown-seconds]");
|
|
|
|
if (!targetIso || !toggle || !popover || !subline || !daysNode || !hoursNode || !minutesNode || !secondsNode) {
|
|
return;
|
|
}
|
|
|
|
const targetMs = Date.parse(targetIso);
|
|
if (Number.isNaN(targetMs)) {
|
|
subline.textContent = "--";
|
|
return;
|
|
}
|
|
|
|
const update = () => {
|
|
const now = Date.now();
|
|
const delta = targetMs - now;
|
|
|
|
if (delta <= 0) {
|
|
setAnimatedValue(daysNode, "0");
|
|
setAnimatedValue(hoursNode, "00");
|
|
setAnimatedValue(minutesNode, "00");
|
|
setAnimatedValue(secondsNode, "00");
|
|
subline.textContent = startedLabel;
|
|
return;
|
|
}
|
|
|
|
const parts = splitCountdown(delta);
|
|
setAnimatedValue(daysNode, String(parts.days));
|
|
setAnimatedValue(hoursNode, pad2(parts.hours));
|
|
setAnimatedValue(minutesNode, pad2(parts.minutes));
|
|
setAnimatedValue(secondsNode, pad2(parts.seconds));
|
|
};
|
|
|
|
const close = () => {
|
|
popover.hidden = true;
|
|
toggle.setAttribute("aria-expanded", "false");
|
|
};
|
|
|
|
const open = () => {
|
|
popover.hidden = false;
|
|
toggle.setAttribute("aria-expanded", "true");
|
|
update();
|
|
};
|
|
|
|
toggle.addEventListener("click", (event) => {
|
|
event.preventDefault();
|
|
if (popover.hidden) {
|
|
open();
|
|
} else {
|
|
close();
|
|
}
|
|
});
|
|
|
|
document.addEventListener("click", (event) => {
|
|
if (!widget.contains(event.target)) {
|
|
close();
|
|
}
|
|
});
|
|
|
|
document.addEventListener("keydown", (event) => {
|
|
if (event.key === "Escape") {
|
|
close();
|
|
}
|
|
});
|
|
|
|
update();
|
|
window.setInterval(update, 1000);
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
const widgets = document.querySelectorAll(".toolbar-timer");
|
|
widgets.forEach(initTimer);
|
|
});
|
|
})();
|