Files
web_huangguo_web/app/static/js/pages/dialogLoader.js
T
fish03andClaude Opus 5.5 bef9f8b4ed Initial commit
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 14:43:16 +07:00

244 lines
7.6 KiB
JavaScript

(function (global) {
var definitions = {
download: {
endpoint: "/ui/dialog/download",
elementId: "downloadAppDialog",
css: "/static/css/downloadAppDialog.css?v=2",
js: "/static/js/pages/downloadAppDialog.js?v=4",
open: "openDownloadAppDialog",
},
login: {
endpoint: "/ui/dialog/login",
elementId: "loginDialog",
css: "/static/css/loginDialog.css?v=2",
js: "/static/js/pages/loginDialog.js?v=3",
open: "openLoginDialog",
},
register: {
endpoint: "/ui/dialog/register",
elementId: "registerDialog",
css: "/static/css/registerDialog.css?v=2",
js: "/static/js/pages/registerDialog.js?v=2",
open: "openRegisterDialog",
},
};
var pending = Object.create(null);
var stubOpeners = Object.create(null);
function hasRealOpener(name) {
var definition = definitions[name];
return (
!!definition &&
typeof global[definition.open] === "function" &&
global[definition.open] !== stubOpeners[name]
);
}
function loadStylesheet(href) {
var existing = document.querySelector('link[rel="stylesheet"][href="' + href + '"]');
if (existing) return Promise.resolve();
return new Promise(function (resolve, reject) {
var link = document.createElement("link");
var settled = false;
function finish(ok, err) {
if (settled) return;
settled = true;
if (ok) resolve();
else reject(err || new Error("dialog stylesheet failed"));
}
link.rel = "stylesheet";
link.href = href;
link.onload = function () {
finish(true);
};
link.onerror = function () {
finish(false, new Error("dialog stylesheet failed"));
};
document.head.appendChild(link);
// 部分浏览器对缓存 CSS 不触发 onload,避免一直卡住弹窗
requestAnimationFrame(function () {
try {
if (link.sheet) finish(true);
} catch (e) {}
});
setTimeout(function () {
finish(true);
}, 1500);
});
}
function loadScript(src) {
var existing = document.querySelector('script[src="' + src + '"]');
if (existing) {
if (existing.getAttribute("data-loaded") === "1") return Promise.resolve();
return new Promise(function (resolve, reject) {
existing.addEventListener("load", resolve, { once: true });
existing.addEventListener("error", function () {
reject(new Error("dialog script failed"));
}, { once: true });
});
}
return new Promise(function (resolve, reject) {
var script = document.createElement("script");
script.src = src;
script.async = true;
script.onload = function () {
script.setAttribute("data-loaded", "1");
resolve();
};
script.onerror = function () {
reject(new Error("dialog script failed"));
};
document.head.appendChild(script);
});
}
function fetchFragment(definition) {
if (document.getElementById(definition.elementId)) {
return Promise.resolve();
}
return fetch(definition.endpoint, {
credentials: "same-origin",
headers: { "X-Requested-With": "XMLHttpRequest" },
}).then(function (response) {
if (!response.ok) throw new Error("dialog fragment failed");
return response.text();
}).then(function (html) {
if (document.getElementById(definition.elementId)) return;
var host = document.createElement("div");
host.innerHTML = html;
var dialog = host.querySelector("#" + definition.elementId);
if (!dialog) throw new Error("dialog fragment is invalid");
document.body.appendChild(dialog);
});
}
function ensureDialog(name) {
var definition = definitions[name];
if (!definition) return Promise.reject(new Error("unknown dialog"));
if (document.getElementById(definition.elementId) && hasRealOpener(name)) {
return Promise.resolve();
}
if (pending[name]) return pending[name];
pending[name] = loadStylesheet(definition.css)
.then(function () {
return fetchFragment(definition);
})
.then(function () {
if (hasRealOpener(name)) return;
return loadScript(definition.js);
})
.then(function () {
if (!document.getElementById(definition.elementId) || !hasRealOpener(name)) {
throw new Error("dialog opener is unavailable");
}
})
.catch(function (error) {
delete pending[name];
throw error;
});
return pending[name];
}
function loginFallbackURL() {
var redirect = "";
try {
redirect = global.location.pathname || "/";
} catch (e) {
redirect = "/";
}
var url = "/login/";
if (
typeof redirect === "string" &&
redirect.charAt(0) === "/" &&
redirect.charAt(1) !== "/" &&
redirect !== "/" &&
redirect.indexOf("/?auth=") !== 0
) {
url = "/login/return" + redirect;
}
return url;
}
function openDialog(name, value) {
return ensureDialog(name)
.then(function () {
var opener = global[definitions[name].open];
if (typeof opener !== "function" || opener === stubOpeners[name]) {
throw new Error("dialog opener is unavailable");
}
return opener(value);
})
.catch(function (error) {
if (name === "login") {
try {
var params = new URLSearchParams(global.location.search || "");
// 已在登录入口仍失败时避免死循环跳转
if (params.get("auth") !== "login") {
global.location.href = loginFallbackURL();
}
} catch (e) {}
}
throw error;
});
}
Object.keys(definitions).forEach(function (name) {
var apiName = definitions[name].open;
var stub = function (value) {
return openDialog(name, value);
};
stubOpeners[name] = stub;
if (typeof global[apiName] !== "function") global[apiName] = stub;
});
function triggerName(target) {
if (!target || !target.closest) return "";
if (target.closest("[data-download-app-open]")) return "download";
if (target.closest("[data-register-dialog-open], a[href=\"#register\"], a[href=\"/register/\"]")) {
return "register";
}
if (target.closest("[data-login-dialog-open], a[href=\"#login\"], a[href=\"/login/\"]")) {
return "login";
}
return "";
}
function isMobileViewport() {
return typeof global.matchMedia === "function"
? global.matchMedia("(max-width: 767px)").matches
: (global.innerWidth || 0) <= 767;
}
document.addEventListener("click", function (event) {
var name = triggerName(event.target);
if (!name) return;
// 移动端下载入口保留原生链接行为,直接访问 appAddr,不加载下载弹窗。
if (name === "download" && isMobileViewport()) return;
event.preventDefault();
event.stopPropagation();
if (event.stopImmediatePropagation) event.stopImmediatePropagation();
openDialog(name).catch(function () {});
}, true);
function openFromLocation() {
var params = new URLSearchParams(global.location.search || "");
var auth = params.get("auth");
if (auth === "login" || auth === "register") {
openDialog(auth).catch(function () {});
return;
}
if (global.location.hash === "#login") openDialog("login").catch(function () {});
if (global.location.hash === "#register") openDialog("register").catch(function () {});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", openFromLocation, { once: true });
} else {
openFromLocation();
}
global.ensureDialog = ensureDialog;
})(window);