/** * 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 = {} ): 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), '*'); }