mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
Bunny and direct downloads are pulled through fetch() so we can save them under our own filename. The browser does not treat that as a download, so closing the tab discarded everything received so far without a word. Register a reference counted beforeunload guard while those transfers are in flight, and while a project manifest is being pulled file by file. Browser owned downloads (same-origin proxy, the over-10GB fallback, asset downloads) survive a tab close on their own and stay unguarded.
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
'use client';
|
|
|
|
/**
|
|
* Downloads that we pull through fetch() live inside the page: closing the tab
|
|
* (or reloading) throws away every byte received so far and the browser gives no
|
|
* warning, because as far as it knows nothing is downloading. While one of those
|
|
* is in flight we register a beforeunload handler so the user gets the native
|
|
* "leave site?" dialog instead of silently losing the transfer.
|
|
*
|
|
* Plain navigation downloads (the `download` attribute / a redirect to the CDN)
|
|
* are owned by the browser and survive a tab close, so they must NOT be guarded.
|
|
*/
|
|
|
|
let activeCount = 0;
|
|
|
|
function handleBeforeUnload(event: BeforeUnloadEvent) {
|
|
event.preventDefault();
|
|
// Legacy browsers only show the dialog when returnValue is set; the string
|
|
// itself is ignored, every browser shows its own wording.
|
|
event.returnValue = '';
|
|
}
|
|
|
|
/** Registers the guard and returns a release function. Safe to call again while
|
|
* another download is already guarded — the listener is reference counted and
|
|
* only detaches once the last one releases. Releasing twice is a no-op. */
|
|
export function beginUnloadGuard(): () => void {
|
|
if (typeof window === 'undefined') return () => {};
|
|
|
|
if (activeCount === 0) {
|
|
window.addEventListener('beforeunload', handleBeforeUnload);
|
|
}
|
|
activeCount += 1;
|
|
|
|
let released = false;
|
|
return () => {
|
|
if (released) return;
|
|
released = true;
|
|
activeCount -= 1;
|
|
if (activeCount === 0) {
|
|
window.removeEventListener('beforeunload', handleBeforeUnload);
|
|
}
|
|
};
|
|
}
|
|
|
|
/** Test helper: number of downloads currently holding the guard. */
|
|
export function unloadGuardCount(): number {
|
|
return activeCount;
|
|
}
|