// Main JavaScript file for Flask Files document.addEventListener('DOMContentLoaded', function () { // Initialize components initializeViewToggle(); initializeFolderNavigation(); initializeModals(); initializeContextMenu(); initializeUploadFunctionality(); // Register service worker if supported if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/static/js/service-worker.js') .then(function (registration) { console.log('Service Worker registered with scope:', registration.scope); }).catch(function (error) { console.log('Service Worker registration failed:', error); }); } // Initialize flash message close buttons initFlashMessages(); // Initialize any other global functionality initGlobalDropzone(); }); // Toggle between grid and list views function initializeViewToggle() { const gridViewBtn = document.getElementById('grid-view-btn'); const listViewBtn = document.getElementById('list-view-btn'); const filesContainer = document.getElementById('files-container'); if (gridViewBtn && listViewBtn && filesContainer) { gridViewBtn.addEventListener('click', function () { filesContainer.classList.add('grid-view'); filesContainer.classList.remove('list-view'); gridViewBtn.classList.add('active'); listViewBtn.classList.remove('active'); localStorage.setItem('fileViewPreference', 'grid'); }); listViewBtn.addEventListener('click', function () { filesContainer.classList.add('list-view'); filesContainer.classList.remove('grid-view'); listViewBtn.classList.add('active'); gridViewBtn.classList.remove('active'); localStorage.setItem('fileViewPreference', 'list'); }); // Load user preference from localStorage const viewPreference = localStorage.getItem('fileViewPreference') || 'grid'; if (viewPreference === 'grid') { gridViewBtn.click(); } else { listViewBtn.click(); } } } // Add animations for folder navigation function initializeFolderNavigation() { // Add click event to folder items document.querySelectorAll('.folder-item').forEach(folder => { folder.addEventListener('click', function (e) { e.preventDefault(); const href = this.getAttribute('href'); const filesContainer = document.getElementById('files-container'); // Add transition class filesContainer.classList.add('changing'); // After a short delay, navigate to the folder setTimeout(() => { window.location.href = href; }, 200); }); }); // Add the animation class when page loads const filesContainer = document.getElementById('files-container'); if (filesContainer) { // Remove the class to trigger animation filesContainer.classList.add('folder-enter-active'); } } // Modal handling function initializeModals() { // Hide all modals by default document.querySelectorAll('.modal, .upload-modal, [class*="-modal"]').forEach(modal => { modal.style.display = 'none'; modal.style.opacity = '0'; modal.style.visibility = 'hidden'; // Get close buttons const closeButtons = modal.querySelectorAll('.modal-close, .close-btn, .modal-cancel'); closeButtons.forEach(btn => { btn.addEventListener('click', function () { modal.classList.remove('active'); }); }); // Close when clicking outside modal.addEventListener('click', function (e) { if (e.target === modal) { modal.classList.remove('active'); } }); }); // Setup modal triggers document.querySelectorAll('[data-modal]').forEach(trigger => { trigger.addEventListener('click', function () { const modalId = this.dataset.modal; const modal = document.getElementById(modalId); if (modal) { modal.classList.add('active'); } }); }); } // Context menu for right-click on files/folders function initializeContextMenu() { const contextMenu = document.getElementById('context-menu'); if (!contextMenu) return; document.addEventListener('contextmenu', function (e) { const fileItem = e.target.closest('.file-item, .folder-item'); if (fileItem) { e.preventDefault(); const itemId = fileItem.getAttribute('data-id'); const itemType = fileItem.classList.contains('file-item') ? 'file' : 'folder'; // Position menu contextMenu.style.left = `${e.pageX}px`; contextMenu.style.top = `${e.pageY}px`; // Show menu contextMenu.style.display = 'block'; contextMenu.setAttribute('data-item-id', itemId); contextMenu.setAttribute('data-item-type', itemType); // Set up buttons for different item types setupContextMenuActions(contextMenu, itemId, itemType); } }); // Hide menu on click elsewhere document.addEventListener('click', function () { contextMenu.style.display = 'none'; }); } function setupContextMenuActions(menu, itemId, itemType) { // Show/hide appropriate actions based on item type menu.querySelectorAll('[data-action]').forEach(action => { const forType = action.getAttribute('data-for'); if (forType === 'all' || forType === itemType) { action.style.display = 'block'; } else { action.style.display = 'none'; } }); } // Initialize file upload functionality function initializeUploadFunctionality() { const uploadBtn = document.querySelector('a[href*="upload"]'); const fileInput = document.getElementById('file-upload'); if (uploadBtn && fileInput) { fileInput.addEventListener('change', function (e) { if (this.files.length) { const formData = new FormData(); for (let i = 0; i < this.files.length; i++) { formData.append('file', this.files[i]); } // Get current folder ID from URL if available const urlParams = new URLSearchParams(window.location.search); const folderId = urlParams.get('folder_id'); if (folderId) { formData.append('folder_id', folderId); } fetch('/files/upload', { method: 'POST', body: formData, }) .then(response => response.json()) .then(data => { if (data.success) { // Refresh page to show new file window.location.reload(); } else { alert('Upload failed: ' + data.error); } }) .catch(error => { console.error('Error:', error); alert('Upload failed. Please try again.'); }); } }); } } function initFlashMessages() { document.querySelectorAll('.flash-close').forEach(btn => { btn.addEventListener('click', function () { this.closest('.flash-message').remove(); }); }); } function initGlobalDropzone() { // Setup global dropzone for file uploads const body = document.body; // Only setup if we're on a page that can handle uploads if (document.getElementById('file-upload')) { // Create dropzone overlay if it doesn't exist if (!document.querySelector('.global-dropzone')) { const dropzone = document.createElement('div'); dropzone.className = 'global-dropzone'; dropzone.innerHTML = `

Drop files to upload

Your files will be uploaded to the current folder

`; document.body.appendChild(dropzone); } // Get the dropzone element const dropzone = document.querySelector('.global-dropzone'); // Handle drag events body.addEventListener('dragover', function (e) { e.preventDefault(); e.stopPropagation(); dropzone.classList.add('active'); }); body.addEventListener('dragleave', function (e) { if (e.target === body || e.target === dropzone) { dropzone.classList.remove('active'); } }); dropzone.addEventListener('dragleave', function (e) { if (e.target === dropzone) { dropzone.classList.remove('active'); } }); dropzone.addEventListener('dragover', function (e) { e.preventDefault(); e.stopPropagation(); }); dropzone.addEventListener('drop', function (e) { e.preventDefault(); e.stopPropagation(); dropzone.classList.remove('active'); // Get the file input element const fileInput = document.getElementById('file-upload'); // Handle the dropped files if (e.dataTransfer.files.length > 0) { // Set the files to the file input fileInput.files = e.dataTransfer.files; // Trigger the change event const event = new Event('change', { bubbles: true }); fileInput.dispatchEvent(event); } }); } }