📜
console.js
Back
📝 Javascript ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
// ===== Console Module - Interactive JavaScript Console ===== // Wait for editor to be ready document.addEventListener('DOMContentLoaded', () => { // Get editor reference from global API const { editor, getValue } = window.editorAPI || {}; if (!editor) { console.warn('Editor not found, console functionality may be limited'); return; } // DOM elements const consoleBtn = document.getElementById("consoleBtn"); const consoleOverlay = document.getElementById("consoleOverlay"); const consoleClose = document.getElementById("consoleClose"); const consoleOutput = document.getElementById("consoleOutput"); const consoleForm = document.getElementById("consoleForm"); const consoleInput = document.getElementById("consoleInput"); const clearConsole = document.getElementById("clearConsole"); const runCode = document.getElementById("runCode"); // Console history and state let commandHistory = []; let historyIndex = -1; let consoleContext = {}; // ===== Overlay Management ===== function openOverlay() { consoleOverlay.classList.add("open"); setTimeout(() => { consoleInput.focus(); if (consoleOutput.children.length === 0) { addOutput('JavaScript Console Ready. Type commands or run editor code.', 'log'); addOutput('Try: Math.random(), new Date(), or any JavaScript!', 'log'); } }, 0); } function closeOverlay() { consoleOverlay.classList.remove("open"); consoleBtn.focus(); } // Event listeners consoleBtn.addEventListener("click", openOverlay); consoleClose.addEventListener("click", closeOverlay); // ESC key to close window.addEventListener("keydown", (e) => { if (consoleOverlay.classList.contains("open") && e.key === "Escape") { closeOverlay(); } }); // ===== Console Output Management ===== function addOutput(content, type = 'log') { const line = document.createElement('div'); line.className = `console-line console-${type}-line`; if (typeof content === 'object') { line.textContent = JSON.stringify(content, null, 2); } else { line.textContent = String(content); } consoleOutput.appendChild(line); consoleOutput.scrollTop = consoleOutput.scrollHeight; } function addInputLine(command) { const line = document.createElement('div'); line.className = 'console-line console-input-line'; line.textContent = `> ${command}`; consoleOutput.appendChild(line); } function clearConsoleOutput() { consoleOutput.innerHTML = ''; addOutput('Console cleared', 'log'); } // ===== JavaScript Execution ===== // Override console methods to capture output const originalConsole = { log: console.log, error: console.error, warn: console.warn, info: console.info }; function setupConsoleInterception() { console.log = (...args) => { originalConsole.log(...args); addOutput(args.join(' '), 'log'); }; console.error = (...args) => { originalConsole.error(...args); addOutput(args.join(' '), 'error'); }; console.warn = (...args) => { originalConsole.warn(...args); addOutput(args.join(' '), 'error'); }; console.info = (...args) => { originalConsole.info(...args); addOutput(args.join(' '), 'log'); }; } function restoreConsole() { console.log = originalConsole.log; console.error = originalConsole.error; console.warn = originalConsole.warn; console.info = originalConsole.info; } // Execute JavaScript code safely function executeCode(code) { try { setupConsoleInterception(); // Create a function to execute the code with access to context const func = new Function( ...Object.keys(consoleContext), ` "use strict"; return eval(${JSON.stringify(code)}); ` ); const result = func(...Object.values(consoleContext)); // Only show result if it's not undefined and wasn't logged if (result !== undefined) { addOutput(result, 'output'); } return result; } catch (error) { addOutput(`Error: ${error.message}`, 'error'); return undefined; } finally { restoreConsole(); } } // ===== Command History ===== function addToHistory(command) { // Remove duplicate if exists const existingIndex = commandHistory.indexOf(command); if (existingIndex > -1) { commandHistory.splice(existingIndex, 1); } // Add to end and limit history size commandHistory.push(command); if (commandHistory.length > 50) { commandHistory.shift(); } historyIndex = commandHistory.length; } function navigateHistory(direction) { if (commandHistory.length === 0) return; if (direction === 'up') { historyIndex = Math.max(0, historyIndex - 1); } else if (direction === 'down') { historyIndex = Math.min(commandHistory.length, historyIndex + 1); } if (historyIndex < commandHistory.length) { consoleInput.value = commandHistory[historyIndex]; } else { consoleInput.value = ''; } } // ===== Event Handlers ===== // Form submission consoleForm.addEventListener('submit', (e) => { e.preventDefault(); const command = consoleInput.value.trim(); if (!command) return; // Add to display and history addInputLine(command); addToHistory(command); // Execute command executeCode(command); // Clear input consoleInput.value = ''; }); // History navigation consoleInput.addEventListener('keydown', (e) => { if (e.key === 'ArrowUp') { e.preventDefault(); navigateHistory('up'); } else if (e.key === 'ArrowDown') { e.preventDefault(); navigateHistory('down'); } else if (e.key === 'Tab') { e.preventDefault(); // Basic autocompletion for common objects const value = consoleInput.value; const lastWord = value.split(/\s/).pop(); if (lastWord.includes('.')) { // Don't autocomplete for now, just prevent tab return; } const suggestions = ['console', 'document', 'window', 'Math', 'Date', 'Array', 'Object', 'JSON']; const matches = suggestions.filter(s => s.startsWith(lastWord)); if (matches.length === 1) { const newValue = value.replace(new RegExp(lastWord + '$'), matches[0]); consoleInput.value = newValue; } } }); // Clear console clearConsole.addEventListener('click', clearConsoleOutput); // Run current editor code runCode.addEventListener('click', () => { const code = getValue ? getValue() : editor.getValue(); const mode = editor.session.getMode().$id; if (mode !== 'ace/mode/javascript' && !code.includes('<script>')) { addOutput('Note: Editor content is not JavaScript. Running anyway...', 'log'); } // Extract JavaScript from HTML if needed let jsCode = code; if (mode === 'ace/mode/html') { const scriptMatches = code.match(/<script[^>]*>([\s\S]*?)<\/script>/gi); if (scriptMatches) { jsCode = scriptMatches.map(match => match.replace(/<script[^>]*>|<\/script>/gi, '') ).join('\n\n'); } else { addOutput('No <script> tags found in HTML', 'error'); return; } } addInputLine('// Running editor code...'); executeCode(jsCode); }); // ===== Built-in Commands & Utilities ===== // Add some helpful utilities to the console context consoleContext.help = function() { const helpText = ` JavaScript Console Help: • Type any JavaScript expression • Use arrow keys for command history • Tab for basic autocompletion • clear() - Clear console • help() - Show this help • editor() - Get editor content • run() - Run editor code • Math, Date, Array, Object - Built-in objects available `; addOutput(helpText.trim(), 'log'); }; consoleContext.clear = clearConsoleOutput; consoleContext.editor = function() { return getValue ? getValue() : editor.getValue(); }; consoleContext.run = function() { runCode.click(); }; // ===== Keyboard Shortcuts ===== document.addEventListener('keydown', (e) => { // Ctrl/Cmd + Shift + C for console if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'C') { e.preventDefault(); openOverlay(); } // Ctrl/Cmd + Enter to run code from anywhere if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); runCode.click(); } }); // ===== Auto-run on certain events ===== // Optionally run code when editor content changes (commented out for performance) // editor.on('change', _.debounce(() => { // if (consoleOverlay.classList.contains('open')) { // // Auto-run on change if console is open // } // }, 1000)); // ===== Export Console API ===== window.consoleAPI = { openOverlay, closeOverlay, executeCode, addOutput, clearConsoleOutput, commandHistory }; console.log("Console module loaded successfully"); });