/** * Main Markitect JavaScript Entry Point - Clean Architecture Version * * Uses ONLY the JSON configuration interface - NO Python-generated JavaScript! * Initializes all controls and systems when document is ready * Implements graceful degradation for missing dependencies */ // Main application module const MarkitectMain = { initialized: false, config: null, // Initialize the complete application initialize: function() { if (this.initialized) { console.log('⚠️ MarkitectMain already initialized, skipping'); return; } console.log('🚀 MarkitectMain initializing...'); try { // Get configuration - if not loaded, use defaults this.config = window.markitectConfig; if (!this.config || !this.config.loaded) { console.warn('⚠️ Configuration not loaded, proceeding with defaults'); this.config = { markdownContent: document.querySelector('#markdown-content')?.textContent || '', mode: 'edit', theme: 'github' }; } // Initialize core systems this.initializeCoreComponents(); this.initializeControlPanels(); this.setupEventHandlers(); this.renderContent(); this.initialized = true; console.log('✅ MarkitectMain initialization complete'); } catch (error) { console.error('❌ MarkitectMain initialization failed:', error); this.fallbackMode(); } }, // Initialize core modular components initializeCoreComponents: function() { console.log('🔧 Initializing core components...'); const container = document.getElementById('markdown-content') || document.body; // Initialize section manager if (typeof SectionManager !== 'undefined') { this.sectionManager = new SectionManager(); console.log('✅ SectionManager initialized'); } else { throw new Error('SectionManager not available'); } // Initialize DOM renderer if (typeof DOMRenderer !== 'undefined') { this.domRenderer = new DOMRenderer(this.sectionManager, container); console.log('✅ DOMRenderer initialized'); } else { throw new Error('DOMRenderer not available'); } // Initialize debug panel if (typeof DebugPanel !== 'undefined') { this.debugPanel = new DebugPanel(); console.log('✅ DebugPanel initialized'); } // Initialize document controls if (typeof DocumentControls !== 'undefined') { this.documentControls = new DocumentControls(); this.documentControls.create(); console.log('✅ DocumentControls initialized'); } }, // Initialize control panels with compass positioning initializeControlPanels: function() { console.log('🎛️ Initializing control panels with compass positioning...'); // ContentsControl (Northwest) if (typeof ContentsControl !== 'undefined') { this.contentsControl = new ContentsControl(); this.contentsControl.control.config.position = 'nw'; this.contentsControl.createControl(); window.contentsControl = this.contentsControl; console.log('✅ ContentsControl initialized (Northwest)'); } // StatusControl (East) if (typeof StatusControl !== 'undefined') { this.statusControl = new StatusControl(); this.statusControl.control.config.position = 'e'; this.statusControl.createControl(); window.statusControl = this.statusControl; console.log('✅ StatusControl initialized (East)'); } // DebugControl (Southeast) if (typeof DebugControl !== 'undefined') { this.debugControl = new DebugControl(); this.debugControl.control.config.position = 'se'; this.debugControl.createControl(); window.debugControl = this.debugControl; console.log('✅ DebugControl initialized (Southeast)'); } // EditControl (Northeast) if (typeof EditControl !== 'undefined') { this.editControl = new EditControl(); this.editControl.control.config.position = 'ne'; this.editControl.createControl(); window.editControl = this.editControl; console.log('✅ EditControl initialized (Northeast)'); } }, // Setup event handlers setupEventHandlers: function() { console.log('🔌 Setting up event handlers...'); if (!this.documentControls) return; this.documentControls.setEventHandlers({ 'save-document': () => { console.log('💾 Save document clicked'); try { const currentMarkdown = this.sectionManager.getDocumentMarkdown(); const now = new Date(); const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-').replace('T', '-'); const filename = `${this.config.originalFilename}-edited-${timestamp}.md`; const blob = new Blob([currentMarkdown], { type: 'text/markdown' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); if (this.debugPanel) { this.debugPanel.addMessage(`Document saved as: ${filename}`, 'SUCCESS'); } console.log(`✅ Document saved as: ${filename}`); } catch (error) { if (this.debugPanel) { this.debugPanel.addMessage(`Save failed: ${error.message}`, 'ERROR'); } console.error('❌ Save error:', error); } }, 'reset-all': () => { console.log('🔄 Reset all clicked'); try { this.domRenderer.hideCurrentEditor(); const allSections = Array.from(this.sectionManager.sections.values()); allSections.forEach(section => section.resetToOriginal()); this.domRenderer.renderAllSections(allSections); if (this.debugPanel) { this.debugPanel.addMessage('Reset all sections to original state', 'INFO'); } } catch (error) { console.error('❌ Reset all failed:', error); } }, 'show-status': () => { const status = this.sectionManager.getDocumentStatus(); alert(`Document Status:\nTotal Sections: ${status.totalSections}\nEditing Sections: ${status.editingSections}`); }, 'toggle-debug': () => { if (this.debugPanel) { this.debugPanel.toggle(); } } }); // Setup section manager event handlers if (this.sectionManager && this.debugPanel) { this.sectionManager.on('sections-created', (data) => { this.debugPanel.addMessage(`Created ${data.count} sections`, 'INFO'); }); this.sectionManager.on('edit-started', (data) => { this.debugPanel.addMessage(`Edit started for section: ${data.sectionId}`, 'DEBUG'); }); this.sectionManager.on('changes-accepted', (data) => { this.debugPanel.addMessage(`Changes accepted for section: ${data.sectionId}`, 'SUCCESS'); this.updateSectionDOM(data.sectionId); }); this.sectionManager.on('changes-cancelled', (data) => { this.debugPanel.addMessage(`Changes cancelled for section: ${data.sectionId}`, 'WARNING'); }); } }, // Render content using the configuration renderContent: function() { console.log('📄 Rendering markdown content...'); const markdownToRender = this.config.markdownContent || ''; if (markdownToRender.trim()) { const sections = this.sectionManager.createSectionsFromMarkdown(markdownToRender); this.domRenderer.renderAllSections(sections); if (this.debugPanel) { this.debugPanel.addMessage(`Initialized with ${sections.length} sections`, 'INFO'); } console.log(`✅ Rendered ${sections.length} sections`); } else { if (this.debugPanel) { this.debugPanel.addMessage('No markdown content to initialize', 'WARNING'); } console.warn('⚠️ No markdown content to render'); } }, // Update section DOM after changes updateSectionDOM: function(sectionId) { try { const section = this.sectionManager.sections.get(sectionId); if (section) { const sectionElement = this.domRenderer.findSectionElement(sectionId); if (sectionElement) { const newElement = this.domRenderer.renderSection(section); sectionElement.parentNode.replaceChild(newElement, sectionElement); if (this.debugPanel) { this.debugPanel.addMessage(`DOM updated for section: ${sectionId}`, 'INFO'); } } } } catch (error) { console.error('❌ Failed to update section DOM:', error); } }, // Fallback mode if initialization fails fallbackMode: function() { console.warn('⚠️ Running in fallback mode'); // Basic content rendering fallback const contentDiv = document.getElementById('markdown-content'); if (contentDiv && this.config && this.config.markdownContent) { const basicHtml = this.config.markdownContent .replace(/^# (.*$)/gim, '

$1

') .replace(/^## (.*$)/gim, '

$1

') .replace(/^### (.*$)/gim, '

$1

') .replace(/\n\n/g, '

') .replace(/\n/g, '
'); contentDiv.innerHTML = `

${basicHtml}

`; console.log('✅ Fallback content rendered'); } } }; // Make components globally available for debugging window.MarkitectMain = MarkitectMain; // Auto-initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { // Small delay to ensure config is loaded setTimeout(() => MarkitectMain.initialize(), 100); }); } else { // DOM already ready setTimeout(() => MarkitectMain.initialize(), 100); }