/* ======================================================== File: static/js/state_updater.js Purpose: - Poll /api/state/all - Dispatch merged state to subscribers (bookcard_controller, inspect_state, others) - Pause polling when tab inactive ======================================================== */ console.log("[STATE-UPDATER] loaded"); const STATE_POLL_INTERVAL_MS = 2500; const STATE_ENDPOINT = "/api/state/all"; let STATE_TIMER = null; /* ======================================================== INIT ======================================================== */ document.addEventListener("DOMContentLoaded", () => { initStateUpdater(); }); function initStateUpdater() { const cards = document.querySelectorAll(".book-card"); if (cards.length === 0) { console.log("[STATE-UPDATER] No bookcards found — skipping"); return; } console.log(`[STATE-UPDATER] Starting updater for ${cards.length} bookcards`); startPolling(true); document.addEventListener("visibilitychange", () => { document.hidden ? stopPolling() : startPolling(true); }); } /* ======================================================== DISPATCH ======================================================== */ function dispatchState(entries) { console.debug("[STATE] dispatch", entries.length); // 1. Bookcards if (typeof window.updateBookCardsFromState === "function") { window.updateBookCardsFromState(entries); } // 2. Inspect state tables / other subscribers window.dispatchEvent(new CustomEvent("state:update", { detail: entries })); } /* ======================================================== POLLING CONTROL ======================================================== */ function startPolling(immediate = false) { if (STATE_TIMER) return; console.log("[STATE-UPDATER] Start polling"); if (immediate) pollState(); STATE_TIMER = setInterval(pollState, STATE_POLL_INTERVAL_MS); } function stopPolling() { if (!STATE_TIMER) return; console.log("[STATE-UPDATER] Stop polling (tab inactive)"); clearInterval(STATE_TIMER); STATE_TIMER = null; } /* ======================================================== POLL API ======================================================== */ async function pollState() { if (document.hidden) return; try { const resp = await fetch(STATE_ENDPOINT, { cache: "no-store" }); if (!resp.ok) return; const entries = await resp.json(); if (!Array.isArray(entries)) return; dispatchState(entries); } catch (e) { console.error("[STATE-UPDATER] poll error", e); } }