document.addEventListener('DOMContentLoaded', () => { const dropZone = document.getElementById('dropZone'); const fileInput = document.getElementById('fileInput'); const browseBtn = document.getElementById('browseBtn'); const progressContainer = document.getElementById('progressContainer'); const uploadProgress = document.getElementById('uploadProgress'); const progressText = document.getElementById('progressText'); const errorContainer = document.getElementById('errorContainer'); const resultContainer = document.getElementById('resultContainer'); const downloadLink = document.getElementById('downloadLink'); const copyBtn = document.getElementById('copyBtn'); const copySuccess = document.getElementById('copySuccess'); // Исправление 1: Предотвращаем всплытие события для кнопки browseBtn.addEventListener('click', (e) => { e.stopPropagation(); // Блокируем всплытие события fileInput.click(); }); // Исправление 2: Убрали прямой вызов click из dropZone dropZone.addEventListener('click', (e) => { // Открываем только при клике на саму зону, но не на её дочерние элементы if (e.target === dropZone) { fileInput.click(); } }); fileInput.addEventListener('change', handleFileSelect); ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ['dragenter', 'dragover'].forEach(eventName => { dropZone.addEventListener(eventName, () => { dropZone.classList.add('drag-over'); }, false); }); ['dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, () => { dropZone.classList.remove('drag-over'); }, false); }); dropZone.addEventListener('drop', handleDrop, false); copyBtn.addEventListener('click', copyToClipboard); function handleFileSelect(e) { if (e.target.files.length > 0) { processFile(e.target.files[0]); } } function handleDrop(e) { const files = e.dataTransfer.files; if (files.length > 0) { processFile(files[0]); } } function processFile(file) { hideError(); resultContainer.style.display = 'none'; // Исправление 3: Синхронизация лимита с сообщением (150MB) if (file.size > 150 * 1024 * 1024) { showError('File is too large. Maximum size: 150MB'); return; } // Проверка на русские буквы в имени файла (добавленный блок) const russianLettersRegex = /[а-яёА-ЯЁ]/; if (russianLettersRegex.test(file.name)) { showError('File name contains Russian letters. Please rename the file using only English characters.'); return; } // 1. Добавляем список разрешенных MIME-типов const allowedMimeTypes = [ "application/pdf", "text/plain", "image/jpeg", "image/png", "image/gif", "image/bmp", "audio/mpeg", "video/mp4", "application/zip", "application/x-tar", "application/gzip", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ]; // 2. Проверяем MIME-тип файла if (!allowedMimeTypes.includes(file.type)) { showError(`Unsupported file type: ${file.type || 'unknown type'}. Allowed types: ${allowedMimeTypes.join(', ')}`); return; } progressContainer.style.display = 'block'; uploadProgress.style.width = '0%'; progressText.textContent = '0%'; uploadFile(file); } function uploadFile(file) { const formData = new FormData(); formData.append('file', file); const xhr = new XMLHttpRequest(); // Исправление 4: Добавили обработку ошибок для Safari xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 0) { showError('Network error or blocked by browser'); } } }; xhr.upload.addEventListener('progress', (e) => { if (e.lengthComputable) { const percent = Math.round((e.loaded / e.total) * 100); uploadProgress.style.width = `${percent}%`; progressText.textContent = `${percent}%`; } }); xhr.addEventListener('load', () => { if (xhr.status >= 200 && xhr.status < 300) { try { const response = JSON.parse(xhr.responseText); showResult(response.s3_key); } catch (e) { showError('Error processing server response'); } } else { try { const errorResponse = JSON.parse(xhr.responseText); showError(errorResponse.detail || 'File upload error'); } catch { showError(`Error ${xhr.status}: ${xhr.statusText}`); } } }); xhr.addEventListener('error', () => { showError('Network error. Check your internet connection'); }); xhr.addEventListener('abort', () => { showError('Upload canceled'); }); xhr.open('POST', '/api/v1/upload', true); xhr.send(formData); } function showResult(s3Key) { const downloadUrl = `https://app.nonstudents.online/api/v1/download/${s3Key}`; downloadLink.value = downloadUrl; resultContainer.style.display = 'block'; progressContainer.style.display = 'none'; } function copyToClipboard() { downloadLink.select(); document.execCommand('copy'); copySuccess.style.display = 'flex'; setTimeout(() => { copySuccess.style.display = 'none'; }, 2000); } function showError(message) { errorContainer.textContent = message; errorContainer.style.display = 'block'; progressContainer.style.display = 'none'; } function hideError() { errorContainer.style.display = 'none'; errorContainer.textContent = ''; } });