uploader / app /static /script.js
triflix's picture
Update app/static/script.js
6e095c8 verified
// 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');
});