Files
markdown_editor/static/js/app.js
2025-10-26 08:42:43 +04:00

187 lines
5.3 KiB
JavaScript

/**
* Main Application
* Coordinates all modules and handles user interactions
*/
// Global state
let webdavClient;
let fileTree;
let editor;
let darkMode;
let collectionSelector;
let clipboard = null;
let currentFilePath = null;
// Simple event bus
const eventBus = {
listeners: {},
on(event, callback) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(callback);
},
dispatch(event, data) {
if (this.listeners[event]) {
this.listeners[event].forEach(callback => callback(data));
}
}
};
window.eventBus = eventBus;
// Initialize application
document.addEventListener('DOMContentLoaded', async () => {
// Initialize WebDAV client
webdavClient = new WebDAVClient('/fs/');
// Initialize dark mode
darkMode = new DarkMode();
document.getElementById('darkModeBtn').addEventListener('click', () => {
darkMode.toggle();
});
// Initialize file tree
fileTree = new FileTree('fileTree', webdavClient);
fileTree.onFileSelect = async (item) => {
await editor.loadFile(item.path);
};
// Initialize collection selector
collectionSelector = new CollectionSelector('collectionSelect', webdavClient);
collectionSelector.onChange = async (collection) => {
await fileTree.load();
};
await collectionSelector.load();
await fileTree.load();
// Initialize editor
editor = new MarkdownEditor('editor', 'preview', 'filenameInput');
editor.setWebDAVClient(webdavClient);
// Add test content to verify preview works
setTimeout(() => {
if (!editor.editor.getValue()) {
editor.editor.setValue('# Welcome to Markdown Editor\n\nStart typing to see preview...\n');
editor.updatePreview();
}
}, 200);
// Setup editor drop handler
const editorDropHandler = new EditorDropHandler(
document.querySelector('.editor-container'),
async (file) => {
await handleEditorFileDrop(file);
}
);
// Setup button handlers
document.getElementById('newBtn').addEventListener('click', () => {
editor.newFile();
});
document.getElementById('saveBtn').addEventListener('click', async () => {
await editor.save();
});
document.getElementById('deleteBtn').addEventListener('click', async () => {
await editor.deleteFile();
});
// Setup context menu handlers
setupContextMenuHandlers();
// Initialize mermaid
mermaid.initialize({ startOnLoad: true, theme: darkMode.isDark ? 'dark' : 'default' });
// Initialize file tree actions manager
window.fileTreeActions = new FileTreeActions(webdavClient, fileTree, editor);
// Listen for file-saved event to reload file tree
window.eventBus.on('file-saved', async (path) => {
if (fileTree) {
await fileTree.load();
fileTree.selectNode(path);
}
});
window.eventBus.on('file-deleted', async () => {
if (fileTree) {
await fileTree.load();
}
});
});
// Listen for column resize events to refresh editor
window.addEventListener('column-resize', () => {
if (editor && editor.editor) {
editor.editor.refresh();
}
});
/**
* File Operations
*/
/**
* Context Menu Handlers
*/
function setupContextMenuHandlers() {
const menu = document.getElementById('contextMenu');
menu.addEventListener('click', async (e) => {
const item = e.target.closest('.context-menu-item');
if (!item) return;
const action = item.dataset.action;
const targetPath = menu.dataset.targetPath;
const isDir = menu.dataset.targetIsDir === 'true';
hideContextMenu();
await window.fileTreeActions.execute(action, targetPath, isDir);
});
}
// All context actions are now handled by FileTreeActions, so this function is no longer needed.
// async function handleContextAction(action, targetPath, isDir) { ... }
function updatePasteVisibility() {
const pasteItem = document.getElementById('pasteMenuItem');
if (pasteItem) {
pasteItem.style.display = clipboard ? 'block' : 'none';
}
}
/**
* Editor File Drop Handler
*/
async function handleEditorFileDrop(file) {
try {
// Get current file's directory
let targetDir = '';
if (currentFilePath) {
const parts = currentFilePath.split('/');
parts.pop(); // Remove filename
targetDir = parts.join('/');
}
// Upload file
const uploadedPath = await fileTree.uploadFile(targetDir, file);
// Insert markdown link at cursor
const isImage = file.type.startsWith('image/');
const link = isImage
? `![${file.name}](/${webdavClient.currentCollection}/${uploadedPath})`
: `[${file.name}](/${webdavClient.currentCollection}/${uploadedPath})`;
editor.insertAtCursor(link);
showNotification(`Uploaded and inserted link`, 'success');
} catch (error) {
console.error('Failed to handle file drop:', error);
showNotification('Failed to upload file', 'error');
}
}
// Make showContextMenu global
window.showContextMenu = showContextMenu;