/** * DocumentControls Component * * Extracted from monolithic editor.js as part of architecture refactoring. * Handles the floating control panel and document-level actions. * * Dependencies: * - None (standalone component) */ /** * DocumentControls - Manages the floating control panel and its buttons */ class DocumentControls { constructor() { this.controlPanel = null; this.buttons = new Map(); this.eventHandlers = new Map(); this.isVisible = true; } /** * Create the control panel and add it to the DOM */ create() { if (this.controlPanel) { this.destroy(); // Remove existing panel } // Also remove any existing panel with the same ID in the DOM const existingPanel = document.getElementById('markitect-global-controls'); if (existingPanel && existingPanel.parentNode) { existingPanel.parentNode.removeChild(existingPanel); } // Create the floating control panel this.controlPanel = document.createElement('div'); this.controlPanel.id = 'markitect-global-controls'; this.controlPanel.style.cssText = ` position: fixed; top: 20px; right: 20px; background: rgba(248, 249, 250, 0.95); border: 1px solid #dee2e6; border-radius: 8px; padding: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 1000; backdrop-filter: blur(8px); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 14px; min-width: 200px; `; // Add title const title = document.createElement('div'); title.style.cssText = ` font-weight: 600; margin-bottom: 8px; color: #495057; border-bottom: 1px solid #dee2e6; padding-bottom: 4px; `; title.textContent = 'Document Controls'; // Create button container const buttonContainer = document.createElement('div'); buttonContainer.id = 'button-container'; buttonContainer.style.cssText = ` display: flex; flex-direction: column; gap: 6px; `; this.controlPanel.appendChild(title); this.controlPanel.appendChild(buttonContainer); // Add default buttons this.addDefaultButtons(); // Add debug messages container this.addDebugContainer(); // Add to DOM document.body.appendChild(this.controlPanel); } /** * Add default buttons to the control panel */ addDefaultButtons() { // Save Document button this.addButton('save-document', '💾 Save Document', '#28a745'); // Reset All button this.addButton('reset-all', '🔄 Reset All', '#ffc107', '#212529'); // Show Status button this.addButton('show-status', '📊 Show Status', '#17a2b8'); // Debug button this.addButton('toggle-debug', '🔍 Debug', '#6c757d'); } /** * Add debug container to the control panel */ addDebugContainer() { const debugContainer = document.createElement('div'); debugContainer.id = 'debug-messages-container'; debugContainer.style.cssText = ` margin-top: 12px; max-height: 300px; overflow-y: auto; border: 1px solid #dee2e6; border-radius: 4px; background: #f8f9fa; padding: 8px; font-family: 'Courier New', monospace; font-size: 12px; line-height: 1.4; display: none; `; this.controlPanel.appendChild(debugContainer); } /** * Add a button to the control panel */ addButton(id, text, backgroundColor, textColor = 'white') { const buttonContainer = this.controlPanel.querySelector('#button-container'); if (!buttonContainer) { throw new Error('Button container not found. Call create() first.'); } const button = document.createElement('button'); button.id = id; button.textContent = text; button.style.cssText = ` background: ${backgroundColor}; color: ${textColor}; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer; font-size: 13px; font-weight: 500; transition: background-color 0.2s; `; buttonContainer.appendChild(button); this.buttons.set(id, button); return button; } /** * Remove a button from the control panel */ removeButton(id) { const button = this.buttons.get(id); if (button && button.parentNode) { button.parentNode.removeChild(button); this.buttons.delete(id); this.eventHandlers.delete(id); } } /** * Set event handlers for buttons */ setEventHandlers(handlers) { for (const [buttonId, handler] of Object.entries(handlers)) { const button = this.buttons.get(buttonId); if (button) { // Remove existing handler if any if (this.eventHandlers.has(buttonId)) { button.removeEventListener('click', this.eventHandlers.get(buttonId)); } // Add new handler button.addEventListener('click', handler); this.eventHandlers.set(buttonId, handler); } } } /** * Show the control panel */ show() { if (this.controlPanel) { this.controlPanel.style.display = 'block'; this.isVisible = true; } } /** * Hide the control panel */ hide() { if (this.controlPanel) { this.controlPanel.style.display = 'none'; this.isVisible = false; } } /** * Update status display (can be extended as needed) */ updateStatus(status) { // This method can be extended to show status information // For now, it just stores the status for potential display this.lastStatus = status; // Could update a status indicator in the panel if needed if (status && this.controlPanel) { const title = this.controlPanel.querySelector('div'); if (title) { const statusText = `Document Controls (${status.totalSections} sections, ${status.editingSections} editing)`; // Could update title or add status indicator } } } /** * Get the control panel element */ getControlPanel() { return this.controlPanel; } /** * Destroy the control panel and clean up */ destroy() { if (this.controlPanel && this.controlPanel.parentNode) { this.controlPanel.parentNode.removeChild(this.controlPanel); } // Clean up references this.controlPanel = null; this.buttons.clear(); this.eventHandlers.clear(); this.isVisible = true; } /** * Check if the control panel is visible */ isVisible() { return this.isVisible && this.controlPanel && this.controlPanel.style.display !== 'none'; } /** * Get all button IDs */ getButtonIds() { return Array.from(this.buttons.keys()); } /** * Get a specific button by ID */ getButton(id) { return this.buttons.get(id); } } // Export for use in tests and other modules if (typeof module !== 'undefined' && module.exports) { module.exports = { DocumentControls }; } // Export for browser use if (typeof window !== 'undefined') { window.DocumentControls = DocumentControls; }