Live Script Sandbox (JS/CSS Injector & Debugger)

Yazdığınız JS/CSS kodunu sayfayı yenilemeden anında sayfaya enjekte eden, console.log'ları ve runtime hatalarını canlı panelde raporlayan premium simülatör.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

Advertisement:

// ==UserScript==
// @name         Live Script Sandbox (JS/CSS Injector & Debugger)
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Yazdığınız JS/CSS kodunu sayfayı yenilemeden anında sayfaya enjekte eden, console.log'ları ve runtime hatalarını canlı panelde raporlayan premium simülatör.
// @match        *://*/*
// @grant        none
// @icon         https://cdn-icons-png.flaticon.com/512/1216/1216641.png
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    const translations = {
        en: {
            titleLeft: "Sandbox Editor",
            titleRight: "Terminal Console",
            placeholder: "// Write your JS code here...\\nconsole.log('Hello from Sandbox!');",
            cssPlaceholder: "/* Write your CSS here... */\\nbody { filter: invert(0); }",
            btnRun: "Run Script",
            btnClear: "Clear Logs",
            successCss: "✨ CSS successfully injected into document head.",
            successJs: "✅ Execution finished with zero uncaught errors.",
            emptyCode: "⚠ Terminal: Please write some code first."
        },
        tr: {
            titleLeft: "Sandbox Editör",
            titleRight: "Terminal Konsolu",
            placeholder: "// JS kodunuzu buraya yazın...\\nconsole.log('Sandbox\\'tan Selamlar!');",
            cssPlaceholder: "/* CSS kodunuzu buraya yazın... */\\nbody { filter: invert(0); }",
            btnRun: "Kodu Çalıştır",
            btnClear: "Konsolu Temizle",
            successCss: "✨ CSS, döküman head etiketine başarıyla enjekte edildi.",
            successJs: "✅ Kod yürütme sıfır hata ile tamamlandı.",
            emptyCode: "⚠ Terminal: Lütfen önce bir kod bloğu yazın."
        },
        de: {
            titleLeft: "Sandbox Editor",
            titleRight: "Terminal-Konsole",
            placeholder: "// Schreiben Sie hier Ihren JS-Code...\\nconsole.log('Hallo aus der Sandbox!');",
            cssPlaceholder: "/* Schreiben Sie hier Ihren CSS-Code... */\\nbody { filter: invert(0); }",
            btnRun: "Code Ausführen",
            btnClear: "Konsole Leeren",
            successCss: "✨ CSS erfolgreich in den Document Head injiziert.",
            successJs: "✅ Ausführung mit null unbehandelten Fehlern abgeschlossen.",
            emptyCode: "⚠ Terminal: Bitte schreiben Sie zuerst etwas Code."
        }
    };

    let t = translations.tr;
    let mainHost = null;

    function toggleSandboxPanel() {
        if (mainHost) { mainHost.remove(); mainHost = null; } 
        else { createSandboxPanel(); }
    }

    function executeSandbox(rawCode, mode, outputTerminal) {
        if (!rawCode.trim()) {
            outputTerminal.innerHTML = `<span style="color: #94A3B8;">${t.emptyCode}</span>`;
            return;
        }

        if (mode === 'css') {
            let sandboxStyle = document.getElementById('tm-live-sandbox-style');
            if (!sandboxStyle) {
                sandboxStyle = document.createElement('style');
                sandboxStyle.id = 'tm-live-sandbox-style';
                document.head.appendChild(sandboxStyle);
            }
            sandboxStyle.textContent = rawCode;
            outputTerminal.innerHTML = `<span style="color: #10B981; font-weight: bold;">${t.successCss}</span>`;
        } else {
            outputTerminal.innerHTML = '';
            let logBuffer = [];
            
            const createLogLine = (type, args) => {
                const strArgs = args.map(arg => {
                    if (typeof arg === 'object') {
                        try { return JSON.stringify(arg); } catch(e) { return String(arg); }
                    }
                    return String(arg);
                }).join(' ');

                if (type === 'error') return `<div style="color: #F87171; padding: 2px 0;">🛑 [CON-ERROR] ${strArgs}</div>`;
                if (type === 'warn') return `<div style="color: #FBBF24; padding: 2px 0;">⚠️ [CON-WARN] ${strArgs}</div>`;
                return `<div style="color: #E2E8F0; padding: 2px 0;">💬 [LOG] ${strArgs}</div>`;
            };

            const interceptedConsole = {
                log: (...args) => { logBuffer.push(createLogLine('log', args)); },
                error: (...args) => { logBuffer.push(createLogLine('error', args)); },
                warn: (...args) => { logBuffer.push(createLogLine('warn', args)); },
                info: (...args) => { logBuffer.push(createLogLine('log', args)); }
            };

            try {
                const sandboxExecution = new Function('console', '"use strict";\\n' + rawCode);
                sandboxExecution(interceptedConsole);

                if (logBuffer.length > 0) {
                    outputTerminal.innerHTML = logBuffer.join('') + `<br><span style="color: #34D399; font-weight: 600;">${t.successJs}</span>`;
                } else {
                    outputTerminal.innerHTML = `<span style="color: #34D399; font-weight: 600;">${t.successJs}</span>`;
                }
            } catch (error) {
                let errorLine = "Bilinmiyor";
                if (error.stack) {
                    const match = error.stack.match(/<anonymous>:(\d+):(\d+)/);
                    if (match) errorLine = parseInt(match[1]) - 1;
                }

                outputTerminal.innerHTML = `
                    <div style="background: rgba(239, 68, 68, 0.15); border: 1px solid #EF4444; padding: 12px; border-radius: 6px; color: #F87171; font-family: monospace;">
                        <b style="font-size: 0.95rem; display: block; margin-bottom: 6px;">🛑 SİMÜLASYON HATASI:</b>
                        <div style="margin-bottom: 4px;"><b>Tür:</b> ${error.name}</div>
                        <div style="margin-bottom: 4px;"><b>Mesaj:</b> ${error.message}</div>
                        <div><b>Tahmini Satır:</b> <span style="background: #EF4444; color: white; padding: 1px 6px; border-radius: 4px; font-weight: bold;">${errorLine}</span></div>
                    </div>
                `;
            }
        }
    }

    function createSandboxPanel() {
        if (mainHost) return;

        mainHost = document.createElement('div');
        mainHost.id = "script-sandbox-host";
        mainHost.style.position = "fixed";
        mainHost.style.zIndex = "999999999";
        mainHost.style.top = "0";
        mainHost.style.left = "0";
        
        const shadow = mainHost.attachShadow({ mode: 'open' });
        document.body.appendChild(mainHost);

        const overlay = document.createElement('div');
        overlay.className = "sandbox-overlay";

        overlay.innerHTML = `
            <div class="sandbox-container">
                <div class="panel editor-panel">
                    <div class="panel-header">
                        <span id="leftTitle">${t.titleLeft}</span>
                        <div class="header-actions">
                            <select id="modeSelect" class="premium-select mode-indicator">
                                <option value="js">🟨 JavaScript</option>
                                <option value="css">🟦 CSS Mode</option>
                            </select>
                            <select id="langSelect" class="premium-select">
                                <option value="en">🇬🇧 EN</option>
                                <option value="tr" selected>🇹🇷 TR</option>
                                <option value="de">🇩🇪 DE</option>
                            </select>
                            <button id="closeBtn" class="close-btn" title="ESC">✕</button>
                        </div>
                    </div>
                    <div class="code-area">
                        <div class="line-numbers" id="leftLines"></div>
                        <textarea id="inputCode" spellcheck="false"></textarea>
                    </div>
                </div>

                <div class="action-column">
                    <button id="runBtn" class="action-btn play-btn">
                        <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
                            <polygon points="5 3 19 12 5 21 5 3"></polygon>
                        </svg>
                    </button>
                    <button id="clearBtn" class="action-btn trash-btn">
                        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
                            <polyline points="3 6 5 6 21 6"></polyline>
                            <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
                        </svg>
                    </button>
                </div>

                <div class="panel terminal-panel">
                    <div class="panel-header">
                        <span id="rightTitle">${t.titleRight}</span>
                        <span class="terminal-badge">LIVE REACTION</span>
                    </div>
                    <div class="code-area terminal-bg">
                        <div id="outputTerminal" tabindex="0"></div>
                    </div>
                </div>
            </div>
        `;

        const style = document.createElement('style');
        style.textContent = `
            .sandbox-overlay * { box-sizing: border-box; margin: 0; padding: 0; }
            .sandbox-overlay {
                position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
                background: rgba(9, 15, 29, 0.8); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
                display: flex; align-items: center; justify-content: center;
                font-family: system-ui, -apple-system, sans-serif; padding: 24px;
            }
            .sandbox-container {
                width: 100vw; max-width: 1450px; height: 85vh; max-height: 85vh !important;
                background: #1E293B; border: 1px solid #334155; border-radius: 24px; padding: 20px;
                display: grid; grid-template-columns: 1fr 60px 1fr; gap: 16px; align-items: stretch;
                box-shadow: 0 30px 70px -10px rgba(0, 0, 0, 0.7); overflow: hidden !important;
            }
            .panel {
                background: #0F172A; border: 1px solid #1E293B; border-radius: 16px;
                padding: 16px; display: flex; flex-direction: column; gap: 14px; 
                min-height: 0 !important; height: 100% !important; max-height: 100% !important; overflow: hidden !important;
            }
            .panel-header { display: flex; justify-content: space-between; align-items: center; height: 36px; flex-shrink: 0; }
            .panel-header span { font-size: 0.85rem; font-weight: 800; color: #94A3B8; text-transform: uppercase; letter-spacing: 0.8px; }
            .header-actions { display: flex; gap: 8px; align-items: center; }
            
            .premium-select, .close-btn {
                background: #1E293B; border: 1px solid #334155; border-radius: 8px;
                padding: 6px 12px; font-size: 0.75rem; font-weight: 600; cursor: pointer; color: #CBD5E1; outline: none;
                transition: all 0.2s;
            }
            .mode-indicator { background: #10B981; color: white; border: none; }
            .premium-select:hover { border-color: #475569; background: #273549; }
            .close-btn:hover { background: #EF4444; color: white; border-color: #EF4444; }
            
            .terminal-badge { font-size: 0.7rem !important; background: #334155; color: #38BDF8 !important; padding: 4px 10px; border-radius: 20px; font-weight: 700; }

            .code-area { 
                flex: 1; display: flex; background: #020617; border-radius: 12px; 
                overflow: hidden !important; border: 1px solid #1E293B; min-height: 0 !important; height: 100%; max-height: 100%;
            }
            .terminal-bg { border-color: #334155; box-shadow: inset 0 4px 20px rgba(0,0,0,0.5); }
            
            .line-numbers {
                background: #090D1A; padding: 16px 8px; text-align: right; font-family: 'Courier New', monospace;
                font-size: 0.85rem; color: #475569; user-select: none; min-width: 50px; white-space: pre; line-height: 1.6; 
                overflow: hidden !important; border-right: 1px solid #1E293B; height: 100%; max-height: 100%;
            }
            textarea, #outputTerminal {
                flex: 1; padding: 16px; font-family: 'Courier New', monospace; font-size: 0.9rem; line-height: 1.6;
                border: none; background: transparent; resize: none; outline: none; color: #E2E8F0;
                overflow: auto !important; white-space: pre; height: 100% !important; max-height: 100% !important; width: 100%;
            }
            #outputTerminal { white-space: pre-wrap; word-break: break-all; color: #38BDF8; overflow-y: auto !important; }
            
            .action-column { display: flex; flex-direction: column; gap: 16px; justify-content: center; align-items: center; flex-shrink: 0; }
            .action-btn {
                color: white; border: none; width: 50px; height: 50px; border-radius: 50%;
                cursor: pointer; display: flex; align-items: center; justify-content: center;
                transition: all 0.25s; box-shadow: 0 8px 20px rgba(0,0,0,0.3);
            }
            .play-btn { background: #10B981; box-shadow: 0 6px 20px rgba(16, 185, 129, 0.4); }
            .play-btn:hover { background: #059669; transform: scale(1.1) rotate(90deg); }
            .trash-btn { background: #475569; }
            .trash-btn:hover { background: #EF4444; transform: scale(1.1); }
        `;

        shadow.appendChild(style);
        shadow.appendChild(overlay);

        const input = shadow.getElementById('inputCode');
        const outputTerminal = shadow.getElementById('outputTerminal');
        const leftLines = shadow.getElementById('leftLines');
        const runBtn = shadow.getElementById('runBtn');
        const clearBtn = shadow.getElementById('clearBtn');
        const closeBtn = shadow.getElementById('closeBtn');
        const langSelect = shadow.getElementById('langSelect');
        const modeSelect = shadow.getElementById('modeSelect');

        const updateLineNumbers = () => {
            const lines = input.value || '';
            const lineCount = lines.split('\n').length;
            let nums = '';
            for (let i = 1; i <= lineCount; i++) nums += i + '\n';
            leftLines.textContent = nums;
        };

        input.addEventListener('input', updateLineNumbers);
        input.addEventListener('scroll', () => { leftLines.scrollTop = input.scrollTop; });

        runBtn.addEventListener('click', () => {
            executeSandbox(input.value, modeSelect.value, outputTerminal);
        });

        clearBtn.addEventListener('click', () => {
            outputTerminal.innerHTML = '';
        });

        modeSelect.addEventListener('change', (e) => {
            if (e.target.value === 'css') {
                e.target.style.background = '#0ea5e9';
                input.value = t.cssPlaceholder;
            } else {
                e.target.style.background = '#10B981';
                input.value = t.placeholder;
            }
            updateLineNumbers();
        });

        const closePanel = () => {
            if (mainHost) { mainHost.remove(); mainHost = null; }
            document.removeEventListener('keydown', escHandler);
        };

        closeBtn.addEventListener('click', closePanel);
        const escHandler = (e) => { if (e.key === 'Escape') closePanel(); };
        document.addEventListener('keydown', escHandler);
        
        langSelect.addEventListener('change', (e) => {
            t = translations[e.target.value];
            shadow.getElementById('leftTitle').textContent = t.titleLeft;
            shadow.getElementById('rightTitle').textContent = t.titleRight;
            runBtn.title = t.btnRun;
            clearBtn.title = t.btnClear;
            
            if (modeSelect.value === 'js') {
                input.placeholder = t.placeholder;
            } else {
                input.placeholder = t.cssPlaceholder;
            }
        });

        input.value = t.placeholder;
        updateLineNumbers();
        input.focus();
    }

    document.addEventListener('keydown', (e) => {
        if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === 's') {
            e.preventDefault();
            toggleSandboxPanel();
        }
    });
})();