/** * Bootstrap shell-модалки (.wesp-shell-modal) — единая анимация открытия/закрытия. */ (function (global) { const WIRED = "data-wesp-shell-modal-wired"; const ALLOW_HIDE = "data-wesp-shell-allow-hide"; const MODAL_MS = 240; function prefersReducedMotion() { return global.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches ?? false; } function getDialog(el) { return el?.querySelector(".modal-dialog--shell"); } function wireShellModal(el) { if (!el || el.getAttribute(WIRED)) return; el.setAttribute(WIRED, "1"); el.addEventListener("show.bs.modal", function () { el.classList.remove("wesp-shell-closing"); if (prefersReducedMotion()) { el.classList.add("wesp-shell-visible"); return; } el.classList.remove("wesp-shell-visible"); requestAnimationFrame(function () { requestAnimationFrame(function () { el.classList.add("wesp-shell-visible"); }); }); }); el.addEventListener("shown.bs.modal", function () { el.removeAttribute("aria-hidden"); }); el.addEventListener("hide.bs.modal", function (e) { if (el.getAttribute(ALLOW_HIDE) === "1") { el.removeAttribute(ALLOW_HIDE); el.classList.remove("wesp-shell-visible", "wesp-shell-closing"); return; } if (prefersReducedMotion()) { el.classList.remove("wesp-shell-visible"); return; } e.preventDefault(); el.classList.add("wesp-shell-closing"); el.classList.remove("wesp-shell-visible"); const dialog = getDialog(el); let finished = false; const finish = function () { if (finished) return; finished = true; el.setAttribute(ALLOW_HIDE, "1"); const instance = global.bootstrap?.Modal?.getInstance(el); instance?.hide(); }; if (dialog) { dialog.addEventListener( "transitionend", function (ev) { if (ev.target === dialog) finish(); }, { once: true } ); } global.setTimeout(finish, MODAL_MS + 50); }); el.addEventListener("hidden.bs.modal", function () { el.classList.remove("wesp-shell-closing", "wesp-shell-visible"); el.setAttribute("aria-hidden", "true"); }); } function wireAllShellModals() { document.querySelectorAll(".modal.wesp-shell-modal").forEach(wireShellModal); } function show(modalId) { const el = document.getElementById(modalId); if (!el) return null; wireShellModal(el); const instance = global.bootstrap?.Modal?.getOrCreateInstance(el, { backdrop: true, keyboard: true, focus: true, }); instance?.show(); return instance; } function hide(modalId) { const el = document.getElementById(modalId); if (!el) return; const instance = global.bootstrap?.Modal?.getInstance(el); if (instance) instance.hide(); } function whenPageEnterDone(run) { const html = document.documentElement; let ran = false; let observer = null; let fallbackTimer = 0; const once = function () { if (ran) return; ran = true; if (observer) { observer.disconnect(); observer = null; } if (fallbackTimer) { global.clearTimeout(fallbackTimer); fallbackTimer = 0; } requestAnimationFrame(run); }; if (html.classList.contains("wesp-page-enter-done")) { once(); return; } if ( !html.classList.contains("wesp-page-enter-pending") && !html.classList.contains("wesp-page-enter-ready") ) { once(); return; } observer = new MutationObserver(function () { if (!html.classList.contains("wesp-page-enter-done")) return; once(); }); observer.observe(html, { attributes: true, attributeFilter: ["class"] }); fallbackTimer = global.setTimeout(function () { if (!html.classList.contains("wesp-page-enter-done")) return; once(); }, 1200); } function animateGridCards(gridSelector, options) { if (prefersReducedMotion()) return; const force = Boolean(options && options.force); const run = function () { const grid = document.querySelector(gridSelector); if (!grid) return; const cards = grid.querySelectorAll(".dispenser-card, .component-card, .report-card"); if ( !force && cards.length > 0 && Array.from(cards).every(function (card) { return card.classList.contains("wesp-grid-enter-item"); }) ) { return; } cards.forEach(function (card, i) { card.classList.remove("wesp-grid-enter-item"); card.style.removeProperty("--wesp-grid-i"); void card.offsetWidth; card.style.setProperty("--wesp-grid-i", String(Math.min(i, 12))); card.classList.add("wesp-grid-enter-item"); }); }; whenPageEnterDone(run); } function revealContent(el) { if (!el || prefersReducedMotion()) return; el.classList.remove("wesp-content-reveal"); void el.offsetWidth; el.classList.add("wesp-content-reveal"); } global.WespZootechModals = { show, hide, wireAllShellModals, animateGridCards, revealContent, prefersReducedMotion, }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", wireAllShellModals); } else { wireAllShellModals(); } })(typeof window !== "undefined" ? window : globalThis);