Flask-Files/app/static/js/browser.js
2025-03-23 03:53:45 +01:00

375 lines
No EOL
14 KiB
JavaScript

/**
* File browser functionality
*/
document.addEventListener('DOMContentLoaded', function () {
// View toggle functionality
const filesContainer = document.getElementById('files-container');
const gridViewBtn = document.getElementById('grid-view-btn');
const listViewBtn = document.getElementById('list-view-btn');
if (filesContainer && gridViewBtn && listViewBtn) {
// Set initial view based on saved preference
const savedView = localStorage.getItem('view_preference') || 'grid';
filesContainer.className = `files-container ${savedView}-view`;
// Highlight the correct button
if (savedView === 'grid') {
gridViewBtn.classList.add('active');
listViewBtn.classList.remove('active');
} else {
listViewBtn.classList.add('active');
gridViewBtn.classList.remove('active');
}
// Add event listeners
gridViewBtn.addEventListener('click', function () {
filesContainer.className = 'files-container grid-view';
gridViewBtn.classList.add('active');
listViewBtn.classList.remove('active');
// Save preference
localStorage.setItem('view_preference', 'grid');
});
listViewBtn.addEventListener('click', function () {
filesContainer.className = 'files-container list-view';
listViewBtn.classList.add('active');
gridViewBtn.classList.remove('active');
// Save preference
localStorage.setItem('view_preference', 'list');
});
}
// Variables for tracking selected items
let selectedItemId = null;
let selectedItemType = null;
// Setup context menu functionality
function setupContextMenu() {
// Context menu already implemented via context-menu.js
// We'll just need to ensure our item actions are properly set
// Add item click handler to set selected item
document.querySelectorAll('.file-item, .folder-item').forEach(item => {
item.addEventListener('click', function (e) {
// If clicking on an action button, don't select the item
if (e.target.closest('.item-actions') || e.target.closest('a')) {
return;
}
// Set selected item
selectedItemId = this.dataset.id;
selectedItemType = this.classList.contains('folder-item') ? 'folder' : 'file';
// Highlight selected item
document.querySelectorAll('.file-item, .folder-item').forEach(i => {
i.classList.remove('selected');
});
this.classList.add('selected');
});
// Right-click to open context menu
item.addEventListener('contextmenu', function (e) {
// Set selected item
selectedItemId = this.dataset.id;
selectedItemType = this.classList.contains('folder-item') ? 'folder' : 'file';
// Highlight selected item
document.querySelectorAll('.file-item, .folder-item').forEach(i => {
i.classList.remove('selected');
});
this.classList.add('selected');
});
});
}
// Handle folder creation
const newFolderForm = document.getElementById('new-folder-form');
if (newFolderForm) {
newFolderForm.addEventListener('submit', function (e) {
e.preventDefault();
const folderName = document.getElementById('folder-name').value;
const parentId = document.querySelector('input[name="parent_id"]').value;
// Create FormData
const formData = new FormData();
formData.append('name', folderName);
if (parentId) formData.append('parent_id', parentId);
// Send request
fetch('/files/create_folder', {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Close modal
closeModal('new-folder-modal');
// Show success message
showAlert('Folder created successfully', 'success');
// Reload page to show new folder
setTimeout(() => window.location.reload(), 500);
} else {
showAlert(data.error || 'Error creating folder', 'error');
}
})
.catch(error => {
showAlert('Error creating folder: ' + error, 'error');
});
});
}
// Handle rename
const renameForm = document.getElementById('rename-form');
if (renameForm) {
renameForm.addEventListener('submit', function (e) {
e.preventDefault();
const newName = document.getElementById('new-name').value;
if (!selectedItemId) {
showAlert('No item selected', 'error');
return;
}
fetch('/files/rename', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({
item_id: selectedItemId,
new_name: newName
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Close modal
closeModal('rename-modal');
// Show success message
showAlert('Item renamed successfully', 'success');
// Update item name in the UI or reload
setTimeout(() => window.location.reload(), 500);
} else {
showAlert(data.error || 'Failed to rename item', 'error');
}
})
.catch(error => {
showAlert('Error: ' + error, 'error');
});
});
}
// Handle delete confirmation
const confirmDeleteBtn = document.getElementById('confirm-delete-btn');
if (confirmDeleteBtn) {
confirmDeleteBtn.addEventListener('click', function () {
if (!selectedItemId) {
showAlert('No item selected', 'error');
closeModal('delete-modal');
return;
}
fetch(`/files/delete/${selectedItemId}`, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Close modal
closeModal('delete-modal');
// Show success message
showAlert(data.message || 'Item deleted successfully', 'success');
// Remove the item from the UI or reload
setTimeout(() => window.location.reload(), 500);
} else {
showAlert(data.error || 'Failed to delete item', 'error');
}
})
.catch(error => {
showAlert('Error: ' + error, 'error');
});
});
}
// Initialize
setupContextMenu();
// Buttons to open modals
const deleteBtn = document.getElementById('delete-btn');
if (deleteBtn) {
deleteBtn.addEventListener('click', function () {
if (!selectedItemId) {
showAlert('Please select an item first', 'warning');
return;
}
openModal('delete-modal');
});
}
const renameBtn = document.getElementById('rename-btn');
if (renameBtn) {
renameBtn.addEventListener('click', function () {
if (!selectedItemId) {
showAlert('Please select an item first', 'warning');
return;
}
// Get current name
const selectedItem = document.querySelector(`.file-item[data-id="${selectedItemId}"], .folder-item[data-id="${selectedItemId}"]`);
const currentName = selectedItem ? selectedItem.querySelector('.item-name').textContent.trim() : '';
// Set current name in the input
document.getElementById('new-name').value = currentName;
openModal('rename-modal');
document.getElementById('new-name').focus();
});
}
// Delete functionality
const deleteModal = document.getElementById('delete-modal');
const deleteForm = document.getElementById('delete-form');
const deleteItemIdInput = document.getElementById('delete-item-id');
if (deleteModal && deleteForm) {
// Update the form action when the modal is shown
document.querySelectorAll('.action-btn.delete').forEach(btn => {
btn.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
const itemElement = this.closest('.folder-item, .file-item');
const itemId = itemElement.dataset.id;
// Set the item ID in the form
deleteItemIdInput.value = itemId;
// Update the form action URL
const formAction = deleteForm.action;
deleteForm.action = formAction.replace('placeholder', itemId);
// Show the modal
deleteModal.classList.add('active');
});
});
// Close modal when cancel is clicked
deleteModal.querySelector('.modal-cancel').addEventListener('click', function () {
deleteModal.classList.remove('active');
});
// Close modal when X is clicked
deleteModal.querySelector('.modal-close').addEventListener('click', function () {
deleteModal.classList.remove('active');
});
}
});
// Browser-specific functionality
document.addEventListener('DOMContentLoaded', function () {
// Initialize folder browser view
initializeFolderBrowser();
});
function initializeFolderBrowser() {
// Handle item selection
const items = document.querySelectorAll('.folder-item, .file-item');
items.forEach(item => {
item.addEventListener('click', function (e) {
// Only select if not clicking on an action button
if (!e.target.closest('.file-actions')) {
// Remove selection from all items
items.forEach(i => i.classList.remove('selected'));
// Select this item
this.classList.add('selected');
}
});
});
// Handle folder creation form submission
const newFolderForm = document.getElementById('new-folder-form');
if (newFolderForm) {
newFolderForm.addEventListener('submit', function (e) {
// Form will be submitted normally, we just close the modal
const modal = document.getElementById('new-folder-modal');
if (modal) {
modal.classList.remove('active');
}
});
}
// Handle file/folder actions from context menu
document.querySelectorAll('.context-menu-item').forEach(item => {
item.addEventListener('click', function () {
const action = this.getAttribute('data-action');
const menu = this.closest('.context-menu');
const itemId = menu.getAttribute('data-item-id');
const itemType = menu.getAttribute('data-item-type');
// Handle different actions
switch (action) {
case 'open':
if (itemType === 'folder') {
window.location.href = `/files/browser/${itemId}`;
}
break;
case 'download':
if (itemType === 'file') {
window.location.href = `/files/download/${itemId}`;
}
break;
case 'share':
// TODO: Implement share functionality
alert('Share functionality coming soon');
break;
case 'rename':
// TODO: Implement rename functionality
alert('Rename functionality coming soon');
break;
case 'delete':
if (confirm(`Are you sure you want to delete this ${itemType}?`)) {
// Send delete request to server
fetch(`/files/delete/${itemType}/${itemId}`, {
method: 'POST',
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Remove item from DOM
document.querySelector(`[data-id="${itemId}"]`).remove();
} else {
alert(`Failed to delete ${itemType}: ${data.error}`);
}
})
.catch(error => {
console.error('Error:', error);
alert(`An error occurred while deleting the ${itemType}`);
});
}
break;
}
// Hide menu after action
menu.style.display = 'none';
});
});
}