import type { DocumentField, FieldApplyResult, FieldChange } from '../domain/types';
|
import { applyFieldsCommand, inspectFieldsCommand } from './commands';
|
import type { ApplyResult, AscGlobal, InspectResult } from './types';
|
|
interface LifecycleCallbacks { onReady: () => void; onThemeChanged: (theme: unknown) => void }
|
|
export interface OnlyOfficeBridge {
|
applyFields(changes: FieldChange[]): Promise<FieldApplyResult[]>;
|
bindLifecycle(callbacks: LifecycleCallbacks): () => void;
|
getRuntimeOptions(): unknown;
|
inspectFields(): Promise<DocumentField[]>;
|
}
|
|
function parseResult<T>(raw: unknown): T {
|
const result: unknown = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
if (typeof result !== 'object' || result === null || Array.isArray(result) || !('ok' in result) || typeof result.ok !== 'boolean') {
|
throw new Error('编辑器命令返回无效结果');
|
}
|
return result as T;
|
}
|
|
export function createOnlyOfficeBridge(asc: AscGlobal): OnlyOfficeBridge {
|
function callCommand<T>(command: () => string, scopeKey: string, payload: unknown): Promise<T> {
|
return new Promise((resolve, reject) => {
|
asc.scope[scopeKey] = payload;
|
try {
|
asc.plugin.callCommand(command, false, true, (raw) => {
|
try { resolve(parseResult<T>(raw)); } catch (error) { reject(error); }
|
finally { delete asc.scope[scopeKey]; }
|
});
|
} catch (error) {
|
delete asc.scope[scopeKey];
|
reject(error);
|
}
|
});
|
}
|
|
async function inspectFields(): Promise<DocumentField[]> {
|
const result = await callCommand<InspectResult>(inspectFieldsCommand, 'elnTemplateFillInspect', {});
|
if (!result.ok) throw new Error(result.error || '读取内容控件失败');
|
return result.fields;
|
}
|
|
async function applyFields(changes: FieldChange[]): Promise<FieldApplyResult[]> {
|
const result = await callCommand<ApplyResult>(applyFieldsCommand, 'elnTemplateFillChanges', changes);
|
if (!result.ok) throw new Error(result.error || '应用字段失败');
|
return result.results;
|
}
|
|
function bindLifecycle(callbacks: LifecycleCallbacks): () => void {
|
const originalInit = asc.plugin.init;
|
const originalTheme = asc.plugin.onThemeChanged;
|
asc.plugin.init = callbacks.onReady;
|
asc.plugin.onThemeChanged = (theme) => { asc.plugin.onThemeChangedBase(theme); callbacks.onThemeChanged(theme); };
|
return () => {
|
if (asc.plugin.init === callbacks.onReady) asc.plugin.init = originalInit;
|
asc.plugin.onThemeChanged = originalTheme;
|
};
|
}
|
|
return { applyFields, bindLifecycle, getRuntimeOptions: () => asc.plugin.info?.options, inspectFields };
|
}
|