export const BEFORE_PAGE_REFRESH = "app:before-page-refresh"; export const PAGE_DOWNLOAD_ACTIVE_ATTRIBUTE = "data-page-download-active"; export type PageRefreshRequest = { save: (action: () => Promise) => void; block: (message: string) => void; }; const downloadListeners = new Set<() => void>(); let activePageDownloads = 0; export function isPageDownloadActive() { return activePageDownloads > 0; } export function subscribeToPageDownloadActivity(listener: () => void) { downloadListeners.add(listener); return () => { downloadListeners.delete(listener); }; } function publishDownloadActivity() { if (typeof document !== "undefined") { document.documentElement?.toggleAttribute(PAGE_DOWNLOAD_ACTIVE_ATTRIBUTE, isPageDownloadActive()); } for (const listener of downloadListeners) listener(); } export async function withActivePageDownload(download: () => Promise): Promise { if (++activePageDownloads === 1) publishDownloadActivity(); try { return await download(); } finally { if (--activePageDownloads === 0) publishDownloadActivity(); } } function assertPageDownloadFinished() { if (isPageDownloadActive()) throw new Error("文件正在下载,请等下载完成后再刷新。"); } export async function preparePageRefresh() { assertPageDownloadFinished(); const actions: Array<() => Promise> = []; let blocked = ""; window.dispatchEvent(new CustomEvent(BEFORE_PAGE_REFRESH, { detail: { save: action => actions.push(action), block: message => { blocked ||= message; } }, })); if (blocked) throw new Error(blocked); for (const action of actions) await action(); assertPageDownloadFinished(); }