function duplicateFileReport(incoming = []) { const used = new Set(files.map((item) => normalizedFileName(item.displayName))); const duplicates = []; const unique = []; incoming.forEach((item) => { const key = normalizedFileName(item.displayName); if (used.has(key)) { duplicates.push(item); return; } used.add(key); unique.push(item); }); return { unique, duplicates }; } function addFiles(fileList) { if (!uploadsEnabled) { showToast("Guest uploads are disabled.", "warning"); return; } if (uploadLocked) { showToast("This box is sealed. Clear it to create a fresh upload.", "warning"); return; } const incoming = Array.from(fileList || []).map((file) => makeQueuedFile(file)); if (!incoming.length) return; const { unique, duplicates } = duplicateFileReport(incoming); if (unique.length) { files.push(...unique); setShareUrl(""); renderFiles(); const warning = quotaWarningMessage(); if (warning) showWarningDialog("Quota warning", warning); } if (duplicates.length) showDuplicateDialog(duplicates); if (unique.length) setStatus(`${unique.length} file${unique.length === 1 ? "" : "s"} added to queue`); if (duplicates.length && !unique.length) setStatus(`${duplicates.length} duplicate file${duplicates.length === 1 ? "" : "s"} need your choice`); } function showDuplicateDialog(duplicates) { pendingDuplicateFiles = duplicates; const list = duplicates.map((item) => `
  • ${htmlEscape(item.displayName)} ${formatBytes(item.file.size)}
  • `).join(""); showTemplatePopup("Duplicate file names", "duplicate", { list }) .then(() => document.querySelector("#duplicate-append")?.focus()); showToast("Duplicate names found. Choose skip or append numbers.", "warning"); } function appendPendingDuplicates() { if (!pendingDuplicateFiles.length) return; const used = new Set(files.map((item) => normalizedFileName(item.displayName))); pendingDuplicateFiles.forEach((item) => { item.displayName = nextIncrementedFileName(item.displayName, used); files.push(item); }); const count = pendingDuplicateFiles.length; pendingDuplicateFiles = []; closeDoc(); setShareUrl(""); renderFiles(); showToast("Duplicate files added with numbered names.", "info"); setStatus(`${count} duplicate file${count === 1 ? "" : "s"} added with numbered names`); } function removeFile(index) { if (uploadLocked) { showToast("Box already created. Clear it before editing the queue.", "warning"); return; } const [removed] = files.splice(index, 1); if (removed?.previewURL) URL.revokeObjectURL(removed.previewURL); setShareUrl(""); renderFiles(); setStatus("File removed from queue"); } function clearQueue() { files.forEach((item) => { if (item.previewURL) URL.revokeObjectURL(item.previewURL); }); files = []; pendingDuplicateFiles = []; uploadLocked = false; completedImpactKeys = new Set(); overallImpactDone = false; stopStatusAnimation(); setBoxOptionsLocked(false); setShareUrl(""); if (el.fileInput) { el.fileInput.value = ""; el.fileInput.disabled = !uploadsEnabled; } el.dropzone?.classList.remove("is-locked"); renderFiles(); setStatus(uploadsEnabled ? "Queue cleared" : "Guest uploads are disabled"); showToast("Queue cleared."); } function confirmClearQueue() { if (!files.length && !shareUrl) { showToast("Nothing to clear."); return; } showTemplatePopup("Clear WarpBox?", "clear") .then(() => document.querySelector("#confirm-clear-no")?.focus()); }