diff --git a/CHANGELOG.md b/CHANGELOG.md index 46289535..4b107a3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Removed +- **BREAKING**: Legacy DocumentControls component from TestDrive JSUI plugin system - all control panel functionality now provided by enhanced control panels (ContentsControl, StatusControl, DebugControl, EditControl) with Reset All button functionality moved to EditControl for better maintainability and elimination of code duplication + ## [0.9.0] - 2025-11-14 ### Added diff --git a/capabilities/testdrive-jsui/js/components/document-controls-legacy.js b/capabilities/testdrive-jsui/js/components/document-controls-legacy.js deleted file mode 100644 index e8bcbc22..00000000 --- a/capabilities/testdrive-jsui/js/components/document-controls-legacy.js +++ /dev/null @@ -1,289 +0,0 @@ -/** - * DocumentControlsLegacy Component - * - * Legacy implementation extracted from monolithic editor.js as part of architecture refactoring. - * Handles the floating control panel and document-level actions. - * - * ⚠️ LEGACY COMPONENT: This implementation is maintained for backward compatibility. - * New projects should use the modern control system components instead. - * - * Dependencies: - * - None (standalone component) - */ - -/** - * DocumentControlsLegacy - Legacy floating control panel manager - * - * @deprecated This is a legacy implementation. Use modern control components for new development. - */ -class DocumentControlsLegacy { - 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 = { DocumentControlsLegacy }; -} - -// Export for browser use and global access -if (typeof window !== 'undefined') { - window.DocumentControlsLegacy = DocumentControlsLegacy; -} - -// Also make available in global for tests -if (typeof global !== 'undefined') { - global.DocumentControlsLegacy = DocumentControlsLegacy; -} \ No newline at end of file diff --git a/markitect/plugins/testdrive_jsui.py b/markitect/plugins/testdrive_jsui.py index c5756b1f..21465c94 100644 --- a/markitect/plugins/testdrive_jsui.py +++ b/markitect/plugins/testdrive_jsui.py @@ -42,7 +42,6 @@ class TestDriveJSUIEngine(RenderingEnginePlugin): "static/js/core/debug-system.js", "static/js/core/section-manager.js", "static/js/components/debug-panel.js", - "static/js/components/document-controls.js", "static/js/components/dom-renderer.js", "static/js/controls/control-base.js", "static/js/controls/contents-control.js", diff --git a/markitect/static/js/main-updated.js b/markitect/static/js/main-updated.js index e200d0de..82984441 100644 --- a/markitect/static/js/main-updated.js +++ b/markitect/static/js/main-updated.js @@ -75,12 +75,7 @@ const MarkitectMain = { console.log('✅ DebugPanel initialized'); } - // Initialize document controls - if (typeof DocumentControls !== 'undefined') { - this.documentControls = new DocumentControls(); - this.documentControls.create(); - console.log('✅ DocumentControls initialized'); - } + // Legacy DocumentControls removed - functionality now in enhanced control panels }, // Initialize enhanced control panels with compass positioning @@ -124,73 +119,11 @@ const MarkitectMain = { } }, - // Setup event handlers + // Setup core event handlers (enhanced control panels handle their own events) setupEventHandlers: function() { - console.log('🔌 Setting up event handlers...'); + console.log('🔌 Setting up core 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 + // Setup section manager event handlers for debug panel if (this.sectionManager && this.debugPanel) { this.sectionManager.on('sections-created', (data) => { this.debugPanel.addMessage(`Created ${data.count} sections`, 'INFO'); @@ -209,6 +142,13 @@ const MarkitectMain = { this.debugPanel.addMessage(`Changes cancelled for section: ${data.sectionId}`, 'WARNING'); }); } + + // Make core components available globally for enhanced controls + window.sectionManager = this.sectionManager; + window.domRenderer = this.domRenderer; + window.debugPanel = this.debugPanel; + + console.log('✅ Core event handlers and global references set up'); }, // Render content using the configuration diff --git a/markitect/templates/edit-mode-fixed.html b/markitect/templates/edit-mode-fixed.html index 6743458c..6fc88414 100644 --- a/markitect/templates/edit-mode-fixed.html +++ b/markitect/templates/edit-mode-fixed.html @@ -27,7 +27,6 @@ - diff --git a/testdrive-jsui/static/js/components/document-controls.js b/testdrive-jsui/static/js/components/document-controls.js deleted file mode 100644 index fb83ebd8..00000000 --- a/testdrive-jsui/static/js/components/document-controls.js +++ /dev/null @@ -1,279 +0,0 @@ -/** - * 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; -} \ No newline at end of file