重构 monorepo 并完善网页端订阅与首页体验
- 迁移为 frontend-web、frontend-electron、backend-web 与 docker 部署结构 - 网页端:订阅门禁二次弹窗、套餐/支付组件化、顶栏分组对齐 - 首页:最近文件与模板库布局优化,缩略图对齐,下载与删除操作 - 新增管理后台、支付与云端文件 API,更新 README 与项目规范 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var ALLOWED = /^(index\.web\.html|member\.web\.html|login\.web\.html|register\.web\.html|admin\/(?:index|login)\.html|index\.html|login\.html|design[12]\.web\.html)(\?.*)?$/i;
|
||||
|
||||
function soonEscapeHtml(s) {
|
||||
if (s == null) return '';
|
||||
return String(s)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
|
||||
function soonSafeRedirect(urlParam, fallback) {
|
||||
fallback = fallback || 'index.web.html';
|
||||
if (!urlParam || typeof urlParam !== 'string') return fallback;
|
||||
var raw = urlParam.trim();
|
||||
if (!raw) return fallback;
|
||||
try {
|
||||
raw = decodeURIComponent(raw);
|
||||
} catch (e) {
|
||||
return fallback;
|
||||
}
|
||||
var lower = raw.toLowerCase();
|
||||
if (lower.indexOf('//') === 0 || lower.indexOf('http:') === 0 || lower.indexOf('https:') === 0 ||
|
||||
lower.indexOf('javascript:') === 0 || raw.indexOf('..') !== -1 || raw.indexOf('\\') !== -1) {
|
||||
return fallback;
|
||||
}
|
||||
var pathOnly = raw.split(/[#?]/)[0];
|
||||
if (ALLOWED.test(pathOnly)) return raw;
|
||||
try {
|
||||
var resolved = new URL(raw, window.location.href);
|
||||
if (resolved.origin !== window.location.origin) return fallback;
|
||||
var path = resolved.pathname.replace(/^.*\/pages\//, '').replace(/^\//, '');
|
||||
if (!ALLOWED.test(path.split(/[#?]/)[0])) return fallback;
|
||||
return path + resolved.search + resolved.hash;
|
||||
} catch (e) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function soonSafeImageUrl(url, fallback) {
|
||||
if (!url || typeof url !== 'string') return fallback || '';
|
||||
var raw = url.trim();
|
||||
if (!raw) return fallback || '';
|
||||
var lower = raw.toLowerCase();
|
||||
if (lower.indexOf('javascript:') === 0 || lower.indexOf('data:text/html') === 0 ||
|
||||
lower.indexOf('vbscript:') === 0 || lower.indexOf('//') === 0) {
|
||||
return fallback || '';
|
||||
}
|
||||
if (lower.indexOf('data:image/') === 0) return raw;
|
||||
if (lower.indexOf('blob:') === 0) return raw;
|
||||
if (lower.indexOf('https:') === 0) return raw;
|
||||
if (lower.indexOf('http:') === 0) {
|
||||
try {
|
||||
var apiBase = (typeof window !== 'undefined' && window.SOON_DEPLOY_CONFIG && window.SOON_DEPLOY_CONFIG.api_v1_base);
|
||||
if (apiBase && new URL(raw).origin === new URL(apiBase).origin) return raw;
|
||||
} catch (e) { /* fall through */ }
|
||||
}
|
||||
if (raw.indexOf('../') === 0 || raw.indexOf('./') === 0 || raw.indexOf('/') === 0) {
|
||||
try {
|
||||
var resolved = new URL(raw, window.location.href);
|
||||
if (resolved.origin === window.location.origin) return raw;
|
||||
} catch (e) { /* fall through */ }
|
||||
}
|
||||
return fallback || '';
|
||||
}
|
||||
|
||||
window.soonEscapeHtml = soonEscapeHtml;
|
||||
window.soonSafeRedirect = soonSafeRedirect;
|
||||
window.soonSafeImageUrl = soonSafeImageUrl;
|
||||
})();
|
||||
Reference in New Issue
Block a user