/** * Erga Accessibility Widget v2.0.0 (Full Feature Edition) * Open-source, lightweight, privacy-first accessibility widget. */ (function() { 'use strict'; if (window.ErgaWidgetInitialized) return; window.ErgaWidgetInitialized = true; const STORAGE_KEY = 'erga_accessibility_settings_v2'; let settings = { fontSizeMultiplier: 1.0, fontFamily: 'default', contrast: 'normal', grayscale: false, colorBlindness: 'none', animations: true, cursor: 'default', readingGuide: false, highlightLinks: false, highlightHeadings: false, textSpacing: false, hideImages: false, speechActive: false, lang: 'id' }; const t = { id: { title: 'Panel Aksesibilitas', subtitle: 'Sesuaikan tampilan website untuk kenyamanan Anda', reset: 'Atur Ulang', close: 'Tutup', tools: 'Alat Aksesibilitas', profiles: 'Profil Cepat', fontSize: 'Ukuran Font', fontFamily: 'Jenis Font', grayscale: 'Skala Abu-abu', contrast: 'Kontras Tinggi', colorBlindness: 'Buta Warna', animations: 'Matikan Animasi', cursor: 'Kursor Besar', readingGuide: 'Panduan Baca', highlightLinks: 'Sorot Tautan', highlightHeadings: 'Sorot Judul', textSpacing: 'Spasi Teks', hideImages: 'Sembunyikan Gambar', speech: 'Pembaca Suara (TTS)', profileDyslexia: 'Ramah Disleksia', profileAdhd: 'Ramah ADHD', profileVision: 'Low Vision', profileSeizure: 'Ramah Epilepsi' }, en: { title: 'Accessibility Panel', subtitle: 'Customize website view for your comfort', reset: 'Reset All', close: 'Close', tools: 'Accessibility Tools', profiles: 'Quick Profiles', fontSize: 'Font Size', fontFamily: 'Font Family', grayscale: 'Grayscale', contrast: 'High Contrast', colorBlindness: 'Color Blindness', animations: 'Stop Animations', cursor: 'Big Cursor', readingGuide: 'Reading Guide', highlightLinks: 'Highlight Links', highlightHeadings: 'Highlight Headings', textSpacing: 'Text Spacing', hideImages: 'Hide Images', speech: 'Text-to-Speech', profileDyslexia: 'Dyslexia Friendly', profileAdhd: 'ADHD Friendly', profileVision: 'Low Vision', profileSeizure: 'Seizure Safe' } }; function gettext(key) { const lang = settings.lang.startsWith('id') ? 'id' : 'en'; return t[lang][key] || t['en'][key] || key; } try { const saved = localStorage.getItem(STORAGE_KEY); if (saved) settings = { ...settings, ...JSON.parse(saved) }; } catch(e) {} const style = document.createElement('style'); style.id = 'erga-accessibility-styles'; document.head.appendChild(style); const guideEl = document.createElement('div'); guideEl.id = 'erga-reading-guide-bar'; document.body.appendChild(guideEl); function updateStyles() { let css = ''; if (settings.contrast === 'dark') { css += `html { filter: invert(1) hue-rotate(180deg) !important; background-color: #111 !important; }`; css += `img, video, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; }`; } else if (settings.contrast === 'yellow') { css += `body, html { background-color: #000 !important; color: #ff0 !important; } * { background-color: transparent !important; color: #ff0 !important; border-color: #ff0 !important; }`; } if (settings.grayscale) { css += `html { filter: grayscale(100%) !important; }`; } if (settings.colorBlindness === 'protanopia') { css += `html { filter: url('#protanopia-filter') !important; }`; } else if (settings.colorBlindness === 'deuteranopia') { css += `html { filter: url('#deuteranopia-filter') !important; }`; } if (settings.fontFamily === 'dyslexia') { css += `p, span, a, li, h1, h2, h3, h4, h5, h6 { font-family: Comic SansMS, Arial, sans-serif !important; letter-spacing: 0.08em !important; word-spacing: 0.1em !important; }`; } else if (settings.fontFamily === 'serif') { css += `p, span, a, li, h1, h2, h3, h4, h5, h6 { font-family: Georgia, serif !important; }`; } if (!settings.animations) { css += `*, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }`; } if (settings.cursor === 'big') { css += `*, button, a, input { cursor: url('data:image/svg+xml;utf8,'), auto !important; }`; } if (settings.highlightLinks) { css += `a { background-color: #ff0 !important; color: #000 !important; text-decoration: underline !important; font-weight: bold !important; }`; } if (settings.highlightHeadings) { css += `h1, h2, h3, h4, h5, h6 { background-color: rgba(255, 235, 59, 0.4) !important; border: 2px dashed #fbc02d !important; padding: 4px !important; }`; } if (settings.textSpacing) { css += `p, span, li, a { word-spacing: 0.25em !important; line-height: 1.8 !important; letter-spacing: 0.08em !important; }`; } if (settings.hideImages) { css += `img, svg, picture, video { visibility: hidden !important; }`; } guideEl.style.display = settings.readingGuide ? 'block' : 'none'; style.textContent = css; // Direct Font Size Scaler const textElements = document.querySelectorAll('p, span, a, h1, h2, h3, h4, h5, h6, li, button'); textElements.forEach(el => { if (el.closest('#erga-widget-container')) return; if (!el.dataset.baseFontSize) { const computedSize = window.getComputedStyle(el).fontSize; el.dataset.baseFontSize = parseFloat(computedSize) || 16; } const base = parseFloat(el.dataset.baseFontSize); el.style.fontSize = (base * settings.fontSizeMultiplier) + 'px'; }); // Text to Speech Handling if (settings.speechActive) { startTextToSpeech(); } else { stopTextToSpeech(); } try { localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); } catch(e) {} } // SVG Filter for Color Blindness const svgFilters = document.createElement('div'); svgFilters.innerHTML = ` `; document.body.appendChild(svgFilters); // Reading Guide Mouse Follower document.addEventListener('mousemove', (e) => { if (settings.readingGuide) { guideEl.style.top = (e.clientY - 15) + 'px'; } }); // TTS Engine let utterance = null; function startTextToSpeech() { if (!('speechSynthesis' in window)) return; window.speechSynthesis.cancel(); const text = document.body.innerText.substring(0, 1500); // Ambil ringkasan teks halaman utterance = new SpeechSynthesisUtterance(text); utterance.lang = settings.lang.startsWith('id') ? 'id-ID' : 'en-US'; utterance.onend = () => { settings.speechActive = false; updateUIState(); }; window.speechSynthesis.speak(utterance); } function stopTextToSpeech() { if ('speechSynthesis' in window) { window.speechSynthesis.cancel(); } } const container = document.createElement('div'); container.id = 'erga-widget-container'; container.innerHTML = `
`; const uiStyle = document.createElement('style'); uiStyle.textContent = ` #erga-widget-container { position: fixed; bottom: 24px; right: 24px; z-index: 999999; font-family: system-ui, -apple-system, sans-serif; } #erga-fab { width: 52px; height: 52px; background: #000; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 10px 25px -5px rgba(0,0,0,0.3); transition: transform 0.2s, background 0.2s; user-select: none; } #erga-fab:hover { transform: scale(1.08); background: #222; } #erga-panel { position: absolute; bottom: 68px; right: 0; width: 340px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(16px); border: 1px solid rgba(0,0,0,0.1); border-radius: 16px; box-shadow: 0 20px 40px -10px rgba(0,0,0,0.2); display: none; flex-direction: column; overflow: hidden; animation: ergaSlideUp 0.25s cubic-bezier(0.16, 1, 0.3, 1); } #erga-panel.open { display: flex; } @keyframes ergaSlideUp { from { opacity: 0; transform: translateY(12px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } } .erga-header { padding: 16px; border-bottom: 1px solid #eee; display: flex; align-items: flex-start; justify-content: space-between; background: #fafafa; } .erga-header h3 { margin: 0; font-size: 15px; font-weight: 600; color: #111; } .erga-header p { margin: 2px 0 0; font-size: 12px; color: #666; } #erga-close { background: none; border: none; font-size: 20px; cursor: pointer; color: #666; padding: 0; line-height: 1; } .erga-body { padding: 16px; max-height: 400px; overflow-y: auto; display: flex; flex-direction: column; gap: 16px; } .erga-section label { display: block; font-size: 12px; font-weight: 600; color: #444; margin-bottom: 8px; } .erga-btn-group { display: flex; gap: 8px; } .erga-tool-btn, .erga-toggle-btn, .erga-profile-btn { flex: 1; padding: 8px 10px; background: #f4f4f5; border: 1px solid #e4e4e7; border-radius: 8px; font-size: 11px; font-weight: 500; color: #27272a; cursor: pointer; text-align: left; transition: all 0.15s; } .erga-tool-btn:hover, .erga-toggle-btn:hover, .erga-profile-btn:hover { background: #e4e4e7; } .erga-toggle-btn.active, .erga-profile-btn.active { background: #000; color: #fff; border-color: #000; } .erga-grid-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } .erga-footer { padding: 12px 16px; border-top: 1px solid #eee; background: #fafafa; } #erga-reset-all { width: 100%; padding: 8px; background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; border-radius: 8px; font-size: 12px; font-weight: 600; cursor: pointer; } #erga-reset-all:hover { background: #fecaca; } #erga-reading-guide-bar { position: fixed; left: 0; right: 0; height: 32px; background: rgba(255, 235, 59, 0.35); border-top: 2px solid #fbc02d; border-bottom: 2px solid #fbc02d; pointer-events: none; display: none; z-index: 999998; } `; document.head.appendChild(uiStyle); document.body.appendChild(container); const fab = document.getElementById('erga-fab'); const panel = document.getElementById('erga-panel'); const closeBtn = document.getElementById('erga-close'); const fontSizeVal = document.getElementById('erga-fontsize-val'); fab.addEventListener('click', () => { const isOpen = panel.classList.toggle('open'); panel.setAttribute('aria-hidden', !isOpen); }); closeBtn.addEventListener('click', () => { panel.classList.remove('open'); panel.setAttribute('aria-hidden', 'true'); }); function updateUIState() { document.querySelectorAll('[data-tool]').forEach(btn => { const tool = btn.getAttribute('data-tool'); if (settings[tool]) { btn.classList.add('active'); } else { btn.classList.remove('active'); } }); fontSizeVal.textContent = Math.round(settings.fontSizeMultiplier * 100) + '%'; } document.querySelectorAll('[data-action]').forEach(btn => { btn.addEventListener('click', () => { const action = btn.getAttribute('data-action'); if (action === 'font-inc' && settings.fontSizeMultiplier < 1.5) { settings.fontSizeMultiplier = parseFloat((settings.fontSizeMultiplier + 0.1).toFixed(1)); } if (action === 'font-dec' && settings.fontSizeMultiplier > 0.9) { settings.fontSizeMultiplier = parseFloat((settings.fontSizeMultiplier - 0.1).toFixed(1)); } if (action === 'font-reset') { settings.fontSizeMultiplier = 1.0; } updateStyles(); updateUIState(); }); }); document.querySelectorAll('[data-tool]').forEach(btn => { btn.addEventListener('click', () => { const tool = btn.getAttribute('data-tool'); settings[tool] = !settings[tool]; updateStyles(); updateUIState(); }); }); // Quick Profiles document.querySelectorAll('[data-profile]').forEach(btn => { btn.addEventListener('click', () => { const prof = btn.getAttribute('data-profile'); document.querySelectorAll('.erga-profile-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); if (prof === 'dyslexia') { settings.fontFamily = 'dyslexia'; settings.textSpacing = true; } else if (prof === 'adhd') { settings.readingGuide = true; settings.highlightHeadings = true; } else if (prof === 'vision') { settings.fontSizeMultiplier = 1.3; settings.contrast = 'dark'; } else if (prof === 'seizure') { settings.animations = false; } updateStyles(); updateUIState(); }); }); document.getElementById('erga-reset-all').addEventListener('click', () => { stopTextToSpeech(); settings = { fontSizeMultiplier: 1.0, fontFamily: 'default', contrast: 'normal', grayscale: false, colorBlindness: 'none', animations: true, cursor: 'default', readingGuide: false, highlightLinks: false, highlightHeadings: false, textSpacing: false, hideImages: false, speechActive: false, lang: settings.lang }; document.querySelectorAll('.erga-profile-btn').forEach(b => b.classList.remove('active')); updateStyles(); updateUIState(); }); updateStyles(); updateUIState(); })();