// File upload modal and batch processing utilities // 文件上传模态框和批量处理工具 import { $, $id, createElement, on, addClass, removeClass } from './util.dom.js'; import { formatFileSize } from './util.file.js'; import { t } from './util.i18n.js'; // File upload modal state // 文件上传模态框状态 let uploadModal = null; let selectedFiles = new Map(); let fileIdCounter = 0; let onSendCallback = null; // Listen for language changes to update modal text // 监听语言变更以更新模态框文本 window.addEventListener('languageChange', () => { if (uploadModal) { updateModalTexts(); } }); // Update modal texts when language changes // 语言切换时更新模态框文本 function updateModalTexts() { if (!uploadModal) return; // Update modal title const modalTitle = uploadModal.querySelector('.file-upload-header h3'); if (modalTitle) { modalTitle.textContent = t('file.upload_files', 'Upload Files'); } // Update file list title const fileListTitle = uploadModal.querySelector('.file-list-title'); if (fileListTitle) { fileListTitle.textContent = t('file.selected_files', 'Selected Files'); } // Update clear all button const clearAllBtn = uploadModal.querySelector('.file-clear-all-btn'); if (clearAllBtn) { clearAllBtn.textContent = t('file.clear_all', 'Clear All'); } // Update cancel button const cancelBtn = uploadModal.querySelector('.file-upload-cancel-btn'); if (cancelBtn) { cancelBtn.textContent = t('file.cancel', 'Cancel'); } // Update send files button const sendBtn = uploadModal.querySelector('.file-upload-send-btn'); if (sendBtn) { sendBtn.textContent = t('file.send_files', 'Send Files'); } // Update drag drop text const dragDropText = uploadModal.querySelector('.file-drop-text'); if (dragDropText) { dragDropText.innerHTML = `

${t('file.drag_drop', 'Drag and drop files here')}

${t('file.or', 'or')}

`; // Re-attach browse button event const browseBtn = dragDropText.querySelector('.file-browse-btn'); if (browseBtn) { on(browseBtn, 'click', handleBrowseClick); } } // Update summary if files are selected if (selectedFiles.size > 0) { updateFileListDisplay(); } } // Generate unique file ID // 生成唯一文件ID function generateFileId() { return 'upload_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); } // Create file upload modal // 创建文件上传模态框 function createUploadModal() { const modal = createElement('div', { class: 'file-upload-modal' }, `

${t('file.upload_files', 'Upload Files')}

📁

${t('file.drag_drop', 'Drag and drop files here')}

${t('file.or', 'or')}

