diff --git a/public/browse.html b/public/browse.html
index c0dc686..64cf22b 100644
--- a/public/browse.html
+++ b/public/browse.html
@@ -324,9 +324,6 @@ It's not pretty, but at the same time Adobe's .PSD implementation exists.
// Hide "Go up" row if at root
hideGoUpIfRoot(url);
- // Add download buttons to the table
- addDownloadButtons();
-
// Re-add the spinner
document.body.appendChild(navSpinner);
@@ -351,50 +348,62 @@ It's not pretty, but at the same time Adobe's .PSD implementation exists.
const link = event.target.closest('a');
if (!link) return;
- // Don't interfere with download links
- if (link.hasAttribute('download')) {
- event.preventDefault();
-
- const save = window.__TAURI__.dialog.save;
- const writeTextFile = window.__TAURI__.fs.writeTextFile;
- const writeFile = window.__TAURI__.fs.writeFile;
- const http = window.__TAURI__.http;
-
- // Get the full URL for the download
- const href = link.getAttribute('href');
- const currentUrl = new URLSearchParams(window.location.search).get('url');
- const baseUrl = new URL(currentUrl).href;
- const downloadUrl = new URL(href, baseUrl).href;
-
- // Get the filename from the download attribute or URL
- const filename = link.getAttribute('download') || href.split('/').pop();
-
- save({
- title: 'Save File',
- defaultPath: filename
- }).then(async (result) => {
- if (result) {
- try {
- console.log('downloading', downloadUrl)
- // Fetch the file contents
- const response = await http.fetch(downloadUrl, {
- method: 'GET',
- responseType: 2 // ResponseType.Binary
- });
-
- const data = await response.arrayBuffer();
-
- // Write the file contents
- await writeFile(result, data);
- } catch (err) {
- console.error('Failed to download file:', err);
- }
- }
- });
-
- return;
+ // Get the row and check if it's a file
+ const row = link.closest('tr.file');
+ if (!row) return;
+
+ const isFolder = row.querySelector('svg use').getAttribute('xlink:href') === '#folder';
+
+ if (!isFolder) {
+ // Handle file download
+ event.preventDefault();
+
+ const save = window.__TAURI__.dialog.save;
+ const writeFile = window.__TAURI__.fs.writeFile;
+ const http = window.__TAURI__.http;
+
+ // Get the full URL for the download
+ const href = link.getAttribute('href');
+ const currentUrl = new URLSearchParams(window.location.search).get('url');
+ const baseUrl = new URL(currentUrl).href;
+ const downloadUrl = new URL(href, baseUrl).href;
+
+ // Get the filename from the URL
+ const filename = href.split('/').pop();
+
+ save({
+ title: 'Save File',
+ defaultPath: filename
+ }).then(async (result) => {
+ if (result) {
+ try {
+ // Show the loading spinner while downloading
+ toggleNavSpinner(true);
+
+ console.log('downloading', downloadUrl);
+ // Fetch the file contents
+ const response = await http.fetch(downloadUrl, {
+ method: 'GET',
+ responseType: 2 // ResponseType.Binary
+ });
+
+ const data = await response.arrayBuffer();
+
+ // Write the file contents
+ await writeFile(result, data);
+ } catch (err) {
+ console.error('Failed to download file:', err);
+ } finally {
+ // Hide the loading spinner when done
+ toggleNavSpinner(false);
+ }
+ }
+ });
+
+ return;
}
+ // Handle folder navigation
const href = link.getAttribute('href');
if (!href || href === '') {
event.preventDefault();
@@ -435,6 +444,75 @@ It's not pretty, but at the same time Adobe's .PSD implementation exists.
fetchAndInjectContent(fullUrl);
}
+ // Function to check if an element is in viewport
+ function isInViewport(element) {
+ const rect = element.getBoundingClientRect();
+ return (
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth)
+ );
+ }
+
+ // Function to prefetch links
+ async function prefetchVisibleLinks() {
+ const fileRows = document.querySelectorAll('tr.file');
+ const prefetchedUrls = new Set();
+
+ for (const row of fileRows) {
+ // Skip if not in viewport
+ if (!isInViewport(row)) {
+ continue;
+ }
+
+ // Check if this is a folder by looking for the folder icon
+ const isFolderIcon = row.querySelector('svg use')?.getAttribute('xlink:href') === '#folder';
+ if (!isFolderIcon) {
+ continue;
+ }
+
+ const link = row.querySelector('a');
+ if (!link || prefetchedUrls.has(link.href)) {
+ continue;
+ }
+
+ const href = link.getAttribute('href');
+ if (!href || href === '') continue;
+
+ // Construct full URL similar to handleLinkClick
+ let fullUrl;
+ if (href.startsWith('http')) {
+ fullUrl = href;
+ } else if (href.startsWith('//')) {
+ fullUrl = 'https:' + href;
+ } else if (href.startsWith('/')) {
+ const currentUrl = new URLSearchParams(window.location.search).get('url');
+ const baseUrl = new URL(currentUrl).origin;
+ fullUrl = baseUrl + href;
+ } else {
+ const currentUrl = new URLSearchParams(window.location.search).get('url');
+ const baseUrl = new URL(currentUrl).href;
+ fullUrl = new URL(href, baseUrl).href;
+ }
+
+ try {
+ const pass = new URLSearchParams(window.location.search).get('pass');
+ let prefetchUrl = fullUrl;
+ if (pass) {
+ prefetchUrl = fullUrl.replace('localhost:5572', 'admin:' + pass + '@localhost:5572');
+ }
+
+ // Prefetch the content
+ const fetch = window.__TAURI__.http.fetch;
+ await fetch(prefetchUrl);
+ prefetchedUrls.add(fullUrl);
+ } catch (error) {
+ console.error('Error prefetching:', error);
+ }
+ }
+ }
+
// Function to set up event handlers
function setupEventHandlers() {
// Handle all click events at the document level
@@ -445,32 +523,16 @@ It's not pretty, but at the same time Adobe's .PSD implementation exists.
event.preventDefault();
// You can add form handling logic here if needed
});
- }
- // Function to modify the table structure after content load
- function addDownloadButtons() {
- // Find all file rows
- const fileRows = document.querySelectorAll('tr.file');
- fileRows.forEach(row => {
- // Check if this is a file (not a folder) by looking for the file icon
- const isFolder = row.querySelector('svg use').getAttribute('xlink:href') === '#folder';
-
- if (!isFolder) {
- // Get the file link container
- const nameSpan = row.querySelector('.name');
- if (nameSpan) {
- // Create download link
- const downloadLink = document.createElement('a');
- const fileLink = nameSpan.querySelector('a');
- // keep only the last part of the url, otherwise it uses the wrong root url
- downloadLink.href = fileLink.href.split('/').pop();
- downloadLink.className = 'download-link';
- downloadLink.setAttribute('download', '');
- downloadLink.textContent = '⇩';
- nameSpan.appendChild(downloadLink);
- }
- }
- });
+ // Add scroll event listener for prefetching
+ let scrollTimeout;
+ window.addEventListener('scroll', () => {
+ clearTimeout(scrollTimeout);
+ scrollTimeout = setTimeout(prefetchVisibleLinks, 150);
+ }, { passive: true });
+
+ // Initial prefetch for visible links
+ prefetchVisibleLinks();
}
// Wait for DOM to be ready before initializing