mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 13:55:51 +00:00
ci: auto build & obfuscate [2026-04-06 00:50:28] (Jenkins #7)
This commit is contained in:
18
SL/module/AdditionalFeaturesModule.js
Normal file
18
SL/module/AdditionalFeaturesModule.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('AdditionalFeatures')
|
||||
.view('assets/amily-additional-features/Amily2-AdditionalFeatures.html');
|
||||
|
||||
export default class AdditionalFeaturesModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_additional_features_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SL/module/ApiConfigModule.js
Normal file
28
SL/module/ApiConfigModule.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
import { bindApiConfigPanel } from '../../ui/api-config-bindings.js';
|
||||
import { syncAllSlots } from '../../ui/profile-sync.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('ApiConfig')
|
||||
.view('assets/api-config-panel.html')
|
||||
.strict(true)
|
||||
.required(['mount']);
|
||||
|
||||
export default class ApiConfigModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_api_config_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
bindApiConfigPanel($(this.el));
|
||||
syncAllSlots();
|
||||
}
|
||||
|
||||
expose() {
|
||||
return { syncAllSlots };
|
||||
}
|
||||
}
|
||||
22
SL/module/CWBModule.js
Normal file
22
SL/module/CWBModule.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
import { initializeCharacterWorldBook } from '../../CharacterWorldBook/cwb_index.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('CharacterWorldBook')
|
||||
.view('CharacterWorldBook/cwb_settings.html')
|
||||
.strict(true)
|
||||
.required(['mount']);
|
||||
|
||||
export default class CWBModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_character_world_book_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
await initializeCharacterWorldBook($(this.el));
|
||||
}
|
||||
}
|
||||
24
SL/module/GlossaryModule.js
Normal file
24
SL/module/GlossaryModule.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('Glossary')
|
||||
.view('assets/amily-glossary-system/amily2-glossary.html')
|
||||
.strict(true)
|
||||
.required(['mount']);
|
||||
|
||||
export default class GlossaryModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_glossary_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
// bindGlossaryEvents 由 index.js 中 waitForGlossaryPanelAndBindEvents 轮询调用
|
||||
// 模块化后面板已就绪,可直接绑定
|
||||
const { bindGlossaryEvents } = await import('../../glossary/GT_bindings.js');
|
||||
bindGlossaryEvents();
|
||||
}
|
||||
}
|
||||
22
SL/module/HanlinyuanModule.js
Normal file
22
SL/module/HanlinyuanModule.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
import { bindHanlinyuanEvents } from '../../ui/hanlinyuan-bindings.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('Hanlinyuan')
|
||||
.view('assets/amily-hanlinyuan-system/hanlinyuan.html')
|
||||
.strict(true)
|
||||
.required(['mount']);
|
||||
|
||||
export default class HanlinyuanModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_hanlinyuan_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
bindHanlinyuanEvents();
|
||||
}
|
||||
}
|
||||
22
SL/module/HistoriographyModule.js
Normal file
22
SL/module/HistoriographyModule.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
import { bindHistoriographyEvents } from '../../ui/historiography-bindings.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('Historiography')
|
||||
.view('assets/Amily2-TextOptimization.html')
|
||||
.strict(true)
|
||||
.required(['mount']);
|
||||
|
||||
export default class HistoriographyModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_text_optimization_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
bindHistoriographyEvents();
|
||||
}
|
||||
}
|
||||
144
SL/module/ModuleRegistry.js
Normal file
144
SL/module/ModuleRegistry.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* ModuleRegistry — 模块注册中心
|
||||
*
|
||||
* 职责:
|
||||
* 1. 收集所有 Module 子类的注册信息(name → factory)
|
||||
* 2. 统一执行 init → mount 生命周期
|
||||
* 3. 向 Amily2Bus 暴露各模块的 expose() 结果,供跨模块调用
|
||||
* 4. 提供 dispose 方法用于整体卸载
|
||||
*
|
||||
* 用法:
|
||||
* import { registry } from 'SL/module/ModuleRegistry.js';
|
||||
* registry.register('Hanlinyuan', () => new HanlinyuanModule());
|
||||
* await registry.mountAll(ctx); // ctx = { baseUrl, root, ... }
|
||||
* registry.query('Hanlinyuan'); // 获取该模块 expose() 的公开 API
|
||||
*/
|
||||
|
||||
const _modules = new Map(); // name → Module instance (mounted)
|
||||
const _factories = new Map(); // name → () => Module
|
||||
|
||||
/**
|
||||
* 注册一个模块工厂。
|
||||
* @param {string} name 唯一模块名
|
||||
* @param {Function} factory 无参函数,返回 Module 实例
|
||||
*/
|
||||
export function register(name, factory) {
|
||||
if (_factories.has(name)) {
|
||||
console.warn(`[ModuleRegistry] 模块 "${name}" 已注册,将覆盖。`);
|
||||
}
|
||||
_factories.set(name, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化并挂载所有已注册模块。
|
||||
* @param {Object} ctx 传给 module.init(ctx) 的上下文
|
||||
* ctx.baseUrl — 插件根 URL(用于 view 路径解析)
|
||||
* ctx.root — 挂载目标 DOM 元素
|
||||
*/
|
||||
export async function mountAll(ctx = {}) {
|
||||
for (const [name, factory] of _factories) {
|
||||
if (_modules.has(name)) {
|
||||
console.warn(`[ModuleRegistry] 模块 "${name}" 已挂载,跳过。`);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const mod = factory();
|
||||
await mod.init(ctx);
|
||||
await mod.mount();
|
||||
_modules.set(name, mod);
|
||||
|
||||
// 向 Bus 暴露模块公开 API
|
||||
_exposeToBus(name, mod);
|
||||
|
||||
console.log(`[ModuleRegistry] ✔ ${name}`);
|
||||
} catch (e) {
|
||||
console.error(`[ModuleRegistry] ✘ ${name} 挂载失败:`, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称挂载单个模块(延迟挂载场景)。
|
||||
*/
|
||||
export async function mountOne(name, ctx = {}) {
|
||||
const factory = _factories.get(name);
|
||||
if (!factory) {
|
||||
console.warn(`[ModuleRegistry] 模块 "${name}" 未注册。`);
|
||||
return null;
|
||||
}
|
||||
if (_modules.has(name)) return _modules.get(name);
|
||||
|
||||
const mod = factory();
|
||||
await mod.init(ctx);
|
||||
await mod.mount();
|
||||
_modules.set(name, mod);
|
||||
_exposeToBus(name, mod);
|
||||
return mod;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已挂载模块的公开 API。
|
||||
*/
|
||||
export function query(name) {
|
||||
const mod = _modules.get(name);
|
||||
return mod ? mod.expose() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已挂载的模块实例(内部使用)。
|
||||
*/
|
||||
export function getInstance(name) {
|
||||
return _modules.get(name) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载所有模块。
|
||||
*/
|
||||
export function disposeAll() {
|
||||
for (const [name, mod] of _modules) {
|
||||
try {
|
||||
mod.dispose();
|
||||
} catch (e) {
|
||||
console.error(`[ModuleRegistry] ${name} dispose 失败:`, e);
|
||||
}
|
||||
}
|
||||
_modules.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 已注册的模块名列表。
|
||||
*/
|
||||
export function names() {
|
||||
return [..._factories.keys()];
|
||||
}
|
||||
|
||||
// ── 内部 ──────────────────────────────────────────────
|
||||
|
||||
function _exposeToBus(name, mod) {
|
||||
try {
|
||||
const bus = window.Amily2Bus;
|
||||
if (!bus) return;
|
||||
const exposed = mod.expose();
|
||||
if (exposed && Object.keys(exposed).length > 0) {
|
||||
const _ctx = bus.register(`Module:${name}`);
|
||||
if (_ctx) {
|
||||
_ctx.expose(exposed);
|
||||
_ctx.log(`Module:${name}`, 'info', `模块 ${name} 已注册到 Bus。`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Bus 未就绪或注册冲突,静默忽略
|
||||
}
|
||||
}
|
||||
|
||||
export const registry = {
|
||||
register,
|
||||
mountAll,
|
||||
mountOne,
|
||||
query,
|
||||
getInstance,
|
||||
disposeAll,
|
||||
names,
|
||||
};
|
||||
|
||||
export default registry;
|
||||
22
SL/module/PlotOptModule.js
Normal file
22
SL/module/PlotOptModule.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
import { initializePlotOptimizationBindings } from '../../ui/plot-opt-bindings.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('PlotOptimization')
|
||||
.view('assets/Amily2-optimization.html')
|
||||
.strict(true)
|
||||
.required(['mount']);
|
||||
|
||||
export default class PlotOptModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_plot_optimization_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
initializePlotOptimizationBindings();
|
||||
}
|
||||
}
|
||||
22
SL/module/RendererModule.js
Normal file
22
SL/module/RendererModule.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
import { initializeRendererBindings } from '../../core/tavern-helper/renderer-bindings.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('Renderer')
|
||||
.view('core/tavern-helper/renderer.html')
|
||||
.strict(true)
|
||||
.required(['mount']);
|
||||
|
||||
export default class RendererModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_renderer_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
initializeRendererBindings();
|
||||
}
|
||||
}
|
||||
22
SL/module/SuperMemoryModule.js
Normal file
22
SL/module/SuperMemoryModule.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
import { bindSuperMemoryEvents } from '../../core/super-memory/bindings.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('SuperMemory')
|
||||
.view('core/super-memory/index.html')
|
||||
.strict(true)
|
||||
.required(['mount']);
|
||||
|
||||
export default class SuperMemoryModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_super_memory_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
bindSuperMemoryEvents();
|
||||
}
|
||||
}
|
||||
29
SL/module/WorldEditorModule.js
Normal file
29
SL/module/WorldEditorModule.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Module, ModuleBuilder } from './Module.js';
|
||||
import { extensionName } from '../../utils/settings.js';
|
||||
|
||||
const builder = new ModuleBuilder()
|
||||
.name('WorldEditor')
|
||||
.view('WorldEditor.html');
|
||||
|
||||
export default class WorldEditorModule extends Module {
|
||||
constructor() {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
async mount() {
|
||||
if (this.el) {
|
||||
this.el.id = 'amily2_world_editor_panel';
|
||||
this.el.style.display = 'none';
|
||||
}
|
||||
// WorldEditor.js 必须作为 <script type="module"> 加载
|
||||
const scriptId = 'world-editor-script';
|
||||
if (!document.getElementById(scriptId)) {
|
||||
const extensionFolderPath = `scripts/extensions/third-party/${extensionName}`;
|
||||
const script = document.createElement('script');
|
||||
script.id = scriptId;
|
||||
script.type = 'module';
|
||||
script.src = `${extensionFolderPath}/WorldEditor/WorldEditor.js?v=${Date.now()}`;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
SL/module/register-all.js
Normal file
36
SL/module/register-all.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* register-all.js — 集中注册所有 UI 模块
|
||||
*
|
||||
* 调用 registerAllModules() 后,所有模块工厂被注册到 ModuleRegistry。
|
||||
* 随后由 drawer.js 在面板容器就绪后调用 registry.mountAll(ctx) 完成挂载。
|
||||
*
|
||||
* 注册顺序即挂载顺序 —— DOM 中面板的排列取决于此。
|
||||
*/
|
||||
|
||||
import registry from './ModuleRegistry.js';
|
||||
|
||||
import AdditionalFeaturesModule from './AdditionalFeaturesModule.js';
|
||||
import HistoriographyModule from './HistoriographyModule.js';
|
||||
import HanlinyuanModule from './HanlinyuanModule.js';
|
||||
import TableModule from './TableModule.js';
|
||||
import PlotOptModule from './PlotOptModule.js';
|
||||
import CWBModule from './CWBModule.js';
|
||||
import WorldEditorModule from './WorldEditorModule.js';
|
||||
import GlossaryModule from './GlossaryModule.js';
|
||||
import RendererModule from './RendererModule.js';
|
||||
import SuperMemoryModule from './SuperMemoryModule.js';
|
||||
import ApiConfigModule from './ApiConfigModule.js';
|
||||
|
||||
export function registerAllModules() {
|
||||
registry.register('AdditionalFeatures', () => new AdditionalFeaturesModule());
|
||||
registry.register('Historiography', () => new HistoriographyModule());
|
||||
registry.register('Hanlinyuan', () => new HanlinyuanModule());
|
||||
registry.register('Table', () => new TableModule());
|
||||
registry.register('PlotOptimization', () => new PlotOptModule());
|
||||
registry.register('CharacterWorldBook', () => new CWBModule());
|
||||
registry.register('WorldEditor', () => new WorldEditorModule());
|
||||
registry.register('Glossary', () => new GlossaryModule());
|
||||
registry.register('Renderer', () => new RendererModule());
|
||||
registry.register('SuperMemory', () => new SuperMemoryModule());
|
||||
registry.register('ApiConfig', () => new ApiConfigModule());
|
||||
}
|
||||
Reference in New Issue
Block a user