Files
leaudit-platform-frontend/app/components/collabora/Uno.ts
T
2025-11-20 20:36:42 +08:00

169 lines
5.5 KiB
TypeScript

/**
* Collabora Online UNO 命令工具函数
*
* 职责: 封装 Collabora iframe 的 UNO 命令调用
*
* @encoding UTF-8
*/
/**
* 发送 UNO 命令到 Collabora iframe
* @param iframeWindow - iframe 的 contentWindow
* @param command - UNO 命令名称,如 '.uno:ExecuteSearch'
* @param args - 命令参数
*/
export function sendUnoCommand(
iframeWindow: Window,
command: string,
args: Record<string, any> = {}
): void {
const message = {
MessageId: 'Send_UNO_Command',
SendTime: Date.now(),
Values: {
Command: command,
Args: args,
},
};
console.log('[UNO] 发送命令:', command, args);
iframeWindow.postMessage(JSON.stringify(message), '*');
}
/**
* 搜索文本
* @param iframeWindow - iframe 的 contentWindow
* @param text - 要搜索的文本
*/
export function unoSearchText(iframeWindow: Window, text: string): void {
sendUnoCommand(iframeWindow, '.uno:ExecuteSearch', {
'SearchItem.SearchString': { type: 'string', value: text },
'SearchItem.Command': { type: 'long', value: 1 }, // 1 = Search Next (搜索下一个)
'SearchItem.Backward': { type: 'boolean', value: false },
'SearchItem.Pattern': { type: 'boolean', value: false },
'SearchItem.Content': { type: 'boolean', value: false },
'SearchItem.AsianOptions': { type: 'boolean', value: false },
'SearchItem.AlgorithmType': { type: 'short', value: 0 }, // 普通搜索
'SearchItem.SearchFlags': { type: 'long', value: 0 },
'SearchItem.Start': { type: 'boolean', value: true }, // 从头开始搜索
'SearchItem.Quiet': { type: 'boolean', value: true }, // 静默模式
});
}
/**
* 替换文本
* @param iframeWindow - iframe 的 contentWindow
* @param searchText - 要搜索的文本
* @param replaceText - 替换后的文本
*/
export function unoReplaceText(
iframeWindow: Window,
searchText: string,
replaceText: string
): void {
sendUnoCommand(iframeWindow, '.uno:ExecuteSearch', {
'SearchItem.SearchString': { type: 'string', value: searchText },
'SearchItem.ReplaceString': { type: 'string', value: replaceText },
'SearchItem.Command': { type: 'long', value: 3 }, // 3 = ReplaceAll
'SearchItem.AlgorithmType': { type: 'short', value: 0 },
'SearchItem.SearchFlags': { type: 'long', value: 0 },
'SearchItem.Backward': { type: 'boolean', value: false },
'Quiet': { type: 'boolean', value: true },
});
}
/**
* 高亮文本
* @param iframeWindow - iframe 的 contentWindow
* @param text - 要高亮的文本
* @param color - 高亮颜色,默认 16776960 = 黄色
*/
export function unoHighlightText(
iframeWindow: Window,
text: string,
color: number = 16776960
): void {
// 1. 查找所有
sendUnoCommand(iframeWindow, '.uno:ExecuteSearch', {
'SearchItem.SearchString': { type: 'string', value: text },
'SearchItem.Command': { type: 'long', value: 1 }, // 1 = FindAll
'SearchItem.SearchFlags': { type: 'long', value: 0 },
'SearchItem.AlgorithmType': { type: 'short', value: 0 },
'SearchItem.Backward': { type: 'boolean', value: false },
'Quiet': { type: 'boolean', value: true },
});
// 2. 设置背景色
sendUnoCommand(iframeWindow, '.uno:BackColor', {
BackColor: { type: 'long', value: color },
});
}
/**
* 移除高亮
* @param iframeWindow - iframe 的 contentWindow
* @param text - 要移除高亮的文本
*/
export function unoRemoveHighlight(iframeWindow: Window, text: string): void {
// 1. 查找所有
sendUnoCommand(iframeWindow, '.uno:ExecuteSearch', {
'SearchItem.SearchString': { type: 'string', value: text },
'SearchItem.Command': { type: 'long', value: 1 }, // 1 = FindAll
'SearchItem.SearchFlags': { type: 'long', value: 0 },
'SearchItem.AlgorithmType': { type: 'short', value: 0 },
'SearchItem.Backward': { type: 'boolean', value: false },
'Quiet': { type: 'boolean', value: true },
});
// 2. 移除背景色 -1 = 无色
sendUnoCommand(iframeWindow, '.uno:BackColor', {
BackColor: { type: 'long', value: -1 },
});
}
/**
* 取消 - Escape
* @param iframeWindow - iframe 的 contentWindow
*/
export function unoEscape(iframeWindow: Window): void {
sendUnoCommand(iframeWindow, '.uno:Escape', {});
}
/**
* 滚动到文档开头
* @param iframeWindow - iframe 的 contentWindow
*/
export function unoScrollToTop(iframeWindow: Window): void {
sendUnoCommand(iframeWindow, '.uno:GoToStartOfDoc', {});
}
/**
* 保存文档
* @param iframeWindow - iframe 的 contentWindow
*/
export function unoSave(iframeWindow: Window): void {
sendUnoCommand(iframeWindow, '.uno:Save');
}
/**
* 获取文档状态 (用于检测命令队列完成)
* @param iframeWindow - iframe 的 contentWindow
*
* 说明: 发送 Get_State 命令作为"哨兵命令",利用 Collabora 的单线程命令队列机制。
* 当收到 Doc_ModifiedStatus 类型的回调时,证明前面队列中的所有命令都已执行完毕。
*
* 响应格式: { MessageId: 'Doc_ModifiedStatus', Values: {...} }
*/
export function unoGetState(iframeWindow: Window): void {
const message = {
MessageId: 'Get_State',
SendTime: Date.now(),
Values: {
CommandName: '.uno:ModifiedStatus',
},
};
console.log('[UNO] 发送 Get_State (.uno:ModifiedStatus) - 等待命令队列执行完成');
iframeWindow.postMessage(JSON.stringify(message), '*');
}