`); return modal; } // Show file upload modal // 显示文件上传模态框 export function showFileUploadModal(onSend) { if (uploadModal) { document.body.removeChild(uploadModal); } onSendCallback = onSend; selectedFiles.clear(); uploadModal = createUploadModal(); document.body.appendChild(uploadModal); setupModalEvents(); // Focus and animation setTimeout(() => { addClass(uploadModal, 'show'); }, 10); } // Hide file upload modal // 隐藏文件上传模态框 function hideUploadModal() { if (!uploadModal) return; removeClass(uploadModal, 'show'); setTimeout(() => { if (uploadModal && uploadModal.parentNode) { document.body.removeChild(uploadModal); } uploadModal = null; selectedFiles.clear(); onSendCallback = null; // 通知主模块重置拖拽标志位 window.dispatchEvent(new CustomEvent('fileUploadModalClosed')); }, 300); } // Setup modal event listeners // 设置模态框事件监听器 function setupModalEvents() { if (!uploadModal) return; const overlay = $('.file-upload-overlay', uploadModal); const closeBtn = $('.file-upload-close', uploadModal); const cancelBtn = $('.file-upload-cancel-btn', uploadModal); const sendBtn = $('.file-upload-send-btn', uploadModal); const browseBtn = $('.file-browse-btn', uploadModal); const fileInput = $('#file-upload-input', uploadModal); const dropZone = $('#file-drop-zone', uploadModal); const clearAllBtn = $('.file-clear-all-btn', uploadModal); // Close modal events on(overlay, 'click', hideUploadModal); on(closeBtn, 'click', hideUploadModal); on(cancelBtn, 'click', hideUploadModal); // Browse files on(browseBtn, 'click', () => fileInput.click()); on(fileInput, 'change', handleFileInputChange); // Drag and drop on(dropZone, 'dragover', handleDragOver); on(dropZone, 'dragleave', handleDragLeave); on(dropZone, 'drop', handleDrop); // Clear all files on(clearAllBtn, 'click', clearAllFiles); // Send files on(sendBtn, 'click', handleSendFiles); // Prevent default drag behaviors on document on(document, 'dragover', (e) => e.preventDefault()); on(document, 'drop', (e) => e.preventDefault()); } // Handle file input change // 处理文件输入变化 function handleFileInputChange(e) { const files = Array.from(e.target.files); addFiles(files); e.target.value = ''; // Clear input } // Handle drag over // 处理拖拽悬停 function handleDragOver(e) { e.preventDefault(); e.stopPropagation(); addClass(e.currentTarget, 'drag-over'); } // Handle drag leave // 处理拖拽离开 function handleDragLeave(e) { e.preventDefault(); e.stopPropagation(); removeClass(e.currentTarget, 'drag-over'); } // Handle drop // 处理文件拖放 function handleDrop(e) { e.preventDefault(); e.stopPropagation(); removeClass(e.currentTarget, 'drag-over'); const files = Array.from(e.dataTransfer.files); addFiles(files); } // Add files to selection // 添加文件到选择列表 function addFiles(files) { files.forEach(file => { const fileId = generateFileId(); selectedFiles.set(fileId, file); }); updateFileList(); updateSendButton(); } // Remove file from selection // 从选择列表中移除文件 function removeFile(fileId) { selectedFiles.delete(fileId); updateFileList(); updateSendButton(); } // Clear all files // 清空所有文件 function clearAllFiles() { selectedFiles.clear(); updateFileList(); updateSendButton(); } // Update file list display // 更新文件列表显示 function updateFileList() { if (!uploadModal) return; const fileList = $('#file-list', uploadModal); const fileListContainer = $('#file-list-container', uploadModal); const fileListSummary = $('#file-list-summary', uploadModal); const dropZone = $('#file-drop-zone', uploadModal); if (selectedFiles.size === 0) { fileListContainer.style.display = 'none'; dropZone.style.display = 'flex'; return; } fileListContainer.style.display = 'block'; dropZone.style.display = 'none'; // Update file list fileList.innerHTML = ''; for (const [fileId, file] of selectedFiles) { const fileItem = createElement('div', { class: 'file-item', 'data-file-id': fileId }, `
${file.name}
${formatFileSize(file.size)}
`); fileList.appendChild(fileItem); // Add remove event const removeBtn = $('.file-item-remove', fileItem); on(removeBtn, 'click', (e) => { e.preventDefault(); removeFile(fileId); }); } // Update summary const totalSize = Array.from(selectedFiles.values()).reduce((sum, file) => sum + file.size, 0); const summaryText = t('file.files_selected', '{count} files selected, {size} total') .replace('{count}', selectedFiles.size) .replace('{size}', formatFileSize(totalSize)); fileListSummary.innerHTML = summaryText; } // Update send button state // 更新发送按钮状态 function updateSendButton() { if (!uploadModal) return; const sendBtn = $('.file-upload-send-btn', uploadModal); sendBtn.disabled = selectedFiles.size === 0; } // Handle send files // 处理发送文件 async function handleSendFiles() { if (selectedFiles.size === 0 || !onSendCallback) return; const files = Array.from(selectedFiles.values()); try { // Close modal first hideUploadModal(); // Send files through callback await onSendCallback(files); } catch (error) { console.error('Error sending files:', error); if (window.addSystemMsg) { window.addSystemMsg(`${t('system.file_send_failed', 'Failed to send files:')} ${error.message}`); } } } // Handle keyboard events // 处理键盘事件 on(document, 'keydown', (e) => { if (!uploadModal) return; if (e.key === 'Escape') { hideUploadModal(); } });