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