fd80a3de67
Four related fixes to stop buffering files in page memory and stop hammering layout from the selection paths: - Inline viewer media: video/audio fetched the ENTIRE file into a blob before the first frame (a 2 GB video = 2 GB of tab heap, no progressive playback, no seek). The <video>/<audio> src now points straight at the same-origin API URL — cookies travel automatically and the browser streams with native Range requests, exactly like the music player already did. - Downloads (file, folder ZIP, batch ZIP, viewer button): the fetch → blob → objectURL pattern materialized the whole payload in RAM before the save dialog appeared (a 10 GB batch ZIP risked crashing the tab) with no download progress UI. New shared utils/download.js hands the URL to the browser, which streams to disk with its own progress UI. Batch download uses the existing GET endpoint (same URL contract as the drag-out DownloadURL, now shared via buildBatchDownloadUrl); selections whose id list cannot fit in a URL keep the buffered POST fallback. Trade-off: failed downloads now surface in the browser's download shelf instead of an in-app toast. - Rubber-band lasso: every mousemove (>100/s) walked all cards interleaving getBoundingClientRect() reads with class writes — up to N forced reflows per event, freezing the frame rate on folders with thousands of loaded rows. Card rects (+ item info) are now snapshot once per drag (rebuilt on scroll), and a single rAF pass per frame compares against the cached geometry, touching only cards whose selection state changed. - batchToolbar: getSelection() rebuilt the selection by scanning every .file-item in the document (the TODO admitted it); it now reads the _selected Map that every selection path already keeps in sync. clear() scopes its DOM sweep to #files-list (the only container the toolbar manages) instead of the whole document. https://claude.ai/code/session_01Dp3oWon5GBMVn4j3QXZdgx
45 lines
1.6 KiB
JavaScript
45 lines
1.6 KiB
JavaScript
// @ts-check
|
|
|
|
/**
|
|
* Browser-native download helpers.
|
|
*
|
|
* Downloads are handed to the browser as same-origin navigations: the
|
|
* response streams straight to disk with the browser's own progress UI,
|
|
* and auth cookies travel automatically. Nothing is buffered in page
|
|
* memory — unlike the old `fetch → blob → objectURL` pattern, which
|
|
* materialized the entire payload in the tab's heap before the save
|
|
* dialog could even appear.
|
|
*/
|
|
|
|
/**
|
|
* Trigger a browser-native download for a same-origin URL.
|
|
*
|
|
* @param {string} url - Same-origin URL of the resource to download
|
|
* @param {string} [filename] - Suggested file name. The server's
|
|
* `Content-Disposition` filename wins when present; an empty string
|
|
* keeps whatever the server (or URL) provides.
|
|
*/
|
|
export function triggerBrowserDownload(url, filename = '') {
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = filename;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
}
|
|
|
|
/**
|
|
* Build the GET URL for the batch ZIP download endpoint
|
|
* (`GET /api/batch/download` accepts comma-separated id lists).
|
|
* Shared by the batch toolbar download and the drag-out `DownloadURL`
|
|
* builder so both stay in sync with the endpoint's query contract.
|
|
*
|
|
* @param {string[]} fileIds
|
|
* @param {string[]} folderIds
|
|
* @returns {string} Root-relative URL (prepend `window.location.origin`
|
|
* when an absolute URL is required, e.g. for `DataTransfer.setData`).
|
|
*/
|
|
export function buildBatchDownloadUrl(fileIds, folderIds) {
|
|
return `/api/batch/download?file_ids=${fileIds.join(',')}&folder_ids=${folderIds.join(',')}`;
|
|
}
|