152 lines
4.4 KiB
TypeScript
152 lines
4.4 KiB
TypeScript
/**
|
|
* 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<GotoPageResponse> {
|
|
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), '*');
|
|
});
|
|
}
|