better preview of files
This commit is contained in:
@@ -66,7 +66,7 @@ export class FilePreview {
|
||||
}
|
||||
|
||||
async previewFile(file) {
|
||||
const contentDiv = document.getElementById(`${this.options.containerId}Content`);
|
||||
const contentDiv = document.getElementById('filePreviewContent');
|
||||
const extension = file.name.split('.').pop().toLowerCase();
|
||||
|
||||
// Show loading spinner
|
||||
|
||||
@@ -9,6 +9,28 @@
|
||||
* - File details display
|
||||
*/
|
||||
|
||||
import { FilePreview } from './components/filePreview.js';
|
||||
|
||||
/**
|
||||
* Formats a file size in bytes to a human-readable string.
|
||||
* @param {number} bytes - The file size in bytes
|
||||
* @returns {string} Formatted file size string
|
||||
*/
|
||||
function formatFileSize(bytes) {
|
||||
if (!bytes) return '0 B';
|
||||
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
let size = bytes;
|
||||
let unitIndex = 0;
|
||||
|
||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||
size /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
let currentView = 'grid';
|
||||
let lastSelectedIndex = -1;
|
||||
let sortColumn = 'name'; // Set default sort column to name
|
||||
@@ -21,6 +43,14 @@ window.isAdmin = document.body.dataset.isAdmin === 'true';
|
||||
// Check if we're on the trash page
|
||||
const isTrashPage = window.location.pathname.includes('/trash');
|
||||
|
||||
// Initialize FilePreview component
|
||||
const filePreview = new FilePreview({
|
||||
containerId: 'filePreviewModal',
|
||||
onClose: () => {
|
||||
// Clean up any resources if needed
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Initializes the file view and fetches files.
|
||||
* Sets up the preferred view and initial file sorting.
|
||||
@@ -189,17 +219,31 @@ function renderFiles(files) {
|
||||
${isTrashPage ? `<th onclick="sortFiles('auto_delete')" style="cursor:pointer;">Auto Delete ${(sortColumn==='auto_delete') ? (sortDirection===1?'▲':'▼') : ''}</th>` : ''}
|
||||
<th class='file-actions'></th>
|
||||
</tr></thead><tbody>`;
|
||||
|
||||
files.forEach((file, idx) => {
|
||||
let icon = file.type === 'folder'
|
||||
? `<i class='fas fa-folder' style='font-size:1.5rem;color:var(--primary-color);'></i>`
|
||||
: `<i class='fas ${getFileIcon(file.name)}' style='font-size:1.5rem;color:var(--secondary-color);'></i>`;
|
||||
let size = file.size !== '-' ? (file.size > 0 ? (file.size < 1024*1024 ? (file.size/1024).toFixed(1)+' KB' : (file.size/1024/1024).toFixed(2)+' MB') : '0 KB') : '-';
|
||||
let icon = file.type === 'folder' ?
|
||||
`<i class="fas fa-folder" style="color:var(--primary-color);"></i>` :
|
||||
`<i class="fas ${getFileIcon(file.name)}" style="color:var(--secondary-color);"></i>`;
|
||||
|
||||
let size = file.type === 'folder' ? '-' : formatFileSize(file.size);
|
||||
let dblClickAction = file.type === 'folder' ?
|
||||
`ondblclick='navigateToFolder("${file.name}")'` : '';
|
||||
|
||||
let actionsArr = [];
|
||||
let dblClickAction = '';
|
||||
if (file.type === 'folder') {
|
||||
dblClickAction = `ondblclick=\"window.location.href='/room/${file.room_id}?path=${encodeURIComponent(file.path ? file.path + '/' + file.name : file.name)}'\"`;
|
||||
} else {
|
||||
dblClickAction = `ondblclick=\"window.location.href='/api/rooms/${file.room_id}/files/${encodeURIComponent(file.name)}?path=${encodeURIComponent(file.path)}'\"`;
|
||||
|
||||
// Add preview button for supported file types
|
||||
if (file.type !== 'folder') {
|
||||
const extension = file.name.split('.').pop().toLowerCase();
|
||||
const supportedTypes = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'mp4', 'webm', 'mp3', 'wav'];
|
||||
|
||||
if (supportedTypes.includes(extension)) {
|
||||
actionsArr.push(`
|
||||
<button class="btn btn-sm file-action-btn" title="Preview" onclick="event.stopPropagation(); previewFile(${idx})"
|
||||
style="background-color:var(--primary-opacity-8);color:var(--primary-color);">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
if (isTrashPage) {
|
||||
@@ -225,16 +269,29 @@ function renderFiles(files) {
|
||||
grid.innerHTML = table;
|
||||
} else {
|
||||
files.forEach((file, idx) => {
|
||||
let icon = file.type === 'folder'
|
||||
? `<i class='fas fa-folder' style='font-size:2.5rem;color:var(--primary-color);'></i>`
|
||||
: `<i class='fas ${getFileIcon(file.name)}' style='font-size:2.5rem;color:var(--secondary-color);'></i>`;
|
||||
let size = file.size !== '-' ? (file.size > 0 ? (file.size < 1024*1024 ? (file.size/1024).toFixed(1)+' KB' : (file.size/1024/1024).toFixed(2)+' MB') : '0 KB') : '-';
|
||||
let icon = file.type === 'folder' ?
|
||||
`<i class="fas fa-folder" style="color:var(--primary-color);"></i>` :
|
||||
`<i class="fas ${getFileIcon(file.name)}" style="color:var(--secondary-color);"></i>`;
|
||||
|
||||
let size = file.type === 'folder' ? '-' : formatFileSize(file.size);
|
||||
let dblClickAction = file.type === 'folder' ?
|
||||
`ondblclick='navigateToFolder("${file.name}")'` : '';
|
||||
|
||||
let actionsArr = [];
|
||||
let dblClickAction = '';
|
||||
if (file.type === 'folder') {
|
||||
dblClickAction = `ondblclick=\"window.location.href='/room/${file.room_id}?path=${encodeURIComponent(file.path ? file.path + '/' + file.name : file.name)}'\"`;
|
||||
} else {
|
||||
dblClickAction = `ondblclick=\"window.location.href='/api/rooms/${file.room_id}/files/${encodeURIComponent(file.name)}?path=${encodeURIComponent(file.path)}'\"`;
|
||||
|
||||
// Add preview button for supported file types
|
||||
if (file.type !== 'folder') {
|
||||
const extension = file.name.split('.').pop().toLowerCase();
|
||||
const supportedTypes = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'mp4', 'webm', 'mp3', 'wav'];
|
||||
|
||||
if (supportedTypes.includes(extension)) {
|
||||
actionsArr.push(`
|
||||
<button class="btn btn-sm file-action-btn" title="Preview" onclick="event.stopPropagation(); previewFile(${idx})"
|
||||
style="background-color:var(--primary-opacity-8);color:var(--primary-color);">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
if (isTrashPage) {
|
||||
@@ -606,6 +663,30 @@ function formatDate(dateString) {
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
// Add previewFile function
|
||||
async function previewFile(index) {
|
||||
const file = currentFiles[index];
|
||||
if (!file) return;
|
||||
|
||||
const fileUrl = `/api/rooms/${file.room_id}/files/${encodeURIComponent(file.name)}?path=${encodeURIComponent(file.path || '')}&preview=true`;
|
||||
|
||||
await filePreview.previewFile({
|
||||
name: file.name,
|
||||
url: fileUrl
|
||||
});
|
||||
}
|
||||
|
||||
// Make functions globally accessible
|
||||
window.previewFile = previewFile;
|
||||
window.restoreFile = restoreFile;
|
||||
window.showPermanentDeleteModal = showPermanentDeleteModal;
|
||||
window.showDetailsModal = showDetailsModal;
|
||||
window.toggleStar = toggleStar;
|
||||
window.sortFiles = sortFiles;
|
||||
window.navigateToFile = navigateToFile;
|
||||
window.showEmptyTrashModal = showEmptyTrashModal;
|
||||
window.permanentDeleteFile = permanentDeleteFile;
|
||||
|
||||
// Initialize search functionality
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initializeView();
|
||||
|
||||
@@ -27,7 +27,7 @@ export class ViewManager {
|
||||
this.sortColumn = 'name';
|
||||
this.sortDirection = 'asc';
|
||||
this.filePreview = new FilePreview({
|
||||
containerId: 'roomFilePreviewModal',
|
||||
containerId: 'filePreviewModal',
|
||||
onClose: () => {
|
||||
// Clean up any resources if needed
|
||||
}
|
||||
|
||||
27
templates/components/file_preview_modal.html
Normal file
27
templates/components/file_preview_modal.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!-- File Preview Modal -->
|
||||
<div class="modal fade" id="filePreviewModal" tabindex="-1" aria-labelledby="filePreviewModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="filePreviewModalLabel">File Preview</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<div id="filePreviewContent" class="d-flex justify-content-center align-items-center" style="min-height: 400px;">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="mt-2 text-muted">Loading preview...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<a id="downloadPreviewBtn" href="#" class="btn btn-primary" download>
|
||||
<i class="fas fa-download me-1"></i>Download
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -248,7 +248,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Move Modal -->
|
||||
<div class="modal fade" id="moveModal" tabindex="-1" aria-labelledby="moveModalLabel" aria-hidden="true">
|
||||
<div id="moveModal" class="modal fade" tabindex="-1" aria-labelledby="moveModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@@ -272,6 +272,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Include modals -->
|
||||
{% include 'components/details_modal.html' %}
|
||||
{% include 'components/file_preview_modal.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<option value="file_upload">File Upload</option>
|
||||
<option value="file_delete">File Delete</option>
|
||||
<option value="file_download">File Download</option>
|
||||
<option value="file_preview">File Preview</option>
|
||||
<option value="file_restore">File Restore</option>
|
||||
<option value="file_move">File Move</option>
|
||||
<option value="file_rename">File Rename</option>
|
||||
@@ -90,6 +91,8 @@
|
||||
<span class="badge bg-danger">File Delete</span>
|
||||
{% elif event.event_type == 'file_download' %}
|
||||
<span class="badge bg-info">File Download</span>
|
||||
{% elif event.event_type == 'file_preview' %}
|
||||
<span class="badge bg-info">File Preview</span>
|
||||
{% elif event.event_type == 'file_restore' %}
|
||||
<span class="badge bg-warning">File Restore</span>
|
||||
{% elif event.event_type == 'file_move' %}
|
||||
|
||||
@@ -38,9 +38,10 @@
|
||||
</div>
|
||||
|
||||
{% include 'components/details_modal.html' %}
|
||||
{% include 'components/file_preview_modal.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script src="{{ url_for('static', filename='js/file-grid.js', v=config.CSS_VERSION) }}"></script>
|
||||
<script type="module" src="{{ url_for('static', filename='js/file-grid.js', v=config.CSS_VERSION) }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/starred.js', v=config.CSS_VERSION) }}"></script>
|
||||
{% endblock %}
|
||||
@@ -44,9 +44,10 @@
|
||||
{% include 'components/details_modal.html' %}
|
||||
{% include 'components/permanent_delete_modal.html' %}
|
||||
{% include 'components/empty_trash_modal.html' %}
|
||||
{% include 'components/file_preview_modal.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script src="{{ url_for('static', filename='js/file-grid.js', v=config.CSS_VERSION) }}"></script>
|
||||
<script type="module" src="{{ url_for('static', filename='js/file-grid.js', v=config.CSS_VERSION) }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/trash.js', v=config.CSS_VERSION) }}"></script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user