Add Escape key handler to close move dialog
This commit is contained in:
@@ -260,9 +260,23 @@ const contextMenus = {
|
|||||||
const moveCancelBtn = document.getElementById('move-cancel-btn');
|
const moveCancelBtn = document.getElementById('move-cancel-btn');
|
||||||
const moveConfirmBtn = document.getElementById('move-confirm-btn');
|
const moveConfirmBtn = document.getElementById('move-confirm-btn');
|
||||||
const copyConfirmBtn = document.getElementById('copy-confirm-btn');
|
const copyConfirmBtn = document.getElementById('copy-confirm-btn');
|
||||||
|
const moveFileDialog = document.getElementById('move-file-dialog');
|
||||||
|
|
||||||
moveCancelBtn.addEventListener('click', this.closeMoveDialog);
|
moveCancelBtn.addEventListener('click', this.closeMoveDialog);
|
||||||
|
|
||||||
|
// Close move dialog on Escape key
|
||||||
|
// Store handler reference to avoid duplicate listeners
|
||||||
|
// Note: We don't use stopPropagation because all Escape handlers are on document level
|
||||||
|
// Each handler checks its own state, so multiple dialogs can be closed with multiple Escape presses
|
||||||
|
if (!window._moveDialogEscapeHandler) {
|
||||||
|
window._moveDialogEscapeHandler = (e) => {
|
||||||
|
if (e.key === 'Escape' && moveFileDialog.style.display === 'flex') {
|
||||||
|
this.closeMoveDialog();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('keydown', window._moveDialogEscapeHandler);
|
||||||
|
}
|
||||||
|
|
||||||
// Copy button handler
|
// Copy button handler
|
||||||
copyConfirmBtn.addEventListener('click', async () => {
|
copyConfirmBtn.addEventListener('click', async () => {
|
||||||
// Batch copy mode (from multiSelect)
|
// Batch copy mode (from multiSelect)
|
||||||
@@ -473,8 +487,14 @@ const contextMenus = {
|
|||||||
// Initialize dialog navigation state
|
// Initialize dialog navigation state
|
||||||
// Start at the parent of the item being moved (so user sees siblings and can navigate)
|
// Start at the parent of the item being moved (so user sees siblings and can navigate)
|
||||||
let startFolderId = null;
|
let startFolderId = null;
|
||||||
|
let startFolderName = null;
|
||||||
if (mode === 'file' && item.folder_id) {
|
if (mode === 'file' && item.folder_id) {
|
||||||
startFolderId = item.folder_id;
|
startFolderId = item.folder_id;
|
||||||
|
// We need the folder name for breadcrumb - try to get it from current view
|
||||||
|
const folderEl = document.querySelector(`[data-folder-id="${startFolderId}"]`);
|
||||||
|
if (folderEl) {
|
||||||
|
startFolderName = folderEl.querySelector('.folder-name, .item-name')?.textContent || null;
|
||||||
|
}
|
||||||
} else if (mode === 'folder' && item.parent_id) {
|
} else if (mode === 'folder' && item.parent_id) {
|
||||||
startFolderId = item.parent_id;
|
startFolderId = item.parent_id;
|
||||||
} else {
|
} else {
|
||||||
@@ -488,7 +508,15 @@ const contextMenus = {
|
|||||||
window.app.moveDialogItemId = item.id;
|
window.app.moveDialogItemId = item.id;
|
||||||
window.app.moveDialogItemMode = mode;
|
window.app.moveDialogItemMode = mode;
|
||||||
window.app.moveDialogCurrentFolderId = startFolderId;
|
window.app.moveDialogCurrentFolderId = startFolderId;
|
||||||
window.app.moveDialogBreadcrumb = [];
|
|
||||||
|
// Build initial breadcrumb if starting at a non-home folder
|
||||||
|
// This allows proper navigation back to home
|
||||||
|
const breadcrumb = [];
|
||||||
|
if (startFolderId && startFolderId !== window.app.userHomeFolderId && startFolderName) {
|
||||||
|
// We have the folder name, add it to breadcrumb
|
||||||
|
breadcrumb.push({ id: startFolderId, name: startFolderName });
|
||||||
|
}
|
||||||
|
window.app.moveDialogBreadcrumb = breadcrumb;
|
||||||
|
|
||||||
// Update dialog title (preserve icon)
|
// Update dialog title (preserve icon)
|
||||||
const dialogHeader = document.getElementById('move-file-dialog').querySelector('.rename-dialog-header');
|
const dialogHeader = document.getElementById('move-file-dialog').querySelector('.rename-dialog-header');
|
||||||
@@ -562,24 +590,21 @@ const contextMenus = {
|
|||||||
|
|
||||||
// Ensure we have the home folder ID before proceeding
|
// Ensure we have the home folder ID before proceeding
|
||||||
if (!window.app.userHomeFolderId) {
|
if (!window.app.userHomeFolderId) {
|
||||||
console.log('[Move Dialog] Home folder ID not set, resolving...');
|
|
||||||
await window.resolveHomeFolder();
|
await window.resolveHomeFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build URL - use /api/folders/{id}/contents to get CHILDREN of the folder
|
// Get the effective folder ID
|
||||||
let url;
|
const effectiveParentId = parentFolderId || window.app.userHomeFolderId;
|
||||||
let effectiveParentId = parentFolderId || window.app.userHomeFolderId;
|
|
||||||
|
|
||||||
if (effectiveParentId) {
|
// Must have a folder ID to proceed
|
||||||
// Use the contents endpoint to get children (not the folder itself)
|
if (!effectiveParentId) {
|
||||||
url = `/api/folders/${effectiveParentId}/contents`;
|
console.error('[Move Dialog] Cannot load folders - no folder ID available');
|
||||||
} else {
|
return;
|
||||||
// Last resort fallback: this returns root folders (home folder)
|
|
||||||
// We should NOT use this as it returns the folder itself, not its contents
|
|
||||||
console.error('[Move Dialog] No folder ID available, using fallback');
|
|
||||||
url = '/api/folders';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the contents endpoint to get children
|
||||||
|
const url = `/api/folders/${effectiveParentId}/contents`;
|
||||||
|
|
||||||
console.log('[Move Dialog] Loading folders from:', url, 'effectiveParentId:', effectiveParentId);
|
console.log('[Move Dialog] Loading folders from:', url, 'effectiveParentId:', effectiveParentId);
|
||||||
const response = await fetch(url, { headers });
|
const response = await fetch(url, { headers });
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -606,13 +631,9 @@ const contextMenus = {
|
|||||||
const mode = window.app.moveDialogItemMode;
|
const mode = window.app.moveDialogItemMode;
|
||||||
const breadcrumb = window.app.moveDialogBreadcrumb || [];
|
const breadcrumb = window.app.moveDialogBreadcrumb || [];
|
||||||
|
|
||||||
// Only show breadcrumb when we've navigated into subfolders
|
// Always show breadcrumb to allow navigation back to home
|
||||||
if (breadcrumb.length > 0) {
|
this._renderMoveDialogBreadcrumb(breadcrumbContainer, breadcrumb, effectiveParentId);
|
||||||
this._renderMoveDialogBreadcrumb(breadcrumbContainer, breadcrumb, effectiveParentId);
|
breadcrumbContainer.style.display = 'flex';
|
||||||
breadcrumbContainer.style.display = 'flex';
|
|
||||||
} else {
|
|
||||||
breadcrumbContainer.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Option to select current folder as destination (only after navigating into subfolders)
|
// Option to select current folder as destination (only after navigating into subfolders)
|
||||||
if (breadcrumb.length > 0 && effectiveParentId && effectiveParentId !== itemId) {
|
if (breadcrumb.length > 0 && effectiveParentId && effectiveParentId !== itemId) {
|
||||||
@@ -632,8 +653,9 @@ const contextMenus = {
|
|||||||
folderSelectContainer.appendChild(currentFolderOption);
|
folderSelectContainer.appendChild(currentFolderOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add "Go to parent" option if we have navigated into subfolders
|
// Add "Go to parent" option if not at home folder
|
||||||
if (breadcrumb.length > 0) {
|
const isAtHomeFolder = effectiveParentId === window.app.userHomeFolderId;
|
||||||
|
if (!isAtHomeFolder || breadcrumb.length > 0) {
|
||||||
const parentOption = document.createElement('div');
|
const parentOption = document.createElement('div');
|
||||||
parentOption.className = 'folder-select-item folder-navigate-up';
|
parentOption.className = 'folder-select-item folder-navigate-up';
|
||||||
parentOption.innerHTML = `
|
parentOption.innerHTML = `
|
||||||
@@ -654,6 +676,7 @@ const contextMenus = {
|
|||||||
this.loadMoveDialogFolders(parentFolder ? parentFolder.id : null);
|
this.loadMoveDialogFolders(parentFolder ? parentFolder.id : null);
|
||||||
} else {
|
} else {
|
||||||
// Go to root (home folder)
|
// Go to root (home folder)
|
||||||
|
window.app.moveDialogBreadcrumb = [];
|
||||||
window.app.moveDialogCurrentFolderId = window.app.userHomeFolderId || null;
|
window.app.moveDialogCurrentFolderId = window.app.userHomeFolderId || null;
|
||||||
this.loadMoveDialogFolders(window.app.userHomeFolderId || null);
|
this.loadMoveDialogFolders(window.app.userHomeFolderId || null);
|
||||||
}
|
}
|
||||||
@@ -798,63 +821,19 @@ const contextMenus = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load all folders for the move dialog (legacy - kept for batch operations)
|
* Load all folders for the move dialog (batch operations)
|
||||||
* @param {string} itemId - ID of the item being moved
|
* Uses the same navigation pattern as loadMoveDialogFolders
|
||||||
* @param {string} mode - 'file' or 'folder'
|
* @param {string} itemId - ID of the item being moved (unused, kept for compatibility)
|
||||||
|
* @param {string} mode - 'batch' for batch operations
|
||||||
*/
|
*/
|
||||||
async loadAllFolders(itemId, mode) {
|
async loadAllFolders(itemId, mode) {
|
||||||
// For batch mode, use the old behavior but start from home folder
|
// For batch mode, use the same navigation as regular move dialog
|
||||||
try {
|
// Initialize navigation state starting at home folder
|
||||||
const token = localStorage.getItem('oxicloud_token');
|
window.app.moveDialogBreadcrumb = [];
|
||||||
const headers = token ? { 'Authorization': `Bearer ${token}` } : {};
|
window.app.moveDialogCurrentFolderId = window.app.userHomeFolderId || null;
|
||||||
const response = await fetch('/api/folders', { headers });
|
|
||||||
if (response.ok) {
|
|
||||||
const folders = await response.json();
|
|
||||||
const folderSelectContainer = document.getElementById('folder-select-container');
|
|
||||||
|
|
||||||
// Clear container
|
// Use loadMoveDialogFolders which uses /api/folders/{id}/contents
|
||||||
folderSelectContainer.innerHTML = '';
|
await this.loadMoveDialogFolders(window.app.userHomeFolderId || null);
|
||||||
|
|
||||||
// Add all available folders
|
|
||||||
if (Array.isArray(folders)) {
|
|
||||||
const excludeIds = itemId ? [itemId] : [];
|
|
||||||
folders.forEach(folder => {
|
|
||||||
// Skip folders that would create cycles
|
|
||||||
if (excludeIds.includes(folder.id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const folderItem = document.createElement('div');
|
|
||||||
folderItem.className = 'folder-select-item';
|
|
||||||
folderItem.dataset.folderId = folder.id;
|
|
||||||
folderItem.innerHTML = `<i class="fas fa-folder"></i> ${escapeHtml(folder.name)}`;
|
|
||||||
|
|
||||||
folderItem.addEventListener('click', () => {
|
|
||||||
// Deselect all
|
|
||||||
document.querySelectorAll('.folder-select-item').forEach(item => {
|
|
||||||
item.classList.remove('selected');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Select this one
|
|
||||||
folderItem.classList.add('selected');
|
|
||||||
window.app.selectedTargetFolderId = folder.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
folderSelectContainer.appendChild(folderItem);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default selection
|
|
||||||
window.app.selectedTargetFolderId = "";
|
|
||||||
|
|
||||||
// Translate new elements (scoped to container)
|
|
||||||
if (window.i18n && window.i18n.translateElement) {
|
|
||||||
window.i18n.translateElement(folderSelectContainer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error loading folders:', error);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Show share dialog for files or folders
|
* Show share dialog for files or folders
|
||||||
|
|||||||
Reference in New Issue
Block a user