/** * AKSRT Remote Modal — zibll RefreshModal parity. * * Open a center/bottom modal with static HTML or remote fetch. * Contract: * - data-toggle="AksrtRemoteModal" | data-aksrt-remote-modal * - data-remote / href → fetch HTML * - data-class → dialog class (modal-mini full-sm …) * - data-height → min-height hint * - mobile-bottom="true" → bottom sheet on narrow viewports * * @package AKSRT */ (function (window, document) { "use strict"; var ROOT_ID = "aksrt-remote-modal-root"; var active = null; function isMobile() { return window.matchMedia && window.matchMedia("(max-width: 768px)").matches; } function ensureRoot() { var root = document.getElementById(ROOT_ID); if (root) return root; root = document.createElement("div"); root.id = ROOT_ID; root.className = "aksrt-remote-modal-host"; document.body.appendChild(root); return root; } function restHeaders() { var h = { Accept: "text/html, application/json" }; if (window.aksrtData && aksrtData.restNonce) { h["X-WP-Nonce"] = aksrtData.restNonce; } return h; } function lockScroll(lock) { document.documentElement.classList.toggle("aksrt-remote-modal-open", !!lock); document.body.classList.toggle("aksrt-remote-modal-open", !!lock); } function close() { if (!active) return; active.classList.remove("is-open"); lockScroll(false); var node = active; active = null; window.setTimeout(function () { if (node && node.parentNode) node.parentNode.removeChild(node); }, 220); document.dispatchEvent(new CustomEvent("aksrt:remote-modal:close")); } function bindChrome(shell) { shell.addEventListener("click", function (e) { if (e.target.closest("[data-aksrt-remote-modal-close], [data-dismiss='modal'], .aksrt-remote-modal__close")) { e.preventDefault(); close(); return; } if (e.target === shell || e.target.classList.contains("aksrt-remote-modal__overlay")) { close(); } }); shell.addEventListener("keydown", function (e) { if (e.key === "Escape") close(); }); } function open(options) { options = options || {}; close(); var root = ensureRoot(); var shell = document.createElement("div"); var bottom = options.bottom === true || (options.mobileBottom !== false && isMobile()); shell.className = "aksrt-remote-modal" + (bottom ? " aksrt-remote-modal--bottom" : "") + (options.className ? " " + options.className : ""); shell.setAttribute("role", "dialog"); shell.setAttribute("aria-modal", "true"); var heightStyle = options.height ? "min-height:" + parseInt(options.height, 10) + "px;" : ""; shell.innerHTML = '
' + '
' + '
' + (options.html || "") + "
"; root.appendChild(shell); bindChrome(shell); active = shell; lockScroll(true); // Force reflow then open for CSS transition. void shell.offsetWidth; shell.classList.add("is-open"); var focusable = shell.querySelector( "button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])" ); if (focusable) { try { focusable.focus(); } catch (err) {} } document.dispatchEvent( new CustomEvent("aksrt:remote-modal:open", { detail: { shell: shell, options: options } }) ); return shell; } function openRemote(options) { options = options || {}; var url = options.url || ""; if (!url) return Promise.reject(new Error("missing url")); var loading = open({ html: '
' + ((window.aksrtData && aksrtData.ajaxLoading) || "加载中…") + "
", className: options.className || "modal-mini full-sm", bottom: options.bottom, mobileBottom: options.mobileBottom, height: options.height, }); return fetch(url, { method: options.method || "GET", credentials: "same-origin", headers: Object.assign(restHeaders(), options.headers || {}), body: options.body, }) .then(function (res) { var type = (res.headers.get("content-type") || "").toLowerCase(); if (type.indexOf("application/json") !== -1) { return res.json().then(function (json) { if (!res.ok || (json && json.success === false)) { var msg = (json && (json.message || (json.data && json.data.message))) || "加载失败"; throw new Error(msg); } var html = (json && (json.html || (json.data && (json.data.html || json.data)))) || ""; if (typeof html !== "string") html = ""; return html; }); } return res.text().then(function (text) { if (!res.ok) throw new Error("加载失败"); return text; }); }) .then(function (html) { if (loading && loading.parentNode) loading.parentNode.removeChild(loading); if (active === loading) active = null; return open({ html: html, className: options.className || "modal-mini full-sm", bottom: options.bottom, mobileBottom: options.mobileBottom, height: options.height, }); }) .catch(function (err) { if (loading && loading.parentNode) loading.parentNode.removeChild(loading); if (active === loading) active = null; open({ html: '
提示
' + '
' + (err && err.message ? String(err.message) : "加载失败") + '
', className: "modal-mini", mobileBottom: true, }); throw err; }); } function fromTrigger(el) { if (!el) return null; var url = el.getAttribute("data-remote") || el.getAttribute("data-aksrt-remote") || el.getAttribute("href") || ""; if (!url || url === "#") return null; var height = el.getAttribute("data-height") || el.getAttribute("data-aksrt-height"); return openRemote({ url: url, className: el.getAttribute("data-class") || el.getAttribute("data-aksrt-class") || "modal-mini full-sm", height: height ? parseInt(height, 10) : 0, mobileBottom: el.getAttribute("mobile-bottom") !== "false", bottom: el.getAttribute("data-bottom") === "true", }); } document.addEventListener("click", function (e) { var trigger = e.target.closest( '[data-toggle="AksrtRemoteModal"], [data-toggle="RefreshModal"], [data-aksrt-remote-modal], a.aksrt-remote-modal-link' ); if (!trigger) return; if (trigger.getAttribute("data-aksrt-remote-modal") === "off") return; e.preventDefault(); fromTrigger(trigger); }); document.addEventListener("keydown", function (e) { if (e.key === "Escape" && active) close(); }); window.AksrtRemoteModal = { open: open, openRemote: openRemote, close: close, fromTrigger: fromTrigger, getActive: function () { return active; }, }; })(window, document);