/* ======================================================================= File: static/js/log_view.js Purpose: Log viewer functionality: - filtering - clearing - auto-scroll - delta polling (efficient) - rolling limit (prevent GUI freeze) ======================================================================= */ console.log(">>> log_view.js LOADING…"); /* --------------------------------------------------------- Log filtering --------------------------------------------------------- */ let LOG_FILTER = "ALL"; let LAST_LOG_INDEX = -1; // For delta polling const MAX_LOG_LINES = 2000; // Rolling cap to prevent freezing function applyLogFilter() { console.log(">>> log_view.js applyLogFilter(), filter =", LOG_FILTER); const lines = $$(".log-line"); console.log(">>> log_view.js number of log-line elements:", lines.length); lines.forEach((line) => { const text = line.innerText; line.style.display = LOG_FILTER === "ALL" || text.includes(LOG_FILTER) ? "block" : "none"; }); } /* --------------------------------------------------------- UI bindings --------------------------------------------------------- */ document.addEventListener("DOMContentLoaded", () => { console.log(">>> log_view.js DOMContentLoaded"); const filterSel = $("#log-filter"); const clearBtn = $("#log-clear"); const output = $("#log-output"); if (!filterSel) { console.log(">>> log_view.js: No log viewer found on this page."); return; } console.log(">>> log_view.js: log viewer detected."); // Filter dropdown filterSel.addEventListener("change", () => { LOG_FILTER = filterSel.value; console.log(">>> log_view.js filter changed to:", LOG_FILTER); applyLogFilter(); }); // Clear log window if (clearBtn) { clearBtn.addEventListener("click", () => { console.log(">>> log_view.js log-clear clicked → clearing output"); if (output) { output.innerHTML = ""; LAST_LOG_INDEX = -1; // reset delta polling } }); } }); /* --------------------------------------------------------- Append + Rolling buffer --------------------------------------------------------- */ function logAppend(lineText) { const output = $("#log-output"); if (!output) return; const div = document.createElement("div"); div.classList.add("log-line"); // ----------------------------------------------------- // Assign subtype classes // ----------------------------------------------------- if (lineText.includes("[DL]") || lineText.includes("[DOWNLOAD]")) { div.classList.add("dl"); } else if (lineText.includes("[PARSE]")) { div.classList.add("parse"); } else if (lineText.includes("[SAVE]")) { div.classList.add("save"); } else if (lineText.includes("[AUDIO]")) { div.classList.add("audio"); } else if (lineText.includes("[CTRL]")) { div.classList.add("ctrl"); } else if (lineText.includes("[ERROR]")) { div.classList.add("error"); } else { div.classList.add("default"); } div.innerText = lineText; output.appendChild(div); // Rolling buffer while (output.children.length > MAX_LOG_LINES) { output.removeChild(output.firstChild); } applyLogFilter(); autoScroll(output); } /* --------------------------------------------------------- Delta-based log polling --------------------------------------------------------- */ function pollLogs() { fetch(`/logs?last_index=${LAST_LOG_INDEX}`) .then((r) => r.json()) .then((data) => { const lines = data.lines || []; if (lines.length > 0) { lines.forEach((line) => logAppend(line)); LAST_LOG_INDEX = data.total - 1; } }) .catch((err) => { console.warn(">>> log_view.js pollLogs() error:", err); }); } // Poll every 800 ms setInterval(pollLogs, 800); console.log(">>> log_view.js LOADED");