document.addEventListener("DOMContentLoaded", function() { // Upload queue management const uploadQueue = { queue: [], processing: false, add: function(file, fileElements) { this.queue.push({ file, fileElements }); this.processNext(); }, processNext: function() { if (this.processing || this.queue.length === 0) return; this.processing = true; const next = this.queue[0]; uploadFile(next.file, next.fileElements) .then(() => { this.queue.shift(); // Remove the processed file this.processing = false; this.processNext(); // Process next file if any }) .catch(error => { console.error('Upload error:', error); this.queue.shift(); // Remove the failed file this.processing = false; this.processNext(); // Continue with next file }); } }; function createFileElement(file) { const listItem = document.createElement("li"); listItem.className = "mb-4"; // File name display const nameSpan = document.createElement("span"); nameSpan.textContent = file.name; nameSpan.className = "text-gray-300 truncate max-w-[300px] inline-block"; // Progress elements const progressWrapper = document.createElement("div"); progressWrapper.className = "mt-2 flex items-center gap-2"; const progressBar = document.createElement("progress"); progressBar.className = "flex-grow h-2 bg-zinc-700 rounded-full overflow-hidden"; progressBar.setAttribute("max", "100"); progressBar.setAttribute("value", "0"); progressBar.style = ` -webkit-appearance: none; appearance: none; `; // Add custom styling for the progress bar const style = document.createElement('style'); style.textContent = ` progress::-webkit-progress-bar { background-color: #3f3f46; border-radius: 9999px; } progress::-webkit-progress-value { background-color: #e80860; border-radius: 9999px; } progress::-moz-progress-bar { background-color: #e80860; border-radius: 9999px; } `; document.head.appendChild(style); const percentSpan = document.createElement("span"); percentSpan.className = "text-sm text-gray-400 w-12 text-right"; percentSpan.textContent = "0%"; progressWrapper.appendChild(progressBar); progressWrapper.appendChild(percentSpan); listItem.appendChild(nameSpan); listItem.appendChild(progressWrapper); document.getElementById("upload-filelist").appendChild(listItem); return { element: listItem, progressBar: progressBar, percentSpan: percentSpan }; } function updateProgress(event) { const target = event.target; const progressBar = target.bar; const percentSpan = target.percent; if (event.lengthComputable) { const percentage = Math.floor((event.loaded / event.total) * 100); progressBar.setAttribute("value", percentage); percentSpan.textContent = percentage + "%"; } } function handleUploadComplete(event) { const target = event.target; const progressBar = target.bar; const row = target.row; const percentSpan = target.percent; percentSpan.style.visibility = "hidden"; progressBar.style.visibility = "hidden"; row.removeChild(progressBar.parentElement); const status = target.status; const responseWrapper = document.createElement("div"); responseWrapper.className = "w-full p-3 mt-2 rounded-lg transition-all duration-300"; row.appendChild(responseWrapper); try { if (status === 200) { let response; try { response = JSON.parse(target.responseText); } catch (e) { throw new Error('Invalid server response'); } if (response.success && response.files && response.files.length > 0) { // Success state responseWrapper.className += " bg-zinc-800 border border-zinc-700"; // Create container for URL and button const urlContainer = document.createElement("div"); urlContainer.className = "flex items-center justify-between gap-4"; // URL display const urlDisplay = document.createElement("div"); urlDisplay.className = "flex items-center gap-2 overflow-hidden"; // File icon const fileIcon = document.createElement("span"); fileIcon.innerHTML = ` `; // URL link const urlLink = document.createElement("a"); urlLink.href = response.files[0].url; urlLink.className = "text-emerald-500 hover:text-emerald-400 truncate"; urlLink.textContent = response.files[0].url.replace(/.*?:\/\//g, ""); // Add elements to URL display urlDisplay.appendChild(fileIcon); urlDisplay.appendChild(urlLink); // Create copy button const copyButton = document.createElement("button"); copyButton.className = "flex items-center gap-2 px-4 py-2 bg-zinc-700 hover:bg-zinc-600 rounded-lg transition-colors duration-200"; copyButton.innerHTML = ` Copy URL `; // Add click handler for copy button copyButton.addEventListener("click", function() { navigator.clipboard.writeText(response.files[0].url).then(function() { copyButton.innerHTML = ` Copied! `; setTimeout(() => { copyButton.innerHTML = ` Copy URL `; }, 2000); }); }); // File size info const sizeInfo = document.createElement("div"); sizeInfo.className = "text-sm text-gray-400 mt-2"; const fileSize = (response.files[0].size / 1024 / 1024).toFixed(2); sizeInfo.textContent = `File size: ${fileSize} MB`; // Add all elements to the response wrapper urlContainer.appendChild(urlDisplay); urlContainer.appendChild(copyButton); responseWrapper.appendChild(urlContainer); responseWrapper.appendChild(sizeInfo); } else { throw new Error(response.description || 'Upload failed'); } } else if (status === 413) { throw new Error('File too big! Maximum size is 256MB.'); } else if (status === 502) { throw new Error('Server error. Please try again.'); } else { throw new Error('Upload failed. Please try again.'); } } catch (error) { responseWrapper.className += " bg-red-900/20 border border-red-800"; responseWrapper.innerHTML = `
Error: ${error.message}
`; } } function uploadFile(file, fileElements) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("POST", "upload.php"); xhr.row = fileElements.element; xhr.bar = fileElements.progressBar; xhr.percent = fileElements.percentSpan; xhr.upload.bar = fileElements.progressBar; xhr.upload.percent = fileElements.percentSpan; xhr.addEventListener("load", function(event) { handleUploadComplete(event); resolve(); }); xhr.addEventListener("error", function() { handleUploadComplete({ target: { status: 0, row: fileElements.element, bar: fileElements.progressBar, percent: fileElements.percentSpan, responseText: JSON.stringify({ success: false, description: "Network error occurred" }) } }); reject(new Error('Network error')); }); xhr.upload.onprogress = updateProgress; const formData = new FormData(); formData.append("files[]", file); // Get selected expiry from radio buttons const selectedExpiry = document.querySelector('input[name="file-expiry"]:checked'); formData.append("expiry", selectedExpiry ? selectedExpiry.value : "30"); xhr.send(formData); }); } // Handle paste events window.addEventListener("paste", (e) => { const files = e.clipboardData.files; for (let i = 0; i < files.length; i++) { const file = files[i]; const fileElements = createFileElement(file); uploadQueue.add(file, fileElements); } }); // Prevent default drag behaviors function preventDefault(e) { e.stopPropagation(); e.preventDefault(); } // Drag and drop handling const uploadBtn = document.getElementById("upload-btn"); const uploadState = { dragCount: 0 }; function handleDragEnter(state, button, e) { preventDefault(e); if (state.dragCount === 0) { button.textContent = "Drop it here~"; } state.dragCount += 1; } function handleDragLeave(state, button, e) { preventDefault(e); state.dragCount -= 1; if (state.dragCount === 0) { button.textContent = "Select or drop file(s)"; } } // Event listeners for drag and drop window.addEventListener("dragenter", handleDragEnter.bind(null, uploadState, uploadBtn), false); window.addEventListener("dragleave", handleDragLeave.bind(null, uploadState, uploadBtn), false); window.addEventListener("drop", handleDragLeave.bind(null, uploadState, uploadBtn), false); window.addEventListener("dragover", preventDefault, false); // File input handling const uploadInput = document.getElementById("upload-input"); uploadInput.addEventListener("change", function(e) { const files = e.target.files; for (let i = 0; i < files.length; i++) { const file = files[i]; const fileElements = createFileElement(file); uploadQueue.add(file, fileElements); } }); // Upload button click handler uploadBtn.addEventListener("click", ((input, e) => { preventDefault(e); input.click(); }).bind(null, uploadInput)); // Drop handler uploadBtn.addEventListener("drop", ((state, button, e) => { preventDefault(e); handleDragLeave(state, button, e); const files = e.dataTransfer.files; for (let i = 0; i < files.length; i++) { const file = files[i]; const fileElements = createFileElement(file); uploadQueue.add(file, fileElements); } }).bind(null, uploadState, uploadBtn), false); // Add JS class to form document.getElementById("upload-form").classList.add("js"); });