mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
fix(download): warn before the tab closes mid-download
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.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
'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;
|
||||
}
|
||||
Reference in New Issue
Block a user