Added comprehensive plugin system for independent JavaScript UI development: **Plugin Infrastructure:** - Extended existing MarkiTect plugin system with RenderingEnginePlugin base class - Added RENDERING plugin type to PluginType enum - Created RenderingConfig for asset management and deployment - Implemented RenderingEngineManager for plugin discovery and lifecycle **TestDrive JSUI Plugin:** - Extracted JavaScript UI components to independent testdrive-jsui plugin - Created standalone development environment (no Python required) - Implemented compass-positioned control panels (NW, NE, E, SE) - Added clean JSON configuration interface for Python↔JavaScript data transfer **Asset Management:** - Development mode: serve assets directly from plugin source directory - Production mode: deploy to _markitect/plugins/[plugin-name]/ structure - Configurable asset URLs and deployment strategies - Support for external dependencies (CDN resources) **Standalone Development:** - testdrive-jsui/test.html for browser-based development - Package.json with npm scripts for development server - Complete separation of JavaScript development from Python environment - Hot reload and standard web development workflow **Integration Demo:** - demo_plugin_integration.py showcasing all plugin capabilities - Standalone, plugin discovery, production deployment examples - Asset URL generation for different deployment modes This enables JavaScript-first development while maintaining clean integration with the MarkiTect Python ecosystem. Developers can now work on UI components independently using standard web development tools and workflows. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
191 lines
5.7 KiB
JavaScript
191 lines
5.7 KiB
JavaScript
/**
|
|
* DebugPanel Component
|
|
*
|
|
* Extracted from monolithic editor.js as part of architecture refactoring.
|
|
* Handles debug message display and management for client-side debugging.
|
|
*
|
|
* Dependencies:
|
|
* - None (standalone component)
|
|
*/
|
|
|
|
/**
|
|
* DebugPanel - Manages debug message display and interaction
|
|
*/
|
|
class DebugPanel {
|
|
constructor() {
|
|
this.messages = [];
|
|
this.isActive = false;
|
|
this.maxMessages = 1000; // Keep last 1000 messages
|
|
}
|
|
|
|
/**
|
|
* Add a debug message
|
|
*/
|
|
addMessage(message, category = 'INFO') {
|
|
const messageObj = {
|
|
message,
|
|
category,
|
|
timestamp: new Date().toLocaleTimeString()
|
|
};
|
|
|
|
this.messages.push(messageObj);
|
|
|
|
// Keep only last maxMessages
|
|
if (this.messages.length > this.maxMessages) {
|
|
this.messages = this.messages.slice(-this.maxMessages);
|
|
}
|
|
|
|
// Auto-update if panel is visible
|
|
if (this.isActive) {
|
|
this.update();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggle the debug panel on/off
|
|
*/
|
|
toggle() {
|
|
const debugContainer = document.getElementById('debug-messages-container');
|
|
const debugButton = document.getElementById('toggle-debug');
|
|
|
|
if (!debugContainer || !debugButton) {
|
|
console.warn('DebugPanel: Required DOM elements not found');
|
|
return;
|
|
}
|
|
|
|
if (this.isActive) {
|
|
this.hide();
|
|
} else {
|
|
this.show();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show the debug panel
|
|
*/
|
|
show() {
|
|
const debugContainer = document.getElementById('debug-messages-container');
|
|
const debugButton = document.getElementById('toggle-debug');
|
|
|
|
if (!debugContainer || !debugButton) {
|
|
console.warn('DebugPanel: Required DOM elements not found');
|
|
return;
|
|
}
|
|
|
|
debugContainer.style.display = 'block';
|
|
debugButton.textContent = '🔍 Debug (ON)';
|
|
debugButton.style.background = '#28a745';
|
|
this.isActive = true;
|
|
this.update();
|
|
}
|
|
|
|
/**
|
|
* Hide the debug panel
|
|
*/
|
|
hide() {
|
|
const debugContainer = document.getElementById('debug-messages-container');
|
|
const debugButton = document.getElementById('toggle-debug');
|
|
|
|
if (!debugContainer || !debugButton) {
|
|
console.warn('DebugPanel: Required DOM elements not found');
|
|
return;
|
|
}
|
|
|
|
debugContainer.style.display = 'none';
|
|
debugButton.textContent = '🔍 Debug';
|
|
debugButton.style.background = '#6c757d';
|
|
this.isActive = false;
|
|
}
|
|
|
|
/**
|
|
* Update the debug panel with current messages
|
|
*/
|
|
update() {
|
|
const debugContainer = document.getElementById('debug-messages-container');
|
|
if (!debugContainer || !this.isActive) {
|
|
return;
|
|
}
|
|
|
|
if (this.messages.length === 0) {
|
|
debugContainer.innerHTML = '<div style="color: #6c757d; font-style: italic; padding: 12px;">No debug messages yet. Click sections to generate debug output.</div>';
|
|
return;
|
|
}
|
|
|
|
// Show the last 50 messages in reverse order (newest first)
|
|
const recentMessages = this.messages.slice(-50).reverse();
|
|
|
|
const messagesHtml = recentMessages.map(msg => {
|
|
const categoryColor = {
|
|
'INFO': '#17a2b8',
|
|
'WARNING': '#ffc107',
|
|
'ERROR': '#dc3545',
|
|
'SUCCESS': '#28a745',
|
|
'DEBUG': '#6f42c1'
|
|
}[msg.category] || '#6c757d';
|
|
|
|
return `
|
|
<div style="margin-bottom: 6px; padding: 4px; border-left: 3px solid ${categoryColor}; background: white; border-radius: 2px;">
|
|
<span style="color: #6c757d; font-size: 11px;">[${msg.timestamp}]</span>
|
|
<span style="color: ${categoryColor}; font-weight: bold;">${msg.category}:</span>
|
|
<span style="color: #333;">${msg.message}</span>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
debugContainer.innerHTML = `
|
|
<div style="margin-bottom: 8px; padding: 6px; background: #e9ecef; border-radius: 4px; font-weight: bold; color: #495057;">
|
|
Debug Messages (${this.messages.length} total, showing last ${recentMessages.length})
|
|
<button id="debug-clear-btn" style="float: right; background: #dc3545; color: white; border: none; padding: 2px 6px; border-radius: 2px; font-size: 11px; cursor: pointer;">Clear</button>
|
|
</div>
|
|
<div style="max-height: 250px; overflow-y: auto;">
|
|
${messagesHtml}
|
|
</div>
|
|
`;
|
|
|
|
// Add event listener for clear button
|
|
const clearBtn = debugContainer.querySelector('#debug-clear-btn');
|
|
if (clearBtn) {
|
|
clearBtn.addEventListener('click', () => {
|
|
this.clear();
|
|
});
|
|
}
|
|
|
|
// Auto-scroll to bottom to show newest messages
|
|
const scrollContainer = debugContainer.querySelector('div[style*="overflow-y"]');
|
|
if (scrollContainer) {
|
|
scrollContainer.scrollTop = scrollContainer.scrollHeight;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear all debug messages
|
|
*/
|
|
clear() {
|
|
this.messages = [];
|
|
this.update();
|
|
}
|
|
|
|
/**
|
|
* Get the number of messages
|
|
*/
|
|
getMessageCount() {
|
|
return this.messages.length;
|
|
}
|
|
|
|
/**
|
|
* Get recent messages
|
|
*/
|
|
getRecentMessages(count = 10) {
|
|
return this.messages.slice(-count);
|
|
}
|
|
}
|
|
|
|
// Export for use in tests and other modules
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = { DebugPanel };
|
|
}
|
|
|
|
// Export for browser use
|
|
if (typeof window !== 'undefined') {
|
|
window.DebugPanel = DebugPanel;
|
|
} |