/** * Collabora 自定义页面跳转模块 * * 使用自定义 PostMessage 协议实现页面跳转,不依赖 UNO 命令 * * @encoding UTF-8 */ /** * 页面跳转响应接口 */ export interface GotoPageResponse { pageNumber: number; pageIndex: number; totalPages: number; currentOffset: number; targetOffset: number; scrollDelta: number; timestamp: number; } /** * Collabora PostMessage 数据类型 */ interface CollaboraMessageData { MessageId?: string; msgId?: string; Values?: { Command?: string; Status?: string; pageNumber?: number; pageIndex?: number; totalPages?: number; currentOffset?: number; targetOffset?: number; scrollDelta?: number; timestamp?: number; Error?: string; [key: string]: unknown; }; args?: { Command?: string; Status?: string; pageNumber?: number; pageIndex?: number; totalPages?: number; currentOffset?: number; targetOffset?: number; scrollDelta?: number; timestamp?: number; Error?: string; [key: string]: unknown; }; [key: string]: unknown; } /** * 解析 PostMessage 数据 */ function parseMessageData(data: unknown): CollaboraMessageData { if (typeof data === 'string') { return JSON.parse(data) as CollaboraMessageData; } return data as CollaboraMessageData; } /** * 跳转到指定页面 (自定义实现,不使用 UNO 命令) * * 使用自定义 custompostMessage 插件实现页面跳转。 * 注意: Collabora 的页码是从 0 开始的,但此函数接受从 1 开始的页码。 * * @param iframeWindow - iframe 的 contentWindow * @param pageNumber - 页码 (从1开始) * @returns Promise,解析为跳转响应信息 * * @example * ```typescript * const response = await customGotoPage(iframeWindow, 5); * console.log(`成功跳转到第 ${response.pageNumber} 页`); * ``` */ export async function customGotoPage( iframeWindow: Window, pageNumber: number ): Promise { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { cleanup(); reject(new Error('页面跳转超时')); }, 5000); const handleMessage = (event: MessageEvent) => { try { if (event.source !== iframeWindow) { return; } const data = parseMessageData(event.data); // bundle.js 的 _postMessage 会将消息转换为: // { MessageId: 'custompostMessage_Resp', Values: { Command: 'GOTO_PAGE', ... } } if ( data.MessageId === 'custompostMessage_Resp' && data.Values?.Command === 'GOTO_PAGE' ) { clearTimeout(timeout); cleanup(); if (data.Values.Status === 'success') { const response: GotoPageResponse = { pageNumber: data.Values.pageNumber || pageNumber, pageIndex: data.Values.pageIndex || pageNumber - 1, totalPages: data.Values.totalPages || 0, currentOffset: data.Values.currentOffset || 0, targetOffset: data.Values.targetOffset || 0, scrollDelta: data.Values.scrollDelta || 0, timestamp: data.Values.timestamp || Date.now(), }; resolve(response); } else { reject(new Error(data.Values.Error || '页面跳转失败')); } } } catch (error) { clearTimeout(timeout); cleanup(); reject(error); } }; const cleanup = () => { window.removeEventListener('message', handleMessage); }; window.addEventListener('message', handleMessage); // 发送跳转请求消息 const message = { MessageId: 'custompostMessage', Values: { Command: 'GOTO_PAGE', Args: { pageNumber: pageNumber, }, }, }; iframeWindow.postMessage(JSON.stringify(message), '*'); }); }