/** * Диалоги alert/confirm для веб-оболочки зоотехника (не скрипты страниц киоска). * API: WespDialog.alert(msg, opts?) -> Promise * WespDialog.confirm(msg, opts?) -> Promise * opts.timerOnly — закрытие только через WespDialog.closeActive() (таймер); без кнопки, без Escape и клика по фону. */ (function (global) { var OVERLAY_ID = "wespShellDialogOverlay"; var STYLE_ID = "wesp-shell-dialog-styles"; function injectStyles() { if (document.getElementById(STYLE_ID)) return; var s = document.createElement("style"); s.id = STYLE_ID; s.textContent = "#" + OVERLAY_ID + "{" + "position:fixed;inset:0;z-index:5000;" + "display:none;align-items:center;justify-content:center;" + "padding:16px;background:rgba(0,0,0,.55);" + "box-sizing:border-box;" + "opacity:0;transition:opacity .22s cubic-bezier(.22,1,.36,1);" + "backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);" + "}" + "#" + OVERLAY_ID + '[aria-hidden="false"]{display:flex;opacity:1;}' + "#" + OVERLAY_ID + ".wesp-shell-dialog-overlay-closing{opacity:0;}" + ".wesp-shell-dialog{" + "width:min(420px,100%);max-height:min(80vh,520px);overflow:auto;" + "background:#fff;color:#111827;border-radius:8px;" + "border:1px solid #e5e7eb;box-shadow:0 8px 32px rgba(0,0,0,.18);" + "padding:20px 22px;font-family:var(--zootech-font,Inter,system-ui,sans-serif);" + "-webkit-font-smoothing:antialiased;" + "text-align:left;" + "opacity:0;transform:scale(.97) translateY(8px);" + "transition:opacity .22s cubic-bezier(.22,1,.36,1),transform .22s cubic-bezier(.22,1,.36,1);" + "}" + "#" + OVERLAY_ID + '[aria-hidden="false"]:not(.wesp-shell-dialog-overlay-closing) .wesp-shell-dialog{' + "opacity:1;transform:scale(1) translateY(0);" + "}" + "#" + OVERLAY_ID + ".wesp-shell-dialog-overlay-closing .wesp-shell-dialog{" + "opacity:0;transform:scale(.97) translateY(8px);" + "}" + "@media (prefers-reduced-motion:reduce){" + "#" + OVERLAY_ID + ",.wesp-shell-dialog{transition:none!important;transform:none!important;}" + "#" + OVERLAY_ID + "{backdrop-filter:none;-webkit-backdrop-filter:none;}" + ".wesp-shell-dialog{opacity:1!important;}" + "}" + ".wesp-shell-dialog-title{" + "margin:0 0 12px 0;font-size:1.125rem;font-weight:600;color:#111827;" + "}" + ".wesp-shell-dialog-body{" + "margin:0;font-size:0.95rem;line-height:1.5;color:#374151;white-space:pre-wrap;word-break:break-word;" + "}" + ".wesp-shell-dialog-actions{" + "display:flex;justify-content:flex-end;flex-wrap:wrap;gap:10px;margin-top:20px;" + "}" + ".wesp-shell-dialog-btn{" + "min-width:120px;padding:10px 18px;border-radius:6px;font-size:0.95rem;font-weight:500;" + "cursor:pointer;font-family:inherit;border:1px solid #e5e7eb;background:#fff;color:#374151;" + "transition:background .2s,border-color .2s,box-shadow .2s;" + "}" + ".wesp-shell-dialog-btn:hover{filter:brightness(.97);}" + ".wesp-shell-dialog-btn-primary{" + "background:#2563eb;border-color:#2563eb;color:#fff;" + "}" + ".wesp-shell-dialog-btn-primary:hover{box-shadow:0 4px 12px rgba(37,99,235,.25);}" + ".wesp-shell-dialog-btn-danger{" + "background:#ef4444;border-color:#ef4444;color:#fff;" + "}" + ".wesp-shell-dialog--danger{border-top:4px solid #ef4444;}" + ".wesp-shell-dialog--success{border-top:4px solid #10b981;}" + "html[data-theme=dark] #" + OVERLAY_ID + " .wesp-shell-dialog{" + "background:var(--dm-surface,#2c3338);color:var(--dm-text,#f5f5f5);border-color:var(--dm-border,rgba(255,255,255,.12));" + "}" + "html[data-theme=dark] #" + OVERLAY_ID + " .wesp-shell-dialog-title{color:var(--dm-text,#f5f5f5);}" + "html[data-theme=dark] #" + OVERLAY_ID + " .wesp-shell-dialog-body{color:var(--dm-text,#f5f5f5);}" + "html[data-theme=dark] #" + OVERLAY_ID + " .wesp-shell-dialog-btn{" + "background:var(--dm-field,#3e444a);border-color:var(--dm-border,rgba(255,255,255,.12));color:var(--dm-text,#f5f5f5);" + "}" + "html[data-theme=dark] #" + OVERLAY_ID + " .wesp-shell-dialog-btn-primary{background:#2563eb;border-color:#2563eb;color:#fff;}" + "html[data-theme=dark] #" + OVERLAY_ID + " .wesp-shell-dialog-btn-danger{background:#dc2626;border-color:#dc2626;color:#fff;}" + ""; document.head.appendChild(s); } function ensureDom() { injectStyles(); var el = document.getElementById(OVERLAY_ID); if (el) return el; el = document.createElement("div"); el.id = OVERLAY_ID; el.setAttribute("aria-hidden", "true"); el.innerHTML = '"; el.addEventListener("click", function (e) { if (e.target === el) { backdropDismiss(); } }); document.body.appendChild(el); return el; } var pendingResolve = null; var pendingMode = null; var blockUserDismiss = false; function backdropDismiss() { if (blockUserDismiss) return; if (pendingMode === "confirm" && pendingResolve) { var fn = pendingResolve; pendingResolve = null; pendingMode = null; hide(); fn(false); } else if (pendingMode === "alert" && pendingResolve) { var fn2 = pendingResolve; pendingResolve = null; pendingMode = null; hide(); fn2(); } } function prefersReducedMotion() { return ( global.matchMedia && global.matchMedia("(prefers-reduced-motion: reduce)").matches ); } function hide() { var el = document.getElementById(OVERLAY_ID); if (!el || el.getAttribute("aria-hidden") === "true") return; var dlg = el.querySelector(".wesp-shell-dialog"); if (dlg) dlg.removeAttribute("tabindex"); blockUserDismiss = false; document.removeEventListener("keydown", onKey); if (prefersReducedMotion()) { el.classList.remove("wesp-shell-dialog-overlay-closing"); el.setAttribute("aria-hidden", "true"); return; } el.classList.add("wesp-shell-dialog-overlay-closing"); var done = false; var finish = function () { if (done) return; done = true; el.classList.remove("wesp-shell-dialog-overlay-closing"); el.setAttribute("aria-hidden", "true"); }; el.addEventListener( "transitionend", function (e) { if (e.target === el) finish(); }, { once: true } ); global.setTimeout(finish, 280); } function closeActive() { if (pendingMode === "confirm" && pendingResolve) { var fnC = pendingResolve; pendingResolve = null; pendingMode = null; hide(); fnC(false); } else if (pendingMode === "alert" && pendingResolve) { var fnA = pendingResolve; pendingResolve = null; pendingMode = null; hide(); fnA(); } } function onKey(e) { if (e.key === "Escape") { e.preventDefault(); if (blockUserDismiss) return; backdropDismiss(); } } function show() { var el = document.getElementById(OVERLAY_ID); if (!el) return; el.classList.remove("wesp-shell-dialog-overlay-closing"); el.setAttribute("aria-hidden", "false"); document.addEventListener("keydown", onKey); if (!prefersReducedMotion()) { var dlg = el.querySelector(".wesp-shell-dialog"); if (dlg) { dlg.style.opacity = "0"; dlg.style.transform = "scale(0.97) translateY(8px)"; requestAnimationFrame(function () { requestAnimationFrame(function () { dlg.style.opacity = ""; dlg.style.transform = ""; }); }); } } } function setDialogVariant(dialogEl, variant) { dialogEl.classList.remove("wesp-shell-dialog--danger", "wesp-shell-dialog--success"); if (variant === "danger") dialogEl.classList.add("wesp-shell-dialog--danger"); else if (variant === "success") dialogEl.classList.add("wesp-shell-dialog--success"); } function displayDialogMessage(message, opts) { const variant = opts && opts.variant; const fallback = opts && opts.fallback; if (variant === "danger" && global.WespUserMessages?.userFacingMessage) { return global.WespUserMessages.userFacingMessage(message, fallback || "Не удалось выполнить операцию. Попробуйте ещё раз."); } return message == null ? "" : String(message); } function alert(message, opts) { opts = opts || {}; return new Promise(function (resolve) { var overlay = ensureDom(); var dialog = overlay.querySelector(".wesp-shell-dialog"); var titleEl = document.getElementById("wespShellDialogTitle"); var bodyEl = document.getElementById("wespShellDialogBody"); var actions = document.getElementById("wespShellDialogActions"); titleEl.textContent = opts.title != null ? String(opts.title) : "Сообщение"; bodyEl.textContent = displayDialogMessage(message, opts); setDialogVariant(dialog, opts.variant || "info"); actions.innerHTML = ""; blockUserDismiss = !!opts.timerOnly; pendingMode = "alert"; pendingResolve = resolve; if (!opts.timerOnly) { var ok = document.createElement("button"); ok.type = "button"; ok.className = "wesp-shell-dialog-btn wesp-shell-dialog-btn-primary"; ok.textContent = opts.okText || "Понятно"; ok.addEventListener("click", function () { pendingResolve = null; pendingMode = null; hide(); resolve(); }); actions.appendChild(ok); show(); ok.focus(); } else { dialog.setAttribute("tabindex", "-1"); show(); dialog.focus(); } }); } function confirm(message, opts) { opts = opts || {}; return new Promise(function (resolve) { blockUserDismiss = false; var overlay = ensureDom(); var dialog = overlay.querySelector(".wesp-shell-dialog"); var titleEl = document.getElementById("wespShellDialogTitle"); var bodyEl = document.getElementById("wespShellDialogBody"); var actions = document.getElementById("wespShellDialogActions"); titleEl.textContent = opts.title != null ? String(opts.title) : "Подтверждение"; bodyEl.textContent = message == null ? "" : String(message); setDialogVariant(dialog, opts.variant || "info"); actions.innerHTML = ""; var cancel = document.createElement("button"); cancel.type = "button"; cancel.className = "wesp-shell-dialog-btn"; cancel.textContent = opts.cancelText || "Отмена"; var ok = document.createElement("button"); ok.type = "button"; ok.className = "wesp-shell-dialog-btn " + (opts.danger ? "wesp-shell-dialog-btn-danger" : "wesp-shell-dialog-btn-primary"); ok.textContent = opts.okText || "Да"; cancel.addEventListener("click", function () { pendingResolve = null; pendingMode = null; hide(); resolve(false); }); ok.addEventListener("click", function () { pendingResolve = null; pendingMode = null; hide(); resolve(true); }); actions.appendChild(cancel); actions.appendChild(ok); pendingMode = "confirm"; pendingResolve = resolve; show(); ok.focus(); }); } global.WespDialog = { alert: alert, confirm: confirm, closeActive: closeActive, }; })(typeof window !== "undefined" ? window : globalThis);