upload-service/web/static/upload.js

150 lines
5.3 KiB
JavaScript

(() => {
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('file-input');
const options = document.getElementById('options');
const uploadBtn = document.getElementById('upload-btn');
const progressSection = document.getElementById('progress-section');
const progressFilename = document.getElementById('progress-filename');
const progressFill = document.getElementById('progress-fill');
const progressText = document.getElementById('progress-text');
const result = document.getElementById('result');
const resultUrl = document.getElementById('result-url');
const copyBtn = document.getElementById('copy-btn');
const resultDelete = document.getElementById('result-delete');
const resultExpiry = document.getElementById('result-expiry');
const errorDiv = document.getElementById('error');
let selectedFile = null;
// Drag and drop
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) {
selectFile(e.dataTransfer.files[0]);
}
});
dropzone.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', () => {
if (fileInput.files.length > 0) {
selectFile(fileInput.files[0]);
}
});
function selectFile(file) {
selectedFile = file;
dropzone.querySelector('p').textContent = file.name + ' (' + formatSize(file.size) + ')';
options.classList.remove('hidden');
result.classList.add('hidden');
errorDiv.classList.add('hidden');
}
uploadBtn.addEventListener('click', () => {
if (!selectedFile) return;
upload(selectedFile);
});
function upload(file) {
const formData = new FormData();
const slug = document.getElementById('slug').value.trim();
if (slug) formData.append('slug', slug);
formData.append('file', file);
const expires = document.getElementById('expires').value;
if (expires) formData.append('expires_in', expires);
const password = document.getElementById('password').value;
if (password) formData.append('password', password);
const xhr = new XMLHttpRequest();
// Show progress
options.classList.add('hidden');
dropzone.classList.add('hidden');
progressSection.classList.remove('hidden');
progressFilename.textContent = file.name;
errorDiv.classList.add('hidden');
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const pct = Math.round((e.loaded / e.total) * 100);
progressFill.style.width = pct + '%';
progressText.textContent = pct + '% — ' + formatSize(e.loaded) + ' / ' + formatSize(e.total);
}
});
xhr.addEventListener('load', () => {
progressSection.classList.add('hidden');
if (xhr.status === 201) {
const data = JSON.parse(xhr.responseText);
showResult(data);
} else {
showError(xhr.responseText || 'Upload failed');
}
});
xhr.addEventListener('error', () => {
progressSection.classList.add('hidden');
showError('Network error — upload failed');
});
xhr.open('POST', '/upload');
xhr.send(formData);
}
function showResult(data) {
result.classList.remove('hidden');
resultUrl.value = data.url;
resultDelete.textContent = 'Delete: curl -X DELETE -H "Authorization: Bearer ' + data.delete_token + '" ' + data.delete_url;
if (data.expires_at) {
resultExpiry.textContent = 'Expires: ' + new Date(data.expires_at).toLocaleString();
} else {
resultExpiry.textContent = '';
}
// Reset for another upload
dropzone.classList.remove('hidden');
dropzone.querySelector('p').innerHTML = 'Drop a file here or <label for="file-input" class="link">browse</label>';
selectedFile = null;
}
function showError(msg) {
errorDiv.textContent = msg;
errorDiv.classList.remove('hidden');
dropzone.classList.remove('hidden');
dropzone.querySelector('p').innerHTML = 'Drop a file here or <label for="file-input" class="link">browse</label>';
selectedFile = null;
}
copyBtn.addEventListener('click', () => {
resultUrl.select();
navigator.clipboard.writeText(resultUrl.value).then(() => {
copyBtn.textContent = 'Copied!';
setTimeout(() => { copyBtn.textContent = 'Copy'; }, 2000);
});
});
function formatSize(bytes) {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
}
})();