refactor(modal): remove legacy compatibility paths
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bdfe3a461d
commit
34150f3358
18 files changed
+188
-380
No files matched your search
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Canonical frontend modal runtime.
|
||||
*
|
||||
* Keeps the existing remote-modal shell while adding cancellable loaders,
|
||||
* Owns the modal shell while adding cancellable loaders,
|
||||
* short in-memory caching, request deduplication, retryable errors, focus
|
||||
* restoration, and modal-scoped rehydration.
|
||||
*
|
||||
@@ -10,7 +10,7 @@
|
||||
(function (window, document) {
|
||||
"use strict";
|
||||
|
||||
var ROOT_ID = "aksrt-remote-modal-root";
|
||||
var ROOT_ID = "aksrt-modal-runtime-root";
|
||||
var active = null;
|
||||
var sequence = 0;
|
||||
var loaders = Object.create(null);
|
||||
@@ -24,7 +24,7 @@
|
||||
if (root) return root;
|
||||
root = document.createElement("div");
|
||||
root.id = ROOT_ID;
|
||||
root.className = "aksrt-remote-modal-host";
|
||||
root.className = "aksrt-modal-runtime-host";
|
||||
document.body.appendChild(root);
|
||||
return root;
|
||||
}
|
||||
@@ -39,31 +39,28 @@
|
||||
}
|
||||
|
||||
function lockScroll(lock) {
|
||||
document.documentElement.classList.toggle("aksrt-remote-modal-open", !!lock);
|
||||
document.body.classList.toggle("aksrt-remote-modal-open", !!lock);
|
||||
document.documentElement.classList.toggle("aksrt-modal-runtime-open", !!lock);
|
||||
document.body.classList.toggle("aksrt-modal-runtime-open", !!lock);
|
||||
}
|
||||
|
||||
function skeleton(options) {
|
||||
return (options && options.skeleton) ||
|
||||
'<div class="aksrt-remote-modal__skeleton" aria-live="polite" aria-busy="true">' +
|
||||
'<span class="aksrt-remote-modal__skeleton-line is-wide"></span>' +
|
||||
'<span class="aksrt-remote-modal__skeleton-line"></span>' +
|
||||
'<span class="aksrt-remote-modal__skeleton-line is-short"></span>' +
|
||||
'<span class="aksrt-remote-modal__skeleton-block"></span>' +
|
||||
'<div class="aksrt-modal-runtime__skeleton" aria-live="polite" aria-busy="true">' +
|
||||
'<span class="aksrt-modal-runtime__skeleton-line is-wide"></span>' +
|
||||
'<span class="aksrt-modal-runtime__skeleton-line"></span>' +
|
||||
'<span class="aksrt-modal-runtime__skeleton-line is-short"></span>' +
|
||||
'<span class="aksrt-modal-runtime__skeleton-block"></span>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function telemetryStart(kind) {
|
||||
if (kind === false) return "";
|
||||
var telemetry = window.AksrtModalTelemetry;
|
||||
if (!telemetry || typeof telemetry.start !== "function") return "";
|
||||
return telemetry.start(kind || "unknown");
|
||||
return window.AksrtModalTelemetry.start(kind || "generic");
|
||||
}
|
||||
|
||||
function telemetryMark(session, event) {
|
||||
var telemetry = window.AksrtModalTelemetry;
|
||||
if (!session || !session.telemetryId || !telemetry || typeof telemetry.mark !== "function") return;
|
||||
telemetry.mark(session.telemetryId, event);
|
||||
if (!session || !session.telemetryId) return;
|
||||
window.AksrtModalTelemetry.mark(session.telemetryId, event);
|
||||
}
|
||||
|
||||
function setState(session, status, error) {
|
||||
@@ -81,7 +78,7 @@
|
||||
}
|
||||
|
||||
function closeSelector() {
|
||||
return "[data-aksrt-remote-modal-close], [data-aksrt-modal-close], [data-dismiss='modal'], .aksrt-remote-modal__close, .aksrt-vip-modal-close, .payvip-modal .close";
|
||||
return "[data-aksrt-modal-close], .aksrt-modal-runtime__close";
|
||||
}
|
||||
|
||||
function bindChrome(session) {
|
||||
@@ -93,11 +90,11 @@
|
||||
close("control");
|
||||
return;
|
||||
}
|
||||
if (event.target === shell || event.target.classList.contains("aksrt-remote-modal__overlay")) {
|
||||
if (event.target === shell || event.target.classList.contains("aksrt-modal-runtime__overlay")) {
|
||||
close("overlay");
|
||||
return;
|
||||
}
|
||||
var retry = event.target.closest("[data-aksrt-remote-modal-retry], [data-aksrt-modal-retry]");
|
||||
var retry = event.target.closest("[data-aksrt-modal-retry]");
|
||||
if (retry) {
|
||||
event.preventDefault();
|
||||
refresh();
|
||||
@@ -138,31 +135,29 @@
|
||||
var initialHtml = options.html !== undefined ? options.html : skeleton(options);
|
||||
var titleId = "aksrt-modal-title-" + String(sequence + 1);
|
||||
var titleHtml = options.title
|
||||
? '<header class="aksrt-remote-modal__header"><h3 class="aksrt-remote-modal__title" id="' + titleId + '">' + escapeHtml(options.title) + '</h3><button type="button" class="aksrt-remote-modal__close" data-aksrt-modal-close aria-label="关闭">×</button></header>'
|
||||
? '<header class="aksrt-modal-runtime__header"><h3 class="aksrt-modal-runtime__title" id="' + titleId + '">' + escapeHtml(options.title) + '</h3><button type="button" class="aksrt-modal-runtime__close" data-aksrt-modal-close aria-label="关闭">×</button></header>'
|
||||
: "";
|
||||
|
||||
shell.className =
|
||||
"aksrt-remote-modal" +
|
||||
(bottom ? " aksrt-remote-modal--bottom" : "") +
|
||||
"aksrt-modal-runtime" +
|
||||
(bottom ? " aksrt-modal-runtime--bottom" : "") +
|
||||
(options.className ? " " + options.className : "");
|
||||
shell.setAttribute("role", "dialog");
|
||||
shell.setAttribute("aria-modal", "true");
|
||||
if (options.title) shell.setAttribute("aria-labelledby", titleId);
|
||||
shell.setAttribute("tabindex", "-1");
|
||||
shell.innerHTML =
|
||||
'<div class="aksrt-remote-modal__overlay" data-aksrt-remote-modal-close></div>' +
|
||||
'<div class="aksrt-remote-modal__dialog" style="' + heightStyle + '">' +
|
||||
'<div class="aksrt-modal-runtime__overlay" data-aksrt-modal-close></div>' +
|
||||
'<div class="aksrt-modal-runtime__dialog" style="' + heightStyle + '">' +
|
||||
titleHtml +
|
||||
'<div class="aksrt-remote-modal__content">' + initialHtml + "</div></div>";
|
||||
'<div class="aksrt-modal-runtime__content">' + initialHtml + "</div></div>";
|
||||
|
||||
var session = {
|
||||
id: String(++sequence),
|
||||
shell: shell,
|
||||
content: shell.querySelector(".aksrt-remote-modal__content"),
|
||||
content: shell.querySelector(".aksrt-modal-runtime__content"),
|
||||
options: options,
|
||||
state: window.AksrtModalState && typeof window.AksrtModalState.create === "function"
|
||||
? window.AksrtModalState.create(options.kind || "generic")
|
||||
: { status: "idle", error: null },
|
||||
state: window.AksrtModalState.create(options.kind || "generic"),
|
||||
focusReturn: document.activeElement,
|
||||
controller: null,
|
||||
flight: null,
|
||||
@@ -184,9 +179,6 @@
|
||||
(nodes.length ? nodes[0] : shell).focus();
|
||||
} catch (error) {}
|
||||
|
||||
document.dispatchEvent(new CustomEvent("aksrt:remote-modal:open", {
|
||||
detail: { shell: shell, options: options, session: session },
|
||||
}));
|
||||
document.dispatchEvent(new CustomEvent("aksrt:modal:open", {
|
||||
detail: { shell: shell, options: options, session: session },
|
||||
}));
|
||||
@@ -203,9 +195,7 @@
|
||||
|
||||
function rehydrate(session) {
|
||||
if (!session || !session.content) return;
|
||||
if (window.AksrtFrontend && typeof window.AksrtFrontend.rehydrate === "function") {
|
||||
window.AksrtFrontend.rehydrate(session.content, "modal");
|
||||
}
|
||||
window.AksrtFrontend.rehydrate(session.content, "modal");
|
||||
}
|
||||
|
||||
function abortSessionRequest(session) {
|
||||
@@ -226,9 +216,6 @@
|
||||
if (!preserveRequest) abortSessionRequest(session);
|
||||
session.shell.classList.remove("is-open");
|
||||
if (!preserveRequest) lockScroll(false);
|
||||
document.dispatchEvent(new CustomEvent("aksrt:remote-modal:close", {
|
||||
detail: { shell: session.shell, reason: reason || "close", session: session },
|
||||
}));
|
||||
document.dispatchEvent(new CustomEvent("aksrt:modal:close", {
|
||||
detail: { shell: session.shell, reason: reason || "close", session: session },
|
||||
}));
|
||||
@@ -249,8 +236,6 @@
|
||||
if (json) {
|
||||
if (typeof json.html === "string") return json.html;
|
||||
if (json.data && typeof json.data.html === "string") return json.data.html;
|
||||
if (json.data && typeof json.data.show_modal === "string") return json.data.show_modal;
|
||||
if (typeof json.data === "string") return json.data;
|
||||
}
|
||||
return typeof result.text === "string" ? result.text : "";
|
||||
}
|
||||
@@ -266,11 +251,11 @@
|
||||
setState(session, unauthorized ? "unauthorized" : "error", error);
|
||||
telemetryMark(session, unauthorized ? "unauthorized" : "error");
|
||||
session.content.innerHTML =
|
||||
'<div class="aksrt-remote-modal__error touch border-title"><b>提示</b></div>' +
|
||||
'<div class="aksrt-remote-modal__error-body">' + escapeHtml(errorMessage(error)) +
|
||||
'<div class="aksrt-modal-runtime__error touch border-title"><b>提示</b></div>' +
|
||||
'<div class="aksrt-modal-runtime__error-body">' + escapeHtml(errorMessage(error)) +
|
||||
'</div><div class="but-average modal-buts">' +
|
||||
'<button type="button" class="but" data-aksrt-remote-modal-retry>重试</button>' +
|
||||
'<button type="button" class="but" data-aksrt-remote-modal-close>关闭</button></div>';
|
||||
'<button type="button" class="but" data-aksrt-modal-retry>重试</button>' +
|
||||
'<button type="button" class="but" data-aksrt-modal-close>关闭</button></div>';
|
||||
rehydrate(session);
|
||||
if (typeof session.options.onError === "function") session.options.onError(error, session);
|
||||
}
|
||||
@@ -282,7 +267,7 @@
|
||||
setState(session, "empty");
|
||||
telemetryMark(session, "first-content");
|
||||
telemetryMark(session, "ready");
|
||||
session.content.innerHTML = '<div class="aksrt-remote-modal__error-body">暂无内容</div>';
|
||||
session.content.innerHTML = '<div class="aksrt-modal-runtime__error-body">暂无内容</div>';
|
||||
return;
|
||||
}
|
||||
session.content.innerHTML = html;
|
||||
@@ -311,21 +296,14 @@
|
||||
if (requestOptions.body === undefined) delete requestOptions.body;
|
||||
if (!requestOptions.signal) delete requestOptions.signal;
|
||||
|
||||
var request = window.AksrtRequest && typeof window.AksrtRequest.request === "function"
|
||||
? function () { return window.AksrtRequest.request(session.options.url, requestOptions); }
|
||||
: function () {
|
||||
return window.fetch(session.options.url, requestOptions).then(function (response) {
|
||||
return response.text().then(function (text) { return { ok: response.ok, status: response.status, text: text, json: null }; });
|
||||
});
|
||||
};
|
||||
var request = function () {
|
||||
return window.AksrtRequest.request(session.options.url, requestOptions);
|
||||
};
|
||||
|
||||
var method = String(session.options.method || "GET").toUpperCase();
|
||||
var cacheable = method === "GET" && session.options.cache !== false;
|
||||
var cacheKey = session.options.cacheKey ||
|
||||
method + ":" +
|
||||
(window.AksrtRequest && typeof window.AksrtRequest.url === "function"
|
||||
? window.AksrtRequest.url(session.options.url, session.options.query)
|
||||
: session.options.url);
|
||||
method + ":" + window.AksrtRequest.url(session.options.url, session.options.query);
|
||||
var cache = window.AksrtModalCache;
|
||||
var acquireOptions = {
|
||||
ttl: Number(session.options.cacheTtl || 15000),
|
||||
@@ -339,7 +317,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
session.flight = cacheable && cache && typeof cache.acquire === "function"
|
||||
session.flight = cacheable
|
||||
? cache.acquire(cacheKey, request, acquireOptions)
|
||||
: { promise: request(), release: function () {} };
|
||||
|
||||
@@ -367,9 +345,7 @@
|
||||
function sessionKey(options) {
|
||||
if (!options || !options.url) return "";
|
||||
var method = String(options.method || "GET").toUpperCase();
|
||||
var requestUrl = window.AksrtRequest && typeof window.AksrtRequest.url === "function"
|
||||
? window.AksrtRequest.url(options.url, options.query)
|
||||
: String(options.url);
|
||||
var requestUrl = window.AksrtRequest.url(options.url, options.query);
|
||||
return method + ":" + requestUrl;
|
||||
}
|
||||
|
||||
@@ -400,10 +376,7 @@
|
||||
}
|
||||
|
||||
function invalidate(tags) {
|
||||
if (window.AksrtModalCache && typeof window.AksrtModalCache.invalidate === "function") {
|
||||
return window.AksrtModalCache.invalidate(tags);
|
||||
}
|
||||
return 0;
|
||||
return window.AksrtModalCache.invalidate(tags);
|
||||
}
|
||||
|
||||
window.AksrtModalRuntime = {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Declarative modal triggers.
|
||||
*
|
||||
* The only modal entry point is AksrtModalRuntime. Triggers carry an
|
||||
* explicit URL and never create a second modal implementation.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
(function (window, document) {
|
||||
"use strict";
|
||||
|
||||
function openFromTrigger(element) {
|
||||
var runtime = window.AksrtModalRuntime;
|
||||
var url = element.getAttribute("data-aksrt-modal-url") || "";
|
||||
if (!url || url === "#") return;
|
||||
|
||||
var ttl = parseInt(element.getAttribute("data-aksrt-modal-cache-ttl") || "15000", 10);
|
||||
var tags = (element.getAttribute("data-aksrt-modal-cache-tags") || "").split(",").map(function (tag) {
|
||||
return tag.trim();
|
||||
}).filter(Boolean);
|
||||
|
||||
runtime.openRemote({
|
||||
url: url,
|
||||
method: element.getAttribute("data-aksrt-modal-method") || "GET",
|
||||
className: element.getAttribute("data-aksrt-modal-class") || "modal-mini full-sm",
|
||||
height: parseInt(element.getAttribute("data-aksrt-modal-height") || "0", 10) || 0,
|
||||
mobileBottom: element.getAttribute("data-aksrt-modal-mobile-bottom") === "true",
|
||||
bottom: element.getAttribute("data-aksrt-modal-bottom") === "true",
|
||||
kind: element.getAttribute("data-aksrt-modal-kind") || "generic",
|
||||
cacheKey: element.getAttribute("data-aksrt-modal-cache-key") || "",
|
||||
cacheTtl: ttl > 0 ? ttl : 15000,
|
||||
cacheTags: tags,
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", function (event) {
|
||||
var trigger = event.target.closest('[data-aksrt-modal="remote"]');
|
||||
if (!trigger) return;
|
||||
event.preventDefault();
|
||||
openFromTrigger(trigger);
|
||||
});
|
||||
})(window, document);
|
||||
@@ -1,77 +0,0 @@
|
||||
/**
|
||||
* AKSRT Remote Modal compatibility bridge.
|
||||
*
|
||||
* The lifecycle implementation lives in AksrtModalRuntime. This file keeps
|
||||
* the legacy trigger contract and the AksrtRemoteModal public alias stable.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
(function (window, document) {
|
||||
"use strict";
|
||||
|
||||
function runtime() {
|
||||
return window.AksrtModalRuntime || null;
|
||||
}
|
||||
|
||||
function fromTrigger(element) {
|
||||
var modalRuntime = runtime();
|
||||
if (!modalRuntime || !element) return Promise.reject(new Error("modal runtime unavailable"));
|
||||
|
||||
var url = element.getAttribute("data-remote") ||
|
||||
element.getAttribute("data-aksrt-remote") ||
|
||||
element.getAttribute("href") || "";
|
||||
if (!url || url === "#") return Promise.resolve(null);
|
||||
|
||||
var ttl = parseInt(element.getAttribute("data-modal-cache-ttl") || "15000", 10);
|
||||
var tags = (element.getAttribute("data-modal-cache-tags") || "").split(",").map(function (tag) {
|
||||
return tag.trim();
|
||||
}).filter(Boolean);
|
||||
|
||||
return modalRuntime.openRemote({
|
||||
url: url,
|
||||
method: element.getAttribute("data-method") || "GET",
|
||||
className: element.getAttribute("data-class") || element.getAttribute("data-aksrt-class") || "modal-mini full-sm",
|
||||
height: parseInt(element.getAttribute("data-height") || element.getAttribute("data-aksrt-height") || "0", 10) || 0,
|
||||
mobileBottom: element.getAttribute("mobile-bottom") !== "false",
|
||||
bottom: element.getAttribute("data-bottom") === "true",
|
||||
kind: element.getAttribute("data-modal-kind") || "generic",
|
||||
cacheKey: element.getAttribute("data-modal-cache-key") || "",
|
||||
cacheTtl: ttl > 0 ? ttl : 15000,
|
||||
cacheTags: tags,
|
||||
});
|
||||
}
|
||||
|
||||
function bind() {
|
||||
if (window.__aksrtRemoteModalBound) return;
|
||||
if (!runtime()) return;
|
||||
window.__aksrtRemoteModalBound = true;
|
||||
|
||||
document.addEventListener("click", function (event) {
|
||||
var trigger = event.target.closest(
|
||||
'[data-toggle="AksrtRemoteModal"], [data-toggle="RefreshModal"], [data-aksrt-remote-modal], a.aksrt-remote-modal-link'
|
||||
);
|
||||
if (!trigger || trigger.getAttribute("data-aksrt-remote-modal") === "off") return;
|
||||
event.preventDefault();
|
||||
fromTrigger(trigger);
|
||||
});
|
||||
}
|
||||
|
||||
function expose() {
|
||||
var modalRuntime = runtime();
|
||||
if (!modalRuntime) return;
|
||||
window.AksrtRemoteModal = {
|
||||
open: modalRuntime.open,
|
||||
openRemote: modalRuntime.openRemote,
|
||||
close: modalRuntime.close,
|
||||
refresh: modalRuntime.refresh,
|
||||
fromTrigger: fromTrigger,
|
||||
getActive: modalRuntime.getActive,
|
||||
};
|
||||
bind();
|
||||
}
|
||||
|
||||
expose();
|
||||
if (!window.AksrtModalRuntime) {
|
||||
document.addEventListener("aksrt:modal-runtime:ready", expose, { once: true });
|
||||
}
|
||||
})(window, document);
|
||||
Reference in new issue
Block a user