📜
editor.js
Back
📝 Javascript ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
// ===== Editor Core ===== const editor = ace.edit("editor"); // Disable workers to avoid security errors in sandboxed environments editor.session.setUseWorker(false); editor.session.setMode("ace/mode/html"); editor.setTheme("ace/theme/monokai"); editor.setOptions({ tabSize: 2, useSoftTabs: true, showPrintMargin: false, wrap: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true, enableSnippets: true, fontSize: "14px", }); // Demo content // ===== STRESS DEMO for Ace tokens (HTML mode) ===== // ===== STRESS DEMO with @editIdentifiers markers ===== // ===== STRESS DEMO with @editIdentifiers markers in HTML + JS comments ===== // ===== STRESS DEMO with inline // @editIdentifiers markers ===== const demo = `<!doctype html> <html lang="en" data-app="stress"> <head> <meta charset="utf-8"> <title>Hello</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- @editIdentifiers@ --> <style> :root { --brand:#4B9; --pad: 8px } body[data-theme="dark"] .hi { font: italic 600 1.5rem/1.3 system-ui; margin: var(--pad); } </style> </head> <body> <h1 title="Greeting" data-role="title">Hello, world! &amp; 👋</h1> <button id="btn">Click me</button> <!-- Scoped: only identifiers named sayHello and user --> <script type="module"> const user = { name: "Ada" }; // @editIdentifiers.sayHello.user@ function sayHello(name) { console.log("Hello,", name); } // @editIdentifiers.sayHello.user@ sayHello(user.name); // @editIdentifiers.sayHello.user@ const notMe = 123; // ignored function helper() { return "nope"; } // ignored </script> <!-- Different scope: only 'x' and 'y' --> <script> let x = 10, y = 20; // @editIdentifiers.x.y@ function add(x, y) { return x + y; } // @editIdentifiers.x.y@ const sum = add(x, y); // @editIdentifiers.x.y@ let z = 3; // ignored function mul(a, b) { return a * b; } // ignored const t = mul(z, sum); // ignored </script> <!-- Catch all --> <script> const n = 10, s = "10", b = true; // @editIdentifiers@ function helper(rate = 0.25) { return Number(rate) * 2; } // @editIdentifiers@ function main(name = \`User-\${n}\`) { // @editIdentifiers@ for (let i = 0; i < 3; i++) { // @editIdentifiers@ if (i === 1 && b) console.log(name, i, new Date().toISOString()); // @editIdentifiers@ } document.getElementById('btn')?.addEventListener('click', (ev) => { // @editIdentifiers@ ev.preventDefault(); // @editIdentifiers@ alert('Hello from JavaScript! ' + helper(0.5)); // @editIdentifiers@ }); } main(); // @editIdentifiers@ </script> <!-- Control: no marker here --> <script> const locked = 1; function closed() { return locked + 1; } const result = closed(); </script> <div id="PLAY" data-add-here> <!-- You can paste extra code with inline markers like: let foo = 1; // @editIdentifiers.foo@ --> </div> </body> </html>`; editor.setValue(demo, -1); // ===== Helpers ===== const $ = (id) => document.getElementById(id); // ===== Settings Panel & Tabs ===== const panel = $("panel"); const settingsBtn = $("settingsBtn"); settingsBtn.addEventListener("click", (e) => { panel.classList.toggle("open"); e.stopPropagation(); }); document.addEventListener("click", (e) => { if (!panel.contains(e.target) && !settingsBtn.contains(e.target)) { panel.classList.remove("open"); } }); // Tab management const tabEditor = $("tab-editor"); const tabAI = $("tab-ai"); const panelEditor = $("panel-editor"); const panelAI = $("panel-ai"); function selectTab(which) { const isEditor = which === "editor"; tabEditor.setAttribute("aria-selected", String(isEditor)); tabAI.setAttribute("aria-selected", String(!isEditor)); panelEditor.classList.toggle("active", isEditor); panelAI.classList.toggle("active", !isEditor); } tabEditor.addEventListener("click", () => selectTab("editor")); tabAI.addEventListener("click", () => selectTab("ai")); // ===== Settings & Preferences ===== const themeSel = $("theme"); const wrapChk = $("wrap"); const fontRange = $("fontsize"); const modeSel = $("mode"); const aiProvider = $("ai-provider"); const aiModel = $("ai-model"); const aiTemp = $("ai-temp"); const aiKey = $("ai-key"); // Safe localStorage access with fallback function getPrefs() { try { return JSON.parse(localStorage?.getItem?.("ace_min_prefs") || "{}"); } catch (e) { console.warn("localStorage not available, using defaults"); return {}; } } function savePrefs() { try { localStorage?.setItem?.("ace_min_prefs", JSON.stringify({ theme: editor.getTheme(), wrap: editor.session.getUseWrapMode(), fontSize: editor.getFontSize(), mode: editor.session.getMode().$id, ai: { provider: aiProvider.value, model: aiModel.value, temperature: parseFloat(aiTemp.value), key: aiKey.value } })); } catch (e) { console.warn("Could not save preferences:", e.message); } } // Load saved preferences const prefs = getPrefs(); if (prefs.theme) { editor.setTheme(prefs.theme); themeSel.value = prefs.theme; } if (prefs.wrap != null) { editor.session.setUseWrapMode(!!prefs.wrap); wrapChk.checked = !!prefs.wrap; } if (prefs.fontSize) { editor.setFontSize(prefs.fontSize); fontRange.value = parseInt(prefs.fontSize); } if (prefs.mode) { editor.session.setMode(prefs.mode); modeSel.value = prefs.mode; } if (prefs.ai) { aiProvider.value = prefs.ai.provider ?? "none"; aiModel.value = prefs.ai.model ?? ""; aiTemp.value = prefs.ai.temperature ?? 0.4; aiKey.value = prefs.ai.key ?? ""; } // Settings event listeners themeSel.addEventListener("change", (e) => { editor.setTheme(e.target.value); savePrefs(); }); wrapChk.addEventListener("change", (e) => { editor.session.setUseWrapMode(e.target.checked); savePrefs(); }); fontRange.addEventListener("input", (e) => { editor.setFontSize(e.target.value + "px"); }); fontRange.addEventListener("change", savePrefs); modeSel.addEventListener("change", (e) => { editor.session.setMode(e.target.value); savePrefs(); }); // AI settings aiProvider.addEventListener("change", savePrefs); aiModel.addEventListener("change", savePrefs); aiTemp.addEventListener("input", savePrefs); aiKey.addEventListener("change", savePrefs); // ===== Export for other modules ===== window.editorAPI = { editor, getSelectedText: () => editor.getSelectedText(), getValue: () => editor.getValue(), focus: () => editor.focus(), savePrefs, getPrefs }; console.log("Editor module loaded successfully");