You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.6 KiB
99 lines
2.6 KiB
/* ========================================================
|
|
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);
|
|
}
|
|
}
|