File preview

This commit is contained in:
2025-06-01 12:31:10 +02:00
parent c0a97a1714
commit aeefd17b10
8 changed files with 280 additions and 8 deletions

View File

@@ -0,0 +1,141 @@
export class FilePreview {
constructor(options = {}) {
this.options = {
containerId: options.containerId || 'filePreviewModal',
onClose: options.onClose || (() => {}),
...options
};
this.modal = null;
this.init();
}
init() {
// Create modal if it doesn't exist
if (!document.getElementById(this.options.containerId)) {
const modalHtml = `
<div class="modal fade" id="${this.options.containerId}" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">File Preview</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="${this.options.containerId}Content" class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
}
this.modal = new bootstrap.Modal(document.getElementById(this.options.containerId));
// Add event listener for modal close
document.getElementById(this.options.containerId).addEventListener('hidden.bs.modal', () => {
this.options.onClose();
});
}
getFileIcon(filename) {
const extension = filename.split('.').pop().toLowerCase();
const iconMap = {
pdf: 'fa-file-pdf',
doc: 'fa-file-word',
docx: 'fa-file-word',
xls: 'fa-file-excel',
xlsx: 'fa-file-excel',
ppt: 'fa-file-powerpoint',
pptx: 'fa-file-powerpoint',
txt: 'fa-file-alt',
jpg: 'fa-file-image',
jpeg: 'fa-file-image',
png: 'fa-file-image',
gif: 'fa-file-image',
zip: 'fa-file-archive',
rar: 'fa-file-archive',
mp3: 'fa-file-audio',
mp4: 'fa-file-video'
};
return iconMap[extension] || 'fa-file';
}
async previewFile(file) {
const contentDiv = document.getElementById(`${this.options.containerId}Content`);
const extension = file.name.split('.').pop().toLowerCase();
// Show loading spinner
contentDiv.innerHTML = `
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
`;
try {
// Handle different file types
if (['jpg', 'jpeg', 'png', 'gif'].includes(extension)) {
// Image preview
contentDiv.innerHTML = `
<img src="${file.url}" class="img-fluid" alt="${file.name}" style="max-height: 70vh;">
`;
} else if (['pdf'].includes(extension)) {
// PDF preview
contentDiv.innerHTML = `
<iframe src="${file.url}" width="100%" height="70vh" frameborder="0"></iframe>
`;
} else if (['mp4', 'webm'].includes(extension)) {
// Video preview
contentDiv.innerHTML = `
<video controls class="w-100" style="max-height: 70vh;">
<source src="${file.url}" type="video/${extension}">
Your browser does not support the video tag.
</video>
`;
} else if (['mp3', 'wav'].includes(extension)) {
// Audio preview
contentDiv.innerHTML = `
<audio controls class="w-100">
<source src="${file.url}" type="audio/${extension}">
Your browser does not support the audio tag.
</audio>
`;
} else {
// Default preview for other file types
contentDiv.innerHTML = `
<div class="text-center py-5">
<i class="fas ${this.getFileIcon(file.name)} fa-4x mb-3" style="color: var(--secondary-color);"></i>
<h5 class="mb-3">${file.name}</h5>
<p class="text-muted">Preview not available for this file type.</p>
<a href="${file.url}" class="btn btn-primary" download>
<i class="fas fa-download me-2"></i>Download
</a>
</div>
`;
}
} catch (error) {
console.error('Error previewing file:', error);
contentDiv.innerHTML = `
<div class="text-center py-5">
<i class="fas fa-exclamation-circle fa-4x mb-3 text-danger"></i>
<h5 class="mb-3">Error Loading Preview</h5>
<p class="text-muted">Unable to load file preview. Please try downloading the file instead.</p>
<a href="${file.url}" class="btn btn-primary" download>
<i class="fas fa-download me-2"></i>Download
</a>
</div>
`;
}
// Show the modal
this.modal.show();
}
close() {
this.modal.hide();
}
}

View File

@@ -13,6 +13,8 @@
* @classdesc Manages the visual representation and interaction of files in the room interface.
* Handles view switching, file rendering, sorting, and UI updates.
*/
import { FilePreview } from '../components/filePreview.js';
export class ViewManager {
/**
* Creates a new ViewManager instance.
@@ -24,6 +26,12 @@ export class ViewManager {
this.currentView = 'grid';
this.sortColumn = 'name';
this.sortDirection = 'asc';
this.filePreview = new FilePreview({
containerId: 'roomFilePreviewModal',
onClose: () => {
// Clean up any resources if needed
}
});
console.log('[ViewManager] Initialized with roomManager:', roomManager);
}
@@ -349,6 +357,19 @@ export class ViewManager {
</button>
`);
} else {
// Check if file type is supported for preview
const extension = file.name.split('.').pop().toLowerCase();
const supportedTypes = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'mp4', 'webm', 'mp3', 'wav'];
if (supportedTypes.includes(extension)) {
actions.push(`
<button class="btn btn-sm file-action-btn" title="Preview" onclick="window.roomManager.viewManager.previewFile(${index})"
style="background-color:var(--primary-opacity-8);color:var(--primary-color);">
<i class="fas fa-eye"></i>
</button>
`);
}
if (this.roomManager.canDownload) {
actions.push(`
<button class="btn btn-sm file-action-btn" title="Download" onclick="window.roomManager.fileManager.downloadFile('${file.name}', '${file.path || ''}')"
@@ -493,4 +514,16 @@ export class ViewManager {
selectedCount: selectedItems.length
});
}
async previewFile(index) {
const file = this.roomManager.fileManager.currentFiles[index];
if (!file) return;
const fileUrl = `/api/rooms/${this.roomManager.roomId}/files/${encodeURIComponent(file.name)}?path=${encodeURIComponent(file.path || '')}&preview=true`;
await this.filePreview.previewFile({
name: file.name,
url: fileUrl
});
}
}

View File

@@ -360,4 +360,20 @@ document.addEventListener('DOMContentLoaded', function() {
});
});
}
// Add event listener for download button
const downloadEventsBtn = document.getElementById('downloadEvents');
if (downloadEventsBtn) {
downloadEventsBtn.addEventListener('click', function() {
const eventType = document.getElementById('eventTypeFilter').value;
const dateRange = document.getElementById('dateRangeFilter').value;
const userId = document.getElementById('userFilter').value;
// Construct download URL with current filters
const downloadUrl = `/settings/events/download?event_type=${eventType}&date_range=${dateRange}&user_id=${userId}`;
// Trigger download
window.location.href = downloadUrl;
});
}
});