Files
site/WESP_REL/static/js/kiosk-dialog.js
T
2026-07-17 12:57:18 +03:00

272 lines
9.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Диалоги для страниц киоска / разгрузки / отбора (терминал). Не подключать на зоотех-оболочку — там wesp-dialog.js (WespDialog).
* API: WespKioskDialog.alert(msg, opts?) -> Promise<void>
* WespKioskDialog.confirm(msg, opts?) -> Promise<boolean>
* opts.timerOnly — закрытие только через WespKioskDialog.closeActive() (таймер); без кнопки, без Escape и клика по фону.
*/
(function (global) {
var OVERLAY_ID = "wespKioskDialogOverlay";
var STYLE_ID = "wesp-kiosk-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;" +
"}" +
"#" +
OVERLAY_ID +
'[aria-hidden="false"]{display:flex;}' +
".wesp-kiosk-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:Inter,system-ui,sans-serif;" +
"text-align:left;" +
"}" +
".wesp-kiosk-dialog-title{" +
"margin:0 0 12px 0;font-size:1.125rem;font-weight:600;color:#111827;" +
"}" +
".wesp-kiosk-dialog-body{" +
"margin:0;font-size:0.95rem;line-height:1.5;color:#374151;white-space:pre-wrap;word-break:break-word;" +
"}" +
".wesp-kiosk-dialog-actions{" +
"display:flex;justify-content:flex-end;flex-wrap:wrap;gap:10px;margin-top:20px;" +
"}" +
".wesp-kiosk-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-kiosk-dialog-btn:hover{filter:brightness(.97);}" +
".wesp-kiosk-dialog-btn-primary{" +
"background:#2563eb;border-color:#2563eb;color:#fff;" +
"}" +
".wesp-kiosk-dialog-btn-primary:hover{box-shadow:0 4px 12px rgba(37,99,235,.25);}" +
".wesp-kiosk-dialog-btn-danger{" +
"background:#ef4444;border-color:#ef4444;color:#fff;" +
"}" +
".wesp-kiosk-dialog--danger{border-top:4px solid #ef4444;}" +
".wesp-kiosk-dialog--success{border-top:4px solid #10b981;}" +
"html[data-theme=dark] #" +
OVERLAY_ID +
" .wesp-kiosk-dialog{" +
"background:#242424;color:#e6e6e6;border-color:#3a3a3a;" +
"}" +
"html[data-theme=dark] #" +
OVERLAY_ID +
" .wesp-kiosk-dialog-title{color:#f3f4f6;}" +
"html[data-theme=dark] #" +
OVERLAY_ID +
" .wesp-kiosk-dialog-body{color:#d1d5db;}" +
"html[data-theme=dark] #" +
OVERLAY_ID +
" .wesp-kiosk-dialog-btn{" +
"background:#2d2d2d;border-color:#3a3a3a;color:#e6e6e6;" +
"}" +
"html[data-theme=dark] #" +
OVERLAY_ID +
" .wesp-kiosk-dialog-btn-primary{background:#2563eb;border-color:#2563eb;color:#fff;}" +
"html[data-theme=dark] #" +
OVERLAY_ID +
" .wesp-kiosk-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 =
'<div class="wesp-kiosk-dialog" role="dialog" aria-modal="true" aria-labelledby="wespKioskDialogTitle">' +
'<h2 class="wesp-kiosk-dialog-title" id="wespKioskDialogTitle"></h2>' +
'<p class="wesp-kiosk-dialog-body" id="wespKioskDialogBody"></p>' +
'<div class="wesp-kiosk-dialog-actions" id="wespKioskDialogActions"></div>' +
"</div>";
el.addEventListener("click", function (e) {
if (e.target === el) {
backdropDismiss();
}
});
document.body.appendChild(el);
return el;
}
var pendingResolve = null;
var pendingMode = null;
/** true: alert с opts.timerOnly — пользователь не закрывает окно вручную */
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 hide() {
var el = document.getElementById(OVERLAY_ID);
if (!el) return;
var dlg = el.querySelector(".wesp-kiosk-dialog");
if (dlg) dlg.removeAttribute("tabindex");
blockUserDismiss = false;
el.setAttribute("aria-hidden", "true");
document.removeEventListener("keydown", onKey);
}
/** Закрыть активный alert/confirm без клика (таймер, программное закрытие). */
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.setAttribute("aria-hidden", "false");
document.addEventListener("keydown", onKey);
}
function setDialogVariant(dialogEl, variant) {
dialogEl.classList.remove("wesp-kiosk-dialog--danger", "wesp-kiosk-dialog--success");
if (variant === "danger") dialogEl.classList.add("wesp-kiosk-dialog--danger");
else if (variant === "success") dialogEl.classList.add("wesp-kiosk-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-kiosk-dialog");
var titleEl = document.getElementById("wespKioskDialogTitle");
var bodyEl = document.getElementById("wespKioskDialogBody");
var actions = document.getElementById("wespKioskDialogActions");
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-kiosk-dialog-btn wesp-kiosk-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-kiosk-dialog");
var titleEl = document.getElementById("wespKioskDialogTitle");
var bodyEl = document.getElementById("wespKioskDialogBody");
var actions = document.getElementById("wespKioskDialogActions");
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-kiosk-dialog-btn";
cancel.textContent = opts.cancelText || "Отмена";
var ok = document.createElement("button");
ok.type = "button";
ok.className =
"wesp-kiosk-dialog-btn " +
(opts.danger ? "wesp-kiosk-dialog-btn-danger" : "wesp-kiosk-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.WespKioskDialog = {
alert: alert,
confirm: confirm,
closeActive: closeActive,
};
})(typeof window !== "undefined" ? window : globalThis);