169 lines
5.5 KiB
TypeScript
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), '*');
|
|
}
|