Files
leaudit-platform-frontend/app/components/collabora/lib/pageInfo.ts
T

153 lines
3.9 KiB
TypeScript

/**
* Collabora 页数信息获取模块
*
* @encoding UTF-8
*/
/**
* 页数信息接口
*/
export interface PageInfo {
totalPages: number;
currentPage: number;
timestamp: number;
}
/**
* Collabora PostMessage 数据类型
*/
interface CollaboraMessageData {
MessageId?: string;
msgId?: string;
// bundle.js _postMessage 发送的格式
Values?: {
Command?: string;
Status?: string;
totalPages?: number;
currentPage?: number;
timestamp?: number;
pages?: number;
currentPage?: number;
[key: string]: unknown;
};
// 原始插件返回的格式
args?: {
Command?: string;
Status?: string;
totalPages?: number;
currentPage?: number;
timestamp?: number;
[key: string]: unknown;
};
[key: string]: unknown;
}
/**
* Collabora 全局对象类型
*/
interface CollaboraApp {
map?: {
_docLayer?: {
_pages?: number;
_currentPage?: number;
[key: string]: unknown;
};
[key: string]: unknown;
};
[key: string]: unknown;
}
/**
* 扩展 Window 类型以包含 Collabora app
*/
interface CollaboraWindow extends Window {
app?: CollaboraApp;
}
/**
* 解析 PostMessage 数据
*/
function parseMessageData(data: unknown): CollaboraMessageData {
if (typeof data === 'string') {
return JSON.parse(data) as CollaboraMessageData;
}
return data as CollaboraMessageData;
}
/**
* 通过 PostMessage 请求页数信息
*
* 使用自定义 custompostMessage 插件获取文档页数。
* 注意: Collabora 的页码是从 0 开始的。
*
* @param iframeWindow - iframe 的 contentWindow
* @returns Promise,解析为页数信息
*
* @example
* ```typescript
* const info = await requestPageInfo(iframeWindow);
* console.log(`文档共 ${info.totalPages} 页,当前在第 ${info.currentPage + 1} 页`);
* ```
*/
export async function requestPageInfo(iframeWindow: Window): Promise<PageInfo> {
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: 'GET_PAGE_INFO', ... } }
// 所以我们需要监听 MessageId 而不是 msgId
if (
data.MessageId === 'custompostMessage_Resp' &&
data.Values?.Command === 'GET_PAGE_INFO' &&
data.Values?.Status === 'success'
) {
clearTimeout(timeout);
cleanup();
const info: PageInfo = {
totalPages: data.Values.totalPages || 0,
currentPage: data.Values.currentPage || 0,
timestamp: data.Values.timestamp || Date.now(),
};
resolve(info);
}
} catch (error) {
clearTimeout(timeout);
cleanup();
reject(error);
}
};
const cleanup = () => {
window.removeEventListener('message', handleMessage);
};
window.addEventListener('message', handleMessage);
// 发送请求消息
const message = {
MessageId: 'custompostMessage',
Values: {
Command: 'GET_PAGE_INFO',
Args: {},
},
};
iframeWindow.postMessage(JSON.stringify(message), '*');
});
}