/** * Console output management for EveAI Client * Handles logging and status bar updates in a consistent way */ // LogViewer class for managing console output class LogViewer { constructor(containerId, options = {}) { console.log('LogViewer constructor: ', containerId, options); this.container = document.getElementById(containerId); if (!this.container) { console.error(`Container element with ID "${containerId}" not found`); // Create a temporary container to avoid errors this.container = document.createElement('div'); this.container.id = containerId; document.body.appendChild(this.container); } this.options = { maxEntries: options.maxEntries || 500, autoScroll: options.autoScroll !== false, timestampFormat: options.timestampFormat || 'HH:MM:SS', ...options }; // Initialize the container if it's empty if (this.container.innerHTML.trim() === '') { this.container.innerHTML = '
'; } this.entriesContainer = this.container.querySelector('.log-entries') || this.container; console.log(`LogViewer initialized with container ${containerId}`); } /** * Add a log entry * @param {string} message - The log message * @param {string} level - Log level (info, success, warning, error) */ log(message, level = 'info') { console.log(`LogViewer: Adding log entry (${level}): ${message}`); // Create timestamp const now = new Date(); const timestamp = now.toLocaleTimeString(); try { // Create entry element const entry = document.createElement('div'); entry.className = `log-entry log-${level}`; entry.innerHTML = ` `; // Add to container and log for debugging console.log("Adding to container:", this.entriesContainer.id || "unnamed container"); this.entriesContainer.appendChild(entry); console.log("Entry added successfully, container now has", this.entriesContainer.children.length, "children"); // Remove old entries if exceeding max while (this.entriesContainer.children.length > this.options.maxEntries) { this.entriesContainer.removeChild(this.entriesContainer.firstChild); } // Auto scroll to bottom if (this.options.autoScroll) { // Try scrolling the container this.scrollToBottom(); // Also try scrolling the parent console output const consoleOutput = document.getElementById('consoleOutput'); if (consoleOutput) { setTimeout(() => { consoleOutput.scrollTop = consoleOutput.scrollHeight; }, 10); } } // Also update status bar if provided this.updateStatusBar(message); } catch (error) { console.error("Error adding log entry:", error); } return this; } /** * Update the current status text in the status bar */ updateStatusBar(message) { const statusElement = document.getElementById('currentStatus'); if (statusElement) { statusElement.textContent = message; } } /** * Convenience methods for different log levels */ info(message) { return this.log(message, 'info'); } success(message) { return this.log(message, 'success'); } warning(message) { return this.log(message, 'warning'); } error(message) { return this.log(message, 'error'); } /** * Clear all log entries */ clear() { this.entriesContainer.innerHTML = ''; return this; } /** * Scroll to the bottom of the log */ scrollToBottom() { try { this.container.scrollTop = this.container.scrollHeight; console.log("Scrolled container to bottom:", this.container.scrollHeight); // Also scroll parent if there is one if (this.container.parentElement) { this.container.parentElement.scrollTop = this.container.parentElement.scrollHeight; } } catch (error) { console.error("Error scrolling to bottom:", error); } return this; } } // Console panel management functions function initConsolePanel() { const toggleBtn = document.getElementById('toggleConsole'); const consoleOutput = document.getElementById('consoleOutput'); const mainContent = document.querySelector('main.container-fluid'); const messageHistory = document.querySelector('.message-history'); // Open console by default if (consoleOutput && !consoleOutput.classList.contains('show')) { consoleOutput.classList.add('show'); if (toggleBtn) { toggleBtn.setAttribute('aria-expanded', 'true'); toggleBtn.innerHTML = 'expand_more'; } // Add expanded class to main content if (mainContent) { mainContent.classList.add('console-expanded'); } // Ensure console scrolls to bottom setTimeout(() => { consoleOutput.scrollTop = consoleOutput.scrollHeight; }, 50); } if (toggleBtn && consoleOutput) { toggleBtn.addEventListener('click', function() { // Toggle the collapse const isExpanded = toggleBtn.getAttribute('aria-expanded') === 'true'; if (!isExpanded) { // Expanding toggleBtn.innerHTML = 'expand_more'; if (mainContent) { mainContent.classList.add('console-expanded'); } // Force scroll to bottom when opened setTimeout(() => { consoleOutput.scrollTop = consoleOutput.scrollHeight; }, 100); } else { // Collapsing toggleBtn.innerHTML = 'expand_less'; if (mainContent) { mainContent.classList.remove('console-expanded'); } // Force message history to adjust after collapse animation setTimeout(() => { if (messageHistory) { // Force a reflow to make sure the height updates messageHistory.style.height = ''; messageHistory.offsetHeight; // Force reflow messageHistory.style.height = 'calc(100vh - 445px)'; } }, 300); // Wait for collapse animation to complete } // Use Bootstrap's collapse method if (typeof bootstrap !== 'undefined') { const collapse = new bootstrap.Collapse(consoleOutput); collapse.toggle(); } else { // Fallback toggle consoleOutput.classList.toggle('show'); } }); } // Add a resize event listener to handle window resizing window.addEventListener('resize', function() { if (messageHistory) { if (mainContent && mainContent.classList.contains('console-expanded')) { messageHistory.style.height = 'calc(100vh - 595px)'; } else { messageHistory.style.height = 'calc(100vh - 445px)'; } } }); } // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', function() { console.log('Console.js DOMContentLoaded fired'); // Initialize console panel initConsolePanel(); // Create global LogViewer instance if container exists const statusMessages = document.getElementById('statusMessages'); console.log('statusMessages element:', statusMessages); if (statusMessages) { console.log('Creating LogViewer instance...'); // Store the old logViewer if it exists const oldLogViewer = window.logViewer; // Create new instance window.logViewer = new LogViewer('statusMessages'); console.log('LogViewer created:', { instance: window.logViewer, constructor: window.logViewer.constructor.name, prototype: Object.getPrototypeOf(window.logViewer), hasLogMethod: typeof window.logViewer.log === 'function', methods: Object.getOwnPropertyNames(window.logViewer).filter(name => typeof window.logViewer[name] === 'function') }); // If there was an old logViewer, log info about it if (oldLogViewer) { console.log('Old logViewer was:', { type: typeof oldLogViewer, constructor: oldLogViewer.constructor ? oldLogViewer.constructor.name : 'unknown', methods: Object.getOwnPropertyNames(oldLogViewer).filter(name => typeof oldLogViewer[name] === 'function') }); } // Test the new instance console.log('Testing new LogViewer instance'); try { console.log('LogViewer test successful'); } catch (e) { console.error('LogViewer test failed:', e); } // Rest of your initialization code... } else { console.warn('statusMessages container not found'); } });