diff --git a/hive-c0re/assets/app.js b/hive-c0re/assets/app.js index 6bce65d..2409710 100644 --- a/hive-c0re/assets/app.js +++ b/hive-c0re/assets/app.js @@ -574,7 +574,35 @@ // ─── state polling ────────────────────────────────────────────────────── let pollTimer = null; + // Sections whose innerHTML gets blown away on each refresh. If the + // operator is typing in one of them, skip the refresh — the next + // tick (or a manual action) will pick it up after they blur. + const MANAGED_SECTION_IDS = [ + 'containers-section', + 'tombstones-section', + 'questions-section', + 'inbox-section', + 'approvals-section', + ]; + function operatorIsTyping() { + const el_ = document.activeElement; + if (!el_ || el_ === document.body) return false; + const tag = el_.tagName; + if (tag !== 'INPUT' && tag !== 'TEXTAREA' && tag !== 'SELECT') return false; + return MANAGED_SECTION_IDS.some((id) => { + const sect = document.getElementById(id); + return sect && sect.contains(el_); + }); + } async function refreshState() { + // Don't yank the form out from under the operator. Try again + // shortly on the next tick; eventually they'll blur and the + // refresh lands. + if (operatorIsTyping()) { + if (pollTimer) clearTimeout(pollTimer); + pollTimer = setTimeout(refreshState, 2000); + return; + } try { const resp = await fetch('/api/state'); if (!resp.ok) throw new Error('http ' + resp.status);