refactor: Modularize UI components and utilities
- Extract UI components into separate JS files - Centralize configuration values in config.js - Introduce a dedicated logger module - Improve file tree drag-and-drop and undo functionality - Refactor modal handling to a single manager - Add URL routing support for SPA navigation - Implement view mode for read-only access
This commit is contained in:
89
static/js/context-menu.js
Normal file
89
static/js/context-menu.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Context Menu Module
|
||||
* Handles the right-click context menu for file tree items
|
||||
*/
|
||||
|
||||
/**
|
||||
* Show context menu at specified position
|
||||
* @param {number} x - X coordinate
|
||||
* @param {number} y - Y coordinate
|
||||
* @param {Object} target - Target object with path and isDir properties
|
||||
*/
|
||||
function showContextMenu(x, y, target) {
|
||||
const menu = document.getElementById('contextMenu');
|
||||
if (!menu) return;
|
||||
|
||||
// Store target data
|
||||
menu.dataset.targetPath = target.path;
|
||||
menu.dataset.targetIsDir = target.isDir;
|
||||
|
||||
// Show/hide menu items based on target type
|
||||
const items = {
|
||||
'new-file': target.isDir,
|
||||
'new-folder': target.isDir,
|
||||
'upload': target.isDir,
|
||||
'download': true,
|
||||
'paste': target.isDir && window.fileTreeActions?.clipboard,
|
||||
'open': !target.isDir
|
||||
};
|
||||
|
||||
Object.entries(items).forEach(([action, show]) => {
|
||||
const item = menu.querySelector(`[data-action="${action}"]`);
|
||||
if (item) {
|
||||
item.style.display = show ? 'flex' : 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Position menu
|
||||
menu.style.display = 'block';
|
||||
menu.style.left = x + 'px';
|
||||
menu.style.top = y + 'px';
|
||||
|
||||
// Adjust if off-screen
|
||||
setTimeout(() => {
|
||||
const rect = menu.getBoundingClientRect();
|
||||
if (rect.right > window.innerWidth) {
|
||||
menu.style.left = (window.innerWidth - rect.width - 10) + 'px';
|
||||
}
|
||||
if (rect.bottom > window.innerHeight) {
|
||||
menu.style.top = (window.innerHeight - rect.height - 10) + 'px';
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the context menu
|
||||
*/
|
||||
function hideContextMenu() {
|
||||
const menu = document.getElementById('contextMenu');
|
||||
if (menu) {
|
||||
menu.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Combined click handler for context menu and outside clicks
|
||||
document.addEventListener('click', async (e) => {
|
||||
const menuItem = e.target.closest('.context-menu-item');
|
||||
|
||||
if (menuItem) {
|
||||
// Handle context menu item click
|
||||
const action = menuItem.dataset.action;
|
||||
const menu = document.getElementById('contextMenu');
|
||||
const targetPath = menu.dataset.targetPath;
|
||||
const isDir = menu.dataset.targetIsDir === 'true';
|
||||
|
||||
hideContextMenu();
|
||||
|
||||
if (window.fileTreeActions) {
|
||||
await window.fileTreeActions.execute(action, targetPath, isDir);
|
||||
}
|
||||
} else if (!e.target.closest('#contextMenu') && !e.target.closest('.tree-node')) {
|
||||
// Hide on outside click
|
||||
hideContextMenu();
|
||||
}
|
||||
});
|
||||
|
||||
// Make functions globally available
|
||||
window.showContextMenu = showContextMenu;
|
||||
window.hideContextMenu = hideContextMenu;
|
||||
|
||||
Reference in New Issue
Block a user