(function () { const matrixForm = document.getElementById("matrixForm"); const matrixScroll = document.getElementById("matrixScroll"); const matrixTable = document.getElementById("matrixTable"); const topScroll = document.getElementById("matrixHScroll"); const topScrollInner = document.getElementById("matrixHScrollInner"); if (!matrixForm || !matrixScroll || !matrixTable || !topScroll || !topScrollInner) return; let isDirty = false; let syncing = false; let saveTimer = null; let saveInFlight = false; function markDirty() { isDirty = true; } function updateTopScrollWidth() { topScrollInner.style.width = matrixTable.scrollWidth + "px"; } function syncScrollFromTop() { if (syncing) return; syncing = true; matrixScroll.scrollLeft = topScroll.scrollLeft; syncing = false; } function syncScrollFromMatrix() { if (syncing) return; syncing = true; topScroll.scrollLeft = matrixScroll.scrollLeft; syncing = false; } async function autoSaveMatrix() { if (saveInFlight) return; saveInFlight = true; try { const formData = new FormData(matrixForm); const response = await fetch(window.location.href, { method: "POST", body: formData, credentials: "same-origin", }); if (!response.ok) throw new Error("save failed"); isDirty = false; } catch (error) { } finally { saveInFlight = false; } } matrixForm.addEventListener("change", (event) => { if (!(event.target && event.target.matches('input[type="checkbox"]'))) return; markDirty(); if (saveTimer) clearTimeout(saveTimer); saveTimer = setTimeout(autoSaveMatrix, 250); }); matrixForm.addEventListener("submit", () => { isDirty = false; }); window.addEventListener("beforeunload", (event) => { if (!isDirty) return; event.preventDefault(); event.returnValue = ""; }); document.addEventListener("click", (event) => { const anchor = event.target.closest("a"); if (!anchor || !isDirty) return; const ok = window.confirm("Есть несохраненные изменения матрицы. Нажмите OK, чтобы остаться и сначала сохранить."); if (!ok) return; event.preventDefault(); }); document.addEventListener("submit", (event) => { const form = event.target; if (!form || form === matrixForm || !isDirty) return; const ok = window.confirm("Есть несохраненные изменения матрицы. Нажмите OK, чтобы остаться и сначала сохранить."); if (!ok) return; event.preventDefault(); }); topScroll.addEventListener("scroll", syncScrollFromTop); matrixScroll.addEventListener("scroll", syncScrollFromMatrix); window.addEventListener("resize", updateTopScrollWidth); updateTopScrollWidth(); syncScrollFromMatrix(); })();