Adds a draggable button and keyboard toggle to open/close Eruda console in Orion browser on iOS.
// ==UserScript== // @name Orion iOS Eruda Console Toggle // @namespace https://littlelooney.example/orion-eruda // @version 2026-05-24.1 // @description Adds a draggable button and keyboard toggle to open/close Eruda console in Orion browser on iOS. // @author LittleLooney + OpenAI // @match *://*/* // @require https://cdn.jsdelivr.net/npm/[email protected]/eruda.min.js // @grant none // @run-at document-idle // ==/UserScript== (() => { 'use strict'; const STORAGE_KEY = 'orion-eruda-toggle-position'; const BTN_ID = 'orion-eruda-toggle-btn'; let erudaReady = false; let erudaVisible = false; function loadPosition() { try { const saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); if (typeof saved.left === 'number' && typeof saved.top === 'number') return saved; } catch { // ignore broken storage } return { left: 14, top: 86 }; } function savePosition(left, top) { localStorage.setItem(STORAGE_KEY, JSON.stringify({ left, top })); } function clamp(value, min, max) { return Math.min(Math.max(value, min), max); } function updateButtonStyle(btn, pos) { const maxLeft = Math.max(8, window.innerWidth - btn.offsetWidth - 8); const maxTop = Math.max(8, window.innerHeight - btn.offsetHeight - 8); const left = clamp(pos.left, 8, maxLeft); const top = clamp(pos.top, 8, maxTop); btn.style.left = `${left}px`; btn.style.top = `${top}px`; savePosition(left, top); } function ensureEruda() { if (!window.eruda) { throw new Error('Eruda library is unavailable. Orion may have blocked @require loading.'); } if (!erudaReady) { window.eruda.init(); window.eruda.hide(); erudaReady = true; erudaVisible = false; } } function setButtonState(btn, text) { btn.textContent = text; btn.setAttribute('aria-label', text); } function toggleEruda(btn) { btn.disabled = true; try { ensureEruda(); erudaVisible = !erudaVisible; if (erudaVisible) { window.eruda.show(); setButtonState(btn, 'Console: ON'); } else { window.eruda.hide(); setButtonState(btn, 'Console: OFF'); } } catch (err) { console.error('[Orion Eruda]', err); setButtonState(btn, 'Console: ERR'); setTimeout(() => setButtonState(btn, erudaVisible ? 'Console: ON' : 'Console: OFF'), 1600); } finally { btn.disabled = false; } } function makeDraggable(btn) { let dragging = false; let moved = false; let startX = 0; let startY = 0; let originLeft = 0; let originTop = 0; const onMove = (clientX, clientY) => { if (!dragging) return; const dx = clientX - startX; const dy = clientY - startY; moved = moved || Math.abs(dx) > 4 || Math.abs(dy) > 4; updateButtonStyle(btn, { left: originLeft + dx, top: originTop + dy }); }; btn.addEventListener('touchstart', (e) => { const t = e.touches[0]; if (!t) return; dragging = true; moved = false; startX = t.clientX; startY = t.clientY; originLeft = parseFloat(btn.style.left) || 0; originTop = parseFloat(btn.style.top) || 0; }, { passive: true }); btn.addEventListener('touchmove', (e) => { const t = e.touches[0]; if (!t) return; onMove(t.clientX, t.clientY); }, { passive: true }); btn.addEventListener('touchend', () => { dragging = false; }, { passive: true }); btn.addEventListener('mousedown', (e) => { dragging = true; moved = false; startX = e.clientX; startY = e.clientY; originLeft = parseFloat(btn.style.left) || 0; originTop = parseFloat(btn.style.top) || 0; e.preventDefault(); }); window.addEventListener('mousemove', (e) => onMove(e.clientX, e.clientY)); window.addEventListener('mouseup', () => { dragging = false; }); btn.addEventListener('click', (e) => { if (moved) { e.preventDefault(); e.stopPropagation(); moved = false; return; } toggleEruda(btn); }); } function attachKeyboardShortcut(btn) { window.addEventListener('keydown', (e) => { if (e.altKey && e.key.toLowerCase() === 'd') { e.preventDefault(); toggleEruda(btn); } }); } function injectUi() { if (document.getElementById(BTN_ID)) return; const btn = document.createElement('button'); btn.id = BTN_ID; btn.type = 'button'; setButtonState(btn, 'Console: OFF'); btn.title = 'Tap to toggle Eruda console. Drag to move. Keyboard: Alt + D'; Object.assign(btn.style, { position: 'fixed', zIndex: '2147483647', padding: '10px 12px', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.25)', background: 'rgba(16,16,20,0.85)', color: '#f5f5f5', fontFamily: '-apple-system, BlinkMacSystemFont, Segoe UI, sans-serif', fontSize: '13px', fontWeight: '600', boxShadow: '0 6px 24px rgba(0,0,0,0.25)', backdropFilter: 'blur(5px)', WebkitBackdropFilter: 'blur(5px)', cursor: 'pointer', userSelect: 'none', WebkitUserSelect: 'none', opacity: '0.95', }); const saved = loadPosition(); document.documentElement.appendChild(btn); updateButtonStyle(btn, saved); makeDraggable(btn); attachKeyboardShortcut(btn); window.addEventListener('resize', () => { updateButtonStyle(btn, { left: parseFloat(btn.style.left) || 8, top: parseFloat(btn.style.top) || 8, }); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', injectUi, { once: true }); } else { injectUi(); } })();