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;
 | 
						|
 |