// The page itself is server-rendered and static. This adds the two things a status page wants that // a snapshot can't carry: times that stay relative to now, and a track counter that keeps running // between refreshes. const REFRESH_KEY = "rvrb-auto-refresh"; const REFRESH_MS = 30_000; let timer; export function onLoad() { wireAutoRefresh(); startTicking(); } export function onUpdate() { // Enhanced navigation swaps the DOM without a page load, so whatever was ticking is now // pointing at elements that are gone. stopTicking(); wireAutoRefresh(); startTicking(); } export function onDispose() { stopTicking(); } function wireAutoRefresh() { const checkbox = document.getElementById("autoRefresh"); if (!checkbox) return; // Read back from storage, since the setting has to survive the very reload it causes. checkbox.checked = localStorage.getItem(REFRESH_KEY) === "on"; checkbox.addEventListener("change", () => { localStorage.setItem(REFRESH_KEY, checkbox.checked ? "on" : "off"); }); } function startTicking() { const started = performance.now(); const progress = document.getElementById("trackProgress"); const elapsedLabel = document.getElementById("trackElapsed"); const times = document.querySelectorAll("time[data-relative]"); const checkbox = document.getElementById("autoRefresh"); const tick = () => { const sinceRender = performance.now() - started; if (progress) advanceTrack(progress, elapsedLabel, sinceRender); times.forEach(relabel); if (checkbox?.checked && sinceRender >= REFRESH_MS) location.reload(); }; tick(); timer = setInterval(tick, 1000); } function stopTicking() { clearInterval(timer); timer = undefined; } // The snapshot says how far into the track the bot was when it was taken, and how long ago that // was; everything after that is just wall clock. function advanceTrack(progress, label, sinceRender) { const duration = Number(progress.dataset.durationMs); if (!duration) return; const elapsed = Math.min( Number(progress.dataset.elapsedMs) + Number(progress.dataset.ageMs) + sinceRender, duration); progress.value = Math.round((elapsed / duration) * Number(progress.max)); if (label) label.textContent = formatDuration(elapsed); } function relabel(time) { const at = Date.parse(time.dateTime); if (Number.isNaN(at)) return; time.title ||= time.textContent; time.textContent = formatAgo(Date.now() - at); } function formatAgo(ms) { if (ms < 0) return "just now"; const seconds = Math.floor(ms / 1000); if (seconds < 60) return `${seconds}s ago`; const minutes = Math.floor(seconds / 60); if (minutes < 60) return `${minutes}m ago`; const hours = Math.floor(minutes / 60); if (hours < 24) return `${hours}h ago`; const days = Math.floor(hours / 24); return days < 30 ? `${days}d ago` : `${Math.floor(days / 30)}mo ago`; } function formatDuration(ms) { const seconds = Math.max(Math.floor(ms / 1000), 0); const minutes = Math.floor(seconds / 60); return minutes > 0 ? `${minutes}m ${seconds % 60}s` : `${seconds}s`; }