187 lines
5.3 KiB
JavaScript
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})`;
|
|
|
|
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;
|
|
|