Files

143 lines
4.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 画个标 · 海报素材库加载器(懒加载)
* 素材库由 scripts/build-posters.js 构建拆分为:
* - js/data/poster-builtin.js 轻量索引(sources 元数据 + 分类索引,无全量内容)
* - js/data/posters/{id}.js 每源一个数据文件(HGB_PosterSource_{id} = {items:[...]})
* 本模块负责:按源懒加载 + 缓存 + 同步读已加载源 + 预加载核心源
*
* 与图标素材库(iconlib.js)的差异:
* - 海报素材为全彩/位图/模板,保留原始宽高比,渲染不再归一化到 24 视口
* - items 字段而非 icons;每条含 type/category/categoryCn/workspaces 归类标签
*/
const HGB_PosterLib = (function () {
'use strict';
const VERSION = '20260823e'; // 与 poster.html 中 poster-builtin.js?v= 版本联动
const cache = {}; // sid -> {items:[...]}
const pending = {}; // sid -> Promise
function fileURL(sid) {
return 'js/data/posters/' + sid + '.js?v=' + VERSION;
}
function loadScript(url) {
return new Promise((resolve, reject) => {
const s = document.createElement('script');
s.src = url;
s.onload = resolve;
s.onerror = function () { reject(new Error('海报素材源加载失败: ' + url)); };
document.head.appendChild(s);
});
}
/** 加载单个源(缓存 + 并发去重) */
function loadSource(sid) {
if (cache[sid]) return Promise.resolve(cache[sid]);
if (pending[sid]) return pending[sid];
pending[sid] = loadScript(fileURL(sid)).then(() => {
const data = window['HGB_PosterSource_' + sid];
if (!data || !data.items) throw new Error('海报素材源不存在: ' + sid);
cache[sid] = data;
delete pending[sid];
return data;
}).catch((e) => {
delete pending[sid];
throw e;
});
return pending[sid];
}
/** 并行加载多个源(全部成功才 resolve) */
function loadSources(ids) {
return Promise.all((ids || []).map(loadSource));
}
/** 并行加载多个源(容忍单个失败,返回已成功加载的) */
function preload(ids) {
return Promise.allSettled((ids || []).map(loadSource)).then((rs) =>
rs.filter(r => r.status === 'fulfilled').map(r => r.value));
}
/** 加载全部源 */
function loadAll() {
const ids = Object.keys((typeof HGB_PosterBuiltin !== 'undefined' ? HGB_PosterBuiltin.sources : {}) || {});
return preload(ids);
}
/** 同步读取已加载源(未加载返回 null) */
function getSource(sid) {
return cache[sid] || null;
}
/** 是否已加载 */
function loaded(sid) {
return !!cache[sid];
}
/** 已加载的全部源 id */
function loadedIds() {
return Object.keys(cache);
}
/** 从已加载源按 名称/id 找素材(返回 {id,name,svg,type,...} 或 null) */
function findPoster(ref) {
if (!ref || typeof ref !== 'string') return null;
const name = ref.trim();
const parts = name.split(':');
if (parts.length === 2) {
const src = cache[parts[0]];
const hit = src && (src.items || []).find(i => i.name === parts[1] || i.id === name);
if (hit) return hit;
}
const lower = name.toLowerCase();
for (const sid of Object.keys(cache)) {
const hit = (cache[sid].items || []).find(i =>
i.id === name || i.name === name ||
String(i.name).toLowerCase() === lower ||
String(i.name).toLowerCase().includes(lower));
if (hit) return hit;
}
return null;
}
/** 搜索已加载源(词根包含匹配),返回完整素材对象 */
function searchLoaded(keyword, limit) {
const kw = String(keyword || '').toLowerCase();
const out = [];
for (const sid of Object.keys(cache)) {
for (const it of cache[sid].items || []) {
if (it.name && it.name.toLowerCase().includes(kw)) {
out.push({ id: sid + ':' + it.name, name: it.name, svg: it.svg, source: sid, type: it.type });
if (out.length >= (limit || 60)) return out;
}
}
}
return out;
}
/** 搜索索引(全量 id/name,无内容,用于筛选展示) */
function searchIndex(keyword, limit) {
const kw = String(keyword || '').toLowerCase();
const out = [];
const idx = (typeof HGB_PosterBuiltin !== 'undefined' && HGB_PosterBuiltin.itemIndex) || [];
for (const it of idx) {
if (it.name && it.name.toLowerCase().includes(kw)) {
out.push({ id: it.id, name: it.name, source: String(it.id).split(':')[0], category: it.category });
if (out.length >= (limit || 20)) return out;
}
}
return out;
}
/** 按 id 反查来源 id */
function sourceOf(fullId) {
return String(fullId || '').split(':')[0];
}
return {
VERSION, loadSource, loadSources, preload, loadAll,
getSource, loaded, loadedIds, findPoster, searchLoaded, searchIndex, sourceOf
};
})();