4ce4486b26
新增 IndexedDB 与最近文件 L1 缓存、云保存/打开链路;首页支持下载与清空本地缓存;修复清空 storage 后语言初始化报错;优化 design2 背景加载与侧栏标签样式;完善会员激活/支付弹层样式;后端补充文件缩略图字段与 thumb 接口。 Co-authored-by: Cursor <cursoragent@cursor.com>
160 lines
4.8 KiB
JavaScript
160 lines
4.8 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
function computeAssetBase() {
|
|
if (typeof window === 'undefined' || !window.location) {
|
|
return 'assets/images/';
|
|
}
|
|
var p = window.location.pathname || '/';
|
|
if (p.indexOf('/pages/') !== -1 || /\.web\.html$/i.test(p) || /\/pages\/[^/]+\.html$/i.test(p)) {
|
|
return '../assets/images/';
|
|
}
|
|
if (p.endsWith('/pages/') || p.endsWith('/pages')) {
|
|
return '../assets/images/';
|
|
}
|
|
return 'assets/images/';
|
|
}
|
|
|
|
function computeJsBase() {
|
|
if (typeof window === 'undefined' || !window.location) {
|
|
return 'js/';
|
|
}
|
|
var p = window.location.pathname || '/';
|
|
if (p.indexOf('/pages/') !== -1 || /\.web\.html$/i.test(p) || /\/pages\/[^/]+\.html$/i.test(p)) {
|
|
return '../js/';
|
|
}
|
|
return 'js/';
|
|
}
|
|
|
|
window.SOON_ASSET_BASE = computeAssetBase();
|
|
window.SOON_JS_BASE = computeJsBase();
|
|
|
|
window.soonAsset = function (name) {
|
|
var n = String(name || '').replace(/^\/+/, '');
|
|
return window.SOON_ASSET_BASE + n;
|
|
};
|
|
|
|
window.soonJs = function (rel) {
|
|
var n = String(rel || '').replace(/^\/+/, '');
|
|
return window.SOON_JS_BASE + n;
|
|
};
|
|
|
|
/** 等 HTMLImage 解码完成后再 toDataURL / setSrc,避免间歇性空白背景 */
|
|
window.soonFabricImageWhenReady = function (image, cb, skipEmbed) {
|
|
if (!image) {
|
|
if (typeof cb === 'function') cb(null);
|
|
return;
|
|
}
|
|
function finalize() {
|
|
if (skipEmbed) {
|
|
if (typeof cb === 'function') cb(image);
|
|
return;
|
|
}
|
|
try {
|
|
var dataUrl = image.toDataURL();
|
|
if (dataUrl && dataUrl.length > 500) {
|
|
image.setSrc(dataUrl, function (img) {
|
|
if (typeof cb === 'function') cb(img || image);
|
|
});
|
|
return;
|
|
}
|
|
} catch (e) { /* ignore */ }
|
|
if (typeof cb === 'function') cb(image);
|
|
}
|
|
var el = image.getElement ? image.getElement() : null;
|
|
if (!el) {
|
|
finalize();
|
|
return;
|
|
}
|
|
if (el.complete && el.naturalWidth > 0) {
|
|
finalize();
|
|
return;
|
|
}
|
|
el.onload = function () { finalize(); };
|
|
el.onerror = function () {
|
|
if (typeof cb === 'function') cb(null);
|
|
};
|
|
};
|
|
|
|
window.soonFabricImageFromAsset = function (assetName, onReady, onFail, retryLeft, skipEmbed) {
|
|
if (typeof fabric === 'undefined' || !fabric.Image) {
|
|
if (typeof onFail === 'function') onFail();
|
|
return;
|
|
}
|
|
var retries = retryLeft == null ? 2 : retryLeft;
|
|
var url = window.soonAsset(assetName);
|
|
fabric.Image.fromURL(url, function (image) {
|
|
if (!image || !image.width) {
|
|
if (retries > 0) {
|
|
setTimeout(function () {
|
|
window.soonFabricImageFromAsset(assetName, onReady, onFail, retries - 1, skipEmbed);
|
|
}, 150);
|
|
return;
|
|
}
|
|
if (typeof onFail === 'function') onFail();
|
|
return;
|
|
}
|
|
function deliver(img) {
|
|
if (img && typeof onReady === 'function') onReady(img);
|
|
else if (retries > 0) {
|
|
setTimeout(function () {
|
|
window.soonFabricImageFromAsset(assetName, onReady, onFail, retries - 1, skipEmbed);
|
|
}, 150);
|
|
} else if (typeof onFail === 'function') onFail();
|
|
}
|
|
if (skipEmbed) {
|
|
window.soonFabricImageWhenReady(image, deliver, true);
|
|
return;
|
|
}
|
|
window.soonFabricImageWhenReady(image, deliver);
|
|
}, null, { crossOrigin: 'anonymous' });
|
|
};
|
|
|
|
window.soonRunWhenCanvasReady = function (selector, fn) {
|
|
function tryRun() {
|
|
var el = typeof selector === 'string' ? document.querySelector(selector) : selector;
|
|
var w = el ? (el.clientWidth || el.width || 0) : 0;
|
|
if ((!w || w < 50) && window.SOON_DEPLOY_CONFIG) {
|
|
requestAnimationFrame(function () {
|
|
requestAnimationFrame(tryRun);
|
|
});
|
|
return;
|
|
}
|
|
if (typeof fn === 'function') fn(w || 800);
|
|
}
|
|
tryRun();
|
|
};
|
|
|
|
var SOON_LOCALE_CODES = { zh: 1, ozh: 1, en: 1 };
|
|
|
|
window.soonNormalizeLocaleCode = function (loc) {
|
|
if (!loc) return 'zh';
|
|
if (SOON_LOCALE_CODES[loc]) return loc;
|
|
var s = String(loc);
|
|
if (s.indexOf('zh') === 0) return s.indexOf('TW') >= 0 ? 'ozh' : 'zh';
|
|
return 'en';
|
|
};
|
|
|
|
window.soonResolveLocale = function (cb) {
|
|
if (typeof cb !== 'function') return;
|
|
var stored;
|
|
try { stored = localStorage.getItem('lang'); } catch (e) { stored = null; }
|
|
if (stored && SOON_LOCALE_CODES[stored]) {
|
|
cb(stored);
|
|
return;
|
|
}
|
|
var bridge = window.platformBridge;
|
|
if (!bridge || typeof bridge.getLocale !== 'function') {
|
|
cb('zh');
|
|
return;
|
|
}
|
|
var ret;
|
|
try { ret = bridge.getLocale(); } catch (e) { cb('zh'); return; }
|
|
if (ret && typeof ret.then === 'function') {
|
|
ret.then(function (loc) { cb(window.soonNormalizeLocaleCode(loc)); }).catch(function () { cb('zh'); });
|
|
return;
|
|
}
|
|
cb(window.soonNormalizeLocaleCode(ret));
|
|
};
|
|
})();
|