Started room separation
This commit is contained in:
262
static/js/rooms/uploadManager.js
Normal file
262
static/js/rooms/uploadManager.js
Normal file
@@ -0,0 +1,262 @@
|
||||
export class UploadManager {
|
||||
constructor(roomManager) {
|
||||
this.roomManager = roomManager;
|
||||
this.pendingUploads = [];
|
||||
this.pendingUploadIdx = 0;
|
||||
this.overwriteAll = false;
|
||||
this.skipAll = false;
|
||||
|
||||
// Initialize upload-related elements
|
||||
this.uploadBtn = document.getElementById('uploadBtn');
|
||||
this.fileInput = document.getElementById('fileInput');
|
||||
this.uploadForm = document.getElementById('uploadForm');
|
||||
this.fileGrid = document.getElementById('fileGrid');
|
||||
this.dropZoneOverlay = document.getElementById('dropZoneOverlay');
|
||||
this.uploadProgressContainer = document.getElementById('uploadProgressContainer');
|
||||
this.uploadProgressBar = document.getElementById('uploadProgressBar');
|
||||
this.uploadProgressText = document.getElementById('uploadProgressText');
|
||||
|
||||
this.initializeUploadHandlers();
|
||||
}
|
||||
|
||||
initializeUploadHandlers() {
|
||||
if (!this.roomManager.canUpload) return;
|
||||
|
||||
// Initialize drag and drop
|
||||
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||
this.fileGrid.addEventListener(eventName, this.preventDefaults.bind(this), false);
|
||||
document.body.addEventListener(eventName, this.preventDefaults.bind(this), false);
|
||||
});
|
||||
|
||||
['dragenter', 'dragover'].forEach(eventName => {
|
||||
this.fileGrid.addEventListener(eventName, this.highlight.bind(this), false);
|
||||
});
|
||||
|
||||
['dragleave', 'drop'].forEach(eventName => {
|
||||
this.fileGrid.addEventListener(eventName, this.unhighlight.bind(this), false);
|
||||
});
|
||||
|
||||
// Handle dropped files
|
||||
this.fileGrid.addEventListener('drop', this.handleDrop.bind(this), false);
|
||||
|
||||
// Handle file input change
|
||||
this.uploadBtn.addEventListener('click', () => this.fileInput.click());
|
||||
this.fileInput.addEventListener('change', this.handleFileSelect.bind(this));
|
||||
}
|
||||
|
||||
preventDefaults(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
highlight() {
|
||||
this.dropZoneOverlay.style.display = 'block';
|
||||
}
|
||||
|
||||
unhighlight() {
|
||||
this.dropZoneOverlay.style.display = 'none';
|
||||
}
|
||||
|
||||
async handleDrop(e) {
|
||||
const dt = e.dataTransfer;
|
||||
const files = dt.files;
|
||||
|
||||
if (files.length > 0) {
|
||||
await this.startUpload(Array.from(files));
|
||||
}
|
||||
}
|
||||
|
||||
async handleFileSelect() {
|
||||
if (!this.fileInput.files.length) return;
|
||||
await this.startUpload(Array.from(this.fileInput.files));
|
||||
}
|
||||
|
||||
async startUpload(files) {
|
||||
this.uploadProgressContainer.style.display = 'block';
|
||||
this.uploadProgressBar.style.width = '0%';
|
||||
this.uploadProgressBar.classList.remove('bg-success');
|
||||
this.uploadProgressBar.classList.add('bg-info');
|
||||
this.uploadProgressText.textContent = '';
|
||||
|
||||
this.pendingUploads = files;
|
||||
this.pendingUploadIdx = 0;
|
||||
this.overwriteAll = false;
|
||||
this.skipAll = false;
|
||||
|
||||
await this.uploadFilesSequentially();
|
||||
}
|
||||
|
||||
async uploadFilesSequentially() {
|
||||
let completedFiles = 0;
|
||||
let currentFileIndex = 0;
|
||||
|
||||
const updateProgress = () => {
|
||||
if (!this.pendingUploads || currentFileIndex >= this.pendingUploads.length) {
|
||||
this.uploadProgressBar.style.width = '100%';
|
||||
this.uploadProgressBar.textContent = '100%';
|
||||
this.uploadProgressText.textContent = 'Upload complete!';
|
||||
return;
|
||||
}
|
||||
|
||||
const progress = Math.round((completedFiles / this.pendingUploads.length) * 100);
|
||||
this.uploadProgressBar.style.width = progress + '%';
|
||||
this.uploadProgressBar.textContent = progress + '%';
|
||||
this.uploadProgressText.textContent = `Uploading ${this.pendingUploads[currentFileIndex].name} (${currentFileIndex + 1}/${this.pendingUploads.length})`;
|
||||
};
|
||||
|
||||
const processNextFile = async () => {
|
||||
if (currentFileIndex >= this.pendingUploads.length) {
|
||||
// All files processed
|
||||
this.uploadProgressBar.style.width = '100%';
|
||||
this.uploadProgressBar.textContent = '100%';
|
||||
this.uploadProgressBar.classList.remove('bg-info');
|
||||
this.uploadProgressBar.classList.add('bg-success');
|
||||
this.uploadProgressText.textContent = 'Upload complete!';
|
||||
|
||||
// Reset state
|
||||
this.pendingUploads = null;
|
||||
this.pendingUploadIdx = null;
|
||||
this.overwriteAll = false;
|
||||
this.skipAll = false;
|
||||
|
||||
// Hide progress after delay
|
||||
setTimeout(() => {
|
||||
this.uploadProgressContainer.style.display = 'none';
|
||||
this.uploadProgressText.textContent = '';
|
||||
this.uploadProgressBar.style.backgroundColor = '#16767b';
|
||||
this.uploadProgressBar.style.color = '#fff';
|
||||
}, 3000);
|
||||
|
||||
// Refresh file list
|
||||
await this.roomManager.fileManager.fetchFiles();
|
||||
return;
|
||||
}
|
||||
|
||||
const file = this.pendingUploads[currentFileIndex];
|
||||
const formData = new FormData(this.uploadForm);
|
||||
if (this.roomManager.currentPath) {
|
||||
formData.append('path', this.roomManager.currentPath);
|
||||
}
|
||||
formData.set('file', file);
|
||||
|
||||
try {
|
||||
updateProgress();
|
||||
|
||||
let uploadFormData = formData;
|
||||
if (this.overwriteAll) {
|
||||
uploadFormData = new FormData(this.uploadForm);
|
||||
if (this.roomManager.currentPath) {
|
||||
uploadFormData.append('path', this.roomManager.currentPath);
|
||||
}
|
||||
uploadFormData.set('file', file);
|
||||
uploadFormData.append('overwrite', 'true');
|
||||
}
|
||||
|
||||
const response = await this.uploadFile(uploadFormData);
|
||||
|
||||
if (response.success) {
|
||||
completedFiles++;
|
||||
currentFileIndex++;
|
||||
updateProgress();
|
||||
await processNextFile();
|
||||
} else if (response.error === 'File type not allowed') {
|
||||
this.handleFileTypeError(file);
|
||||
currentFileIndex++;
|
||||
updateProgress();
|
||||
await processNextFile();
|
||||
} else if (response.error === 'File exists') {
|
||||
const result = await this.handleFileExists(file, uploadFormData);
|
||||
if (result.continue) {
|
||||
currentFileIndex++;
|
||||
updateProgress();
|
||||
await processNextFile();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Upload error:', error);
|
||||
this.uploadProgressText.textContent = `Error uploading ${file.name}`;
|
||||
this.uploadProgressBar.style.backgroundColor = '#ef4444';
|
||||
this.uploadProgressBar.style.color = '#fff';
|
||||
currentFileIndex++;
|
||||
updateProgress();
|
||||
await processNextFile();
|
||||
}
|
||||
};
|
||||
|
||||
await processNextFile();
|
||||
}
|
||||
|
||||
async uploadFile(formData) {
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
const response = await fetch(`/api/rooms/${this.roomManager.roomId}/files/upload`, {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRFToken': csrfToken },
|
||||
body: formData
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
return {
|
||||
success: response.ok,
|
||||
error: result.error
|
||||
};
|
||||
}
|
||||
|
||||
handleFileTypeError(file) {
|
||||
const allowedTypes = [
|
||||
'Documents: PDF, DOCX, DOC, TXT, RTF, ODT, MD, CSV',
|
||||
'Spreadsheets: XLSX, XLS, ODS, XLSM',
|
||||
'Presentations: PPTX, PPT, ODP',
|
||||
'Images: JPG, JPEG, PNG, GIF, BMP, SVG, WEBP, TIFF',
|
||||
'Archives: ZIP, RAR, 7Z, TAR, GZ',
|
||||
'Code/Text: PY, JS, HTML, CSS, JSON, XML, SQL, SH, BAT',
|
||||
'Audio: MP3, WAV, OGG, M4A, FLAC',
|
||||
'Video: MP4, AVI, MOV, WMV, FLV, MKV, WEBM',
|
||||
'CAD/Design: DWG, DXF, AI, PSD, EPS, INDD',
|
||||
'Other: EML, MSG, VCF, ICS'
|
||||
].join('\n');
|
||||
|
||||
const uploadError = document.getElementById('uploadError');
|
||||
const uploadErrorContent = document.getElementById('uploadErrorContent');
|
||||
|
||||
const newError = `<div class="mb-2"><strong>File type not allowed:</strong> ${file.name}</div>`;
|
||||
if (uploadErrorContent.innerHTML === '') {
|
||||
uploadErrorContent.innerHTML = newError + `<div class='mt-2'><strong>Allowed file types:</strong><br>${allowedTypes}</div>`;
|
||||
} else {
|
||||
uploadErrorContent.innerHTML = newError + uploadErrorContent.innerHTML;
|
||||
}
|
||||
|
||||
uploadError.style.display = 'block';
|
||||
this.uploadProgressBar.style.backgroundColor = '#ef4444';
|
||||
this.uploadProgressBar.style.color = '#fff';
|
||||
}
|
||||
|
||||
async handleFileExists(file, formData) {
|
||||
if (this.overwriteAll) {
|
||||
formData.append('overwrite', 'true');
|
||||
const response = await this.uploadFile(formData);
|
||||
return { continue: response.success };
|
||||
}
|
||||
|
||||
if (this.skipAll) {
|
||||
return { continue: true };
|
||||
}
|
||||
|
||||
const result = await this.roomManager.modalManager.showOverwriteModal(file.name);
|
||||
|
||||
if (result === 'overwrite' || result === 'overwrite_all') {
|
||||
if (result === 'overwrite_all') {
|
||||
this.overwriteAll = true;
|
||||
}
|
||||
formData.append('overwrite', 'true');
|
||||
const response = await this.uploadFile(formData);
|
||||
return { continue: response.success };
|
||||
} else if (result === 'skip' || result === 'skip_all') {
|
||||
if (result === 'skip_all') {
|
||||
this.skipAll = true;
|
||||
}
|
||||
return { continue: true };
|
||||
}
|
||||
|
||||
return { continue: false };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user