// app/static/script.js document.addEventListener('DOMContentLoaded', () => { // --- State --- let currentFile = null; let currentXHR = null; // --- DOM Elements --- const states = { initial: document.getElementById('state-initial'), uploading: document.getElementById('state-uploading'), complete: document.getElementById('state-complete'), error: document.getElementById('state-error'), }; const dropZone = document.getElementById('drop-zone'); const browseBtn = document.getElementById('browse-btn'); const fileInput = document.getElementById('file-input'); const fileNameEl = document.getElementById('file-name'); const fileSizeEl = document.getElementById('file-size'); const progressBar = document.getElementById('progress-bar'); const statusText = document.getElementById('status-text'); const downloadLink = document.getElementById('download-link'); const uploadAnotherBtn = document.getElementById('upload-another-btn'); const errorMessage = document.getElementById('error-message'); const retryBtn = document.getElementById('retry-btn'); // New elements for copy functionality const downloadUrlInput = document.getElementById('download-url-input'); const copyLinkBtn = document.getElementById('copy-link-btn'); // --- UI State Management --- function switchState(state) { Object.values(states).forEach(el => el.classList.remove('active')); if (states[state]) { states[state].classList.add('active'); } } // --- Event Listeners --- browseBtn.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', handleFileSelect); dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('drag-over'); }); dropZone.addEventListener('dragleave', () => dropZone.classList.remove('drag-over')); dropZone.addEventListener('drop', (e) => { e.preventDefault(); dropZone.classList.remove('drag-over'); if (e.dataTransfer.files.length > 0) { handleFileSelect({ target: { files: e.dataTransfer.files } }); } }); uploadAnotherBtn.addEventListener('click', resetUploader); retryBtn.addEventListener('click', resetUploader); copyLinkBtn.addEventListener('click', handleCopyLink); // --- Core Functions --- function handleFileSelect(event) { const file = event.target.files[0]; if (!file) return; currentFile = file; fileNameEl.textContent = file.name; fileSizeEl.textContent = formatBytes(file.size); startUpload(file); } function startUpload(file) { switchState('uploading'); statusText.textContent = 'Uploading...'; progressBar.style.width = '0%'; const formData = new FormData(); formData.append('file', file); const xhr = new XMLHttpRequest(); currentXHR = xhr; xhr.upload.addEventListener('progress', (event) => { if (event.lengthComputable) { const percentage = (event.loaded / event.total) * 100; progressBar.style.width = `${percentage}%`; statusText.textContent = `${formatBytes(event.loaded)} / ${formatBytes(event.total)}`; } }); xhr.addEventListener('load', () => { if (xhr.status >= 200 && xhr.status < 300) { const response = JSON.parse(xhr.responseText); // Construct the full, absolute URL for sharing const fullUrl = `${window.location.origin}${response.download_url}`; downloadLink.href = response.download_url; downloadLink.download = response.filename; downloadUrlInput.value = fullUrl; switchState('complete'); } else { handleUploadError(xhr); } }); xhr.addEventListener('error', () => handleUploadError(xhr)); xhr.addEventListener('abort', () => console.log('Upload aborted.')); xhr.open('POST', '/upload', true); xhr.send(formData); } // NEW: Function to handle copying the link function handleCopyLink() { // Use the modern Navigator Clipboard API navigator.clipboard.writeText(downloadUrlInput.value).then(() => { // Provide visual feedback copyLinkBtn.textContent = 'Copied!'; copyLinkBtn.classList.add('copied'); // Revert back after a couple of seconds setTimeout(() => { copyLinkBtn.textContent = 'Copy'; copyLinkBtn.classList.remove('copied'); }, 2000); }).catch(err => { console.error('Failed to copy text: ', err); // You could add an error state to the button here if needed }); } function handleUploadError(xhr) { let message = 'An unknown network error occurred.'; try { const errorData = JSON.parse(xhr.responseText); message = errorData.detail || 'Upload failed.'; } catch (e) { if (xhr.statusText) { message = xhr.statusText; } } errorMessage.textContent = message; switchState('error'); } function resetUploader() { if (currentXHR) { currentXHR.abort(); currentXHR = null; } currentFile = null; fileInput.value = ''; downloadUrlInput.value = ''; // Clear the URL input switchState('initial'); } function formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } switchState('initial'); });