/* ===========================================
ACCESSIBILITY WIDGET
github.com/sinanisler/accessibility-widgets
github.com/sponsors/sinanisler
=========================================== */
// ===========================================
// TRANSLATIONS
// ===========================================
const TRANSLATIONS = {
en: {
accessibilityMenu: 'Accessibility Menu',
closeAccessibilityMenu: 'Close Accessibility Menu',
accessibilityTools: 'Accessibility Tools',
resetAllSettings: 'Reset All Settings',
screenReader: 'Screen Reader',
voiceCommand: 'Voice Command',
textSpacing: 'Text Spacing',
pauseAnimations: 'Pause Animations',
hideImages: 'Hide Images',
dyslexiaFriendly: 'Dyslexia Friendly',
biggerCursor: 'Bigger Cursor',
lineHeight: 'Line Height',
fontSelection: 'Font Selection',
colorFilter: 'Color Filter',
textAlign: 'Text Align',
textSize: 'Text Size',
highContrast: 'High Contrast',
defaultFont: 'Default Font',
noFilter: 'No Filter',
default: 'Default',
screenReaderOn: 'Screen reader on',
screenReaderOff: 'Screen reader off',
voiceControlActivated: 'Voice control activated',
notSupportedBrowser: 'is not supported in this browser',
close: 'Close',
reset: 'Reset',
saturation: 'Saturation',
selectLanguage: 'Select Language'
},
de: {
accessibilityMenu: 'Barrierefreiheitsmenü',
closeAccessibilityMenu: 'Barrierefreiheitsmenü schließen',
accessibilityTools: 'Barrierefreiheitswerkzeuge',
resetAllSettings: 'Alle Einstellungen zurücksetzen',
screenReader: 'Screenreader',
voiceCommand: 'Sprachbefehl',
textSpacing: 'Textabstand',
pauseAnimations: 'Animationen pausieren',
hideImages: 'Bilder ausblenden',
dyslexiaFriendly: 'Legasthenie-freundlich',
biggerCursor: 'Größerer Cursor',
lineHeight: 'Zeilenhöhe',
fontSelection: 'Schriftauswahl',
colorFilter: 'Farbfilter',
textAlign: 'Textausrichtung',
textSize: 'Textgröße',
highContrast: 'Hoher Kontrast',
defaultFont: 'Standardschrift',
noFilter: 'Kein Filter',
default: 'Standard',
screenReaderOn: 'Screenreader ein',
screenReaderOff: 'Screenreader aus',
voiceControlActivated: 'Sprachsteuerung aktiviert',
notSupportedBrowser: 'wird in diesem Browser nicht unterstützt',
close: 'Schließen',
reset: 'Zurücksetzen',
saturation: 'Sättigung',
selectLanguage: 'Sprache wählen'
},
es: {
accessibilityMenu: 'Menú de Accesibilidad',
closeAccessibilityMenu: 'Cerrar Menú de Accesibilidad',
accessibilityTools: 'Herramientas de Accesibilidad',
resetAllSettings: 'Restablecer Todas las Configuraciones',
screenReader: 'Lector de Pantalla',
voiceCommand: 'Comando de Voz',
textSpacing: 'Espaciado de Texto',
pauseAnimations: 'Pausar Animaciones',
hideImages: 'Ocultar Imágenes',
dyslexiaFriendly: 'Amigable para Dislexia',
biggerCursor: 'Cursor Más Grande',
lineHeight: 'Altura de Línea',
fontSelection: 'Selección de Fuente',
colorFilter: 'Filtro de Color',
textAlign: 'Alineación de Texto',
textSize: 'Tamaño de Texto',
highContrast: 'Alto Contraste',
defaultFont: 'Fuente Predeterminada',
noFilter: 'Sin Filtro',
default: 'Predeterminado',
screenReaderOn: 'Lector de pantalla activado',
screenReaderOff: 'Lector de pantalla desactivado',
voiceControlActivated: 'Control de voz activado',
notSupportedBrowser: 'no es compatible con este navegador',
close: 'Cerrar',
reset: 'Restablecer',
saturation: 'Saturación',
selectLanguage: 'Seleccionar Idioma'
},
it: {
accessibilityMenu: 'Menu Accessibilità',
closeAccessibilityMenu: 'Chiudi Menu Accessibilità',
accessibilityTools: 'Strumenti di Accessibilità',
resetAllSettings: 'Ripristina Tutte le Impostazioni',
screenReader: 'Lettore Schermo',
voiceCommand: 'Comando Vocale',
textSpacing: 'Spaziatura Testo',
pauseAnimations: 'Pausa Animazioni',
hideImages: 'Nascondi Immagini',
dyslexiaFriendly: 'Adatto alla Dislessia',
biggerCursor: 'Cursore Più Grande',
lineHeight: 'Altezza Linea',
fontSelection: 'Selezione Font',
colorFilter: 'Filtro Colore',
textAlign: 'Allineamento Testo',
textSize: 'Dimensione Testo',
highContrast: 'Alto Contrasto',
defaultFont: 'Font Predefinito',
noFilter: 'Nessun Filtro',
default: 'Predefinito',
screenReaderOn: 'Lettore schermo attivo',
screenReaderOff: 'Lettore schermo disattivo',
voiceControlActivated: 'Controllo vocale attivato',
notSupportedBrowser: 'non è supportato in questo browser',
close: 'Chiudi',
reset: 'Ripristina',
saturation: 'Saturazione',
selectLanguage: 'Seleziona Lingua'
},
fr: {
accessibilityMenu: 'Menu Accessibilité',
closeAccessibilityMenu: 'Fermer le Menu Accessibilité',
accessibilityTools: 'Outils d\'Accessibilité',
resetAllSettings: 'Réinitialiser Tous les Paramètres',
screenReader: 'Lecteur d\'Écran',
voiceCommand: 'Commande Vocale',
textSpacing: 'Espacement du Texte',
pauseAnimations: 'Mettre en Pause les Animations',
hideImages: 'Masquer les Images',
dyslexiaFriendly: 'Convivial pour la Dyslexie',
biggerCursor: 'Curseur Plus Grand',
lineHeight: 'Hauteur de Ligne',
fontSelection: 'Sélection de Police',
colorFilter: 'Filtre de Couleur',
textAlign: 'Alignement du Texte',
textSize: 'Taille du Texte',
highContrast: 'Contraste Élevé',
defaultFont: 'Police par Défaut',
noFilter: 'Aucun Filtre',
default: 'Par Défaut',
screenReaderOn: 'Lecteur d\'écran activé',
screenReaderOff: 'Lecteur d\'écran désactivé',
voiceControlActivated: 'Contrôle vocal activé',
notSupportedBrowser: 'n\'est pas pris en charge dans ce navigateur',
close: 'Fermer',
reset: 'Réinitialiser',
saturation: 'Saturation',
selectLanguage: 'Sélectionner la Langue'
},
ru: {
accessibilityMenu: 'Меню Доступности',
closeAccessibilityMenu: 'Закрыть Меню Доступности',
accessibilityTools: 'Инструменты Доступности',
resetAllSettings: 'Сбросить Все Настройки',
screenReader: 'Программа Чтения с Экрана',
voiceCommand: 'Голосовая Команда',
textSpacing: 'Межбуквенный Интервал',
pauseAnimations: 'Приостановить Анимацию',
hideImages: 'Скрыть Изображения',
dyslexiaFriendly: 'Для Дислексии',
biggerCursor: 'Увеличенный Курсор',
lineHeight: 'Высота Строки',
fontSelection: 'Выбор Шрифта',
colorFilter: 'Цветовой Фильтр',
textAlign: 'Выравнивание Текста',
textSize: 'Размер Текста',
highContrast: 'Высокая Контрастность',
defaultFont: 'Шрифт по Умолчанию',
noFilter: 'Без Фильтра',
default: 'По Умолчанию',
screenReaderOn: 'Программа чтения включена',
screenReaderOff: 'Программа чтения выключена',
voiceControlActivated: 'Голосовое управление активировано',
notSupportedBrowser: 'не поддерживается в этом браузере',
close: 'Закрыть',
reset: 'Сбросить',
saturation: 'Насыщенность',
selectLanguage: 'Выберите Язык'
},
tr: {
accessibilityMenu: 'Erişilebilirlik Menüsü',
closeAccessibilityMenu: 'Erişilebilirlik Menüsünü Kapat',
accessibilityTools: 'Erişilebilirlik Araçları',
resetAllSettings: 'Tüm Ayarları Sıfırla',
screenReader: 'Ekran Okuyucu',
voiceCommand: 'Sesli Komut',
textSpacing: 'Metin Aralığı',
pauseAnimations: 'Animasyonları Duraklat',
hideImages: 'Resimleri Gizle',
dyslexiaFriendly: 'Disleksi Dostu',
biggerCursor: 'Daha Büyük İmleç',
lineHeight: 'Satır Yüksekliği',
fontSelection: 'Yazı Tipi Seçimi',
colorFilter: 'Renk Filtresi',
textAlign: 'Metin Hizalama',
textSize: 'Metin Boyutu',
highContrast: 'Yüksek Kontrast',
defaultFont: 'Varsayılan Yazı Tipi',
noFilter: 'Filtre Yok',
default: 'Varsayılan',
screenReaderOn: 'Ekran okuyucu açık',
screenReaderOff: 'Ekran okuyucu kapalı',
voiceControlActivated: 'Sesli kontrol etkinleştirildi',
notSupportedBrowser: 'bu tarayıcıda desteklenmiyor',
close: 'Kapat',
reset: 'Sıfırla',
saturation: 'Doygunluk',
selectLanguage: 'Dil Seçin'
},
ar: {
accessibilityMenu: 'قائمة إمكانية الوصول',
closeAccessibilityMenu: 'إغلاق قائمة إمكانية الوصول',
accessibilityTools: 'أدوات إمكانية الوصول',
resetAllSettings: 'إعادة تعيين جميع الإعدادات',
screenReader: 'قارئ الشاشة',
voiceCommand: 'الأمر الصوتي',
textSpacing: 'تباعد النص',
pauseAnimations: 'إيقاف الرسوم المتحركة مؤقتًا',
hideImages: 'إخفاء الصور',
dyslexiaFriendly: 'صديق لعسر القراءة',
biggerCursor: 'مؤشر أكبر',
lineHeight: 'ارتفاع الخط',
fontSelection: 'اختيار الخط',
colorFilter: 'مرشح الألوان',
textAlign: 'محاذاة النص',
textSize: 'حجم النص',
highContrast: 'تباين عالي',
defaultFont: 'الخط الافتراضي',
noFilter: 'بدون مرشح',
default: 'افتراضي',
screenReaderOn: 'قارئ الشاشة مفعّل',
screenReaderOff: 'قارئ الشاشة معطل',
voiceControlActivated: 'تم تفعيل التحكم الصوتي',
notSupportedBrowser: 'غير مدعوم في هذا المتصفح',
close: 'إغلاق',
reset: 'إعادة تعيين',
saturation: 'التشبع',
selectLanguage: 'اختر اللغة'
},
hi: {
accessibilityMenu: 'पहुँच मेनू',
closeAccessibilityMenu: 'पहुँच मेनू बंद करें',
accessibilityTools: 'पहुँच उपकरण',
resetAllSettings: 'सभी सेटिंग्स रीसेट करें',
screenReader: 'स्क्रीन रीडर',
voiceCommand: 'वॉयस कमांड',
textSpacing: 'टेक्स्ट स्पेसिंग',
pauseAnimations: 'एनिमेशन रोकें',
hideImages: 'चित्र छिपाएँ',
dyslexiaFriendly: 'डिस्लेक्सिया के अनुकूल',
biggerCursor: 'बड़ा कर्सर',
lineHeight: 'लाइन की ऊँचाई',
fontSelection: 'फ़ॉन्ट चयन',
colorFilter: 'रंग फ़िल्टर',
textAlign: 'टेक्स्ट संरेखण',
textSize: 'टेक्स्ट का आकार',
highContrast: 'उच्च कंट्रास्ट',
defaultFont: 'डिफ़ॉल्ट फ़ॉन्ट',
noFilter: 'कोई फ़िल्टर नहीं',
default: 'डिफ़ॉल्ट',
screenReaderOn: 'स्क्रीन रीडर चालू',
screenReaderOff: 'स्क्रीन रीडर बंद',
voiceControlActivated: 'वॉयस नियंत्रण सक्रिय',
notSupportedBrowser: 'इस ब्राउज़र में समर्थित नहीं है',
close: 'बंद करें',
reset: 'रीसेट करें',
saturation: 'संतृप्ति',
selectLanguage: 'भाषा चुनें'
},
'zh-cn': {
accessibilityMenu: '辅助功能菜单',
closeAccessibilityMenu: '关闭辅助功能菜单',
accessibilityTools: '辅助功能工具',
resetAllSettings: '重置所有设置',
screenReader: '屏幕阅读器',
voiceCommand: '语音命令',
textSpacing: '文本间距',
pauseAnimations: '暂停动画',
hideImages: '隐藏图片',
dyslexiaFriendly: '阅读障碍友好',
biggerCursor: '更大的光标',
lineHeight: '行高',
fontSelection: '字体选择',
colorFilter: '颜色滤镜',
textAlign: '文本对齐',
textSize: '文本大小',
highContrast: '高对比度',
defaultFont: '默认字体',
noFilter: '无滤镜',
default: '默认',
screenReaderOn: '屏幕阅读器已开启',
screenReaderOff: '屏幕阅读器已关闭',
voiceControlActivated: '语音控制已激活',
notSupportedBrowser: '此浏览器不支持',
close: '关闭',
reset: '重置',
saturation: '饱和度',
selectLanguage: '选择语言'
},
jp: {
accessibilityMenu: 'アクセシビリティメニュー',
closeAccessibilityMenu: 'アクセシビリティメニューを閉じる',
accessibilityTools: 'アクセシビリティツール',
resetAllSettings: 'すべての設定をリセット',
screenReader: 'スクリーンリーダー',
voiceCommand: '音声コマンド',
textSpacing: 'テキスト間隔',
pauseAnimations: 'アニメーション一時停止',
hideImages: '画像を非表示',
dyslexiaFriendly: 'ディスレクシア対応',
biggerCursor: '大きいカーソル',
lineHeight: '行の高さ',
fontSelection: 'フォント選択',
colorFilter: 'カラーフィルター',
textAlign: 'テキスト配置',
textSize: 'テキストサイズ',
highContrast: 'ハイコントラスト',
defaultFont: 'デフォルトフォント',
noFilter: 'フィルターなし',
default: 'デフォルト',
screenReaderOn: 'スクリーンリーダーがオン',
screenReaderOff: 'スクリーンリーダーがオフ',
voiceControlActivated: '音声制御が有効',
notSupportedBrowser: 'このブラウザではサポートされていません',
close: '閉じる',
reset: 'リセット',
saturation: '彩度',
selectLanguage: '言語を選択'
}
};
// Language detection and management
let currentLanguage = 'en';
function detectBrowserLanguage() {
const browserLang = (navigator.language || navigator.userLanguage).toLowerCase();
// Direct match
if (TRANSLATIONS[browserLang]) {
return browserLang;
}
// Try language code only (e.g., 'en' from 'en-US')
const langCode = browserLang.split('-')[0];
if (TRANSLATIONS[langCode]) {
return langCode;
}
// Special case for Chinese
if (browserLang.includes('zh')) {
if (browserLang.includes('cn') || browserLang.includes('hans')) {
return 'zh-cn';
}
}
// Default to English
return 'en';
}
function setLanguage(lang) {
if (TRANSLATIONS[lang]) {
currentLanguage = lang;
localStorage.setItem('accessibilityWidgetLanguage', lang);
return true;
}
return false;
}
function getTranslation(key) {
return TRANSLATIONS[currentLanguage][key] || TRANSLATIONS['en'][key] || key;
}
// Initialize language from localStorage or detect from browser
const savedLanguage = localStorage.getItem('accessibilityWidgetLanguage');
if (savedLanguage && TRANSLATIONS[savedLanguage]) {
currentLanguage = savedLanguage;
} else {
currentLanguage = detectBrowserLanguage();
localStorage.setItem('accessibilityWidgetLanguage', currentLanguage);
}
// ===========================================
// CONFIGURATION VARIABLES
// ===========================================
// Default configuration - can be overridden by user
const DEFAULT_WIDGET_CONFIG = {
// Core Features
enableHighContrast: true,
enableBiggerText: true,
enableTextSpacing: true, // Now has 3 levels
enablePauseAnimations: true, // Enhanced to include reduced motion features
enableHideImages: true,
enableDyslexiaFont: true,
enableBiggerCursor: true,
enableLineHeight: true, // Now has 3 levels (2em, 3em, 4em)
enableTextAlign: true,
// Advanced Features
enableScreenReader: true,
enableVoiceControl: true,
enableFontSelection: true,
enableColorFilter: true,
// Widget Styling
widgetWidth: '440px',
widgetPosition: {
side: 'right', // 'left' or 'right'
right: '20px',
left: '20px',
bottom: '20px'
},
// Colors
colors: {
primary: '#1663d7', // Header bg, main button bg, active border, close hover bg
secondary: '#ffffff', // Main button icon color
optionBg: '#ffffff', // Option button background
optionText: '#333333', // Option button text color
optionIcon: '#000000' // Option button icon color
},
// Button styling
button: {
size: '55px',
borderRadius: '100px',
iconSize: '40px',
shadow: '0 4px 8px rgba(0, 0, 0, 0.2)'
},
// Menu styling
menu: {
headerHeight: '70px',
padding: '0 10px 10px 10px',
optionPadding: '20px 10px',
optionMargin: '10px',
borderRadius: '8px',
fontSize: '16px',
titleFontSize: '16px',
closeButtonSize: '44px'
},
// Typography
typography: {
fontFamily: 'Arial, sans-serif',
fontSize: '17px',
titleFontSize: '22px',
titleFontWeight: '700',
lineHeight: '1'
},
// Animation
animation: {
transition: '0.2s',
hoverScale: '1.05'
},
// Language/Text Configuration
lang: {
accessibilityMenu: 'Accessibility Menu',
closeAccessibilityMenu: 'Close Accessibility Menu',
accessibilityTools: 'Accessibility Tools',
resetAllSettings: 'Reset All Settings',
screenReader: 'Screen Reader',
voiceCommand: 'Voice Command',
textSpacing: 'Text Spacing',
pauseAnimations: 'Pause Animations',
hideImages: 'Hide Images',
dyslexiaFriendly: 'Dyslexia Friendly',
biggerCursor: 'Bigger Cursor',
lineHeight: 'Line Height',
fontSelection: 'Font Selection',
colorFilter: 'Color Filter',
textAlign: 'Text Align',
textSize: 'Text Size',
highContrast: 'High Contrast',
defaultFont: 'Default Font',
noFilter: 'No Filter',
default: 'Default',
screenReaderOn: 'Screen reader on',
screenReaderOff: 'Screen reader off',
voiceControlActivated: 'Voice control activated',
notSupportedBrowser: 'is not supported in this browser',
close: 'Close',
reset: 'Reset'
},
// Voice Command Configuration - Developers can customize commands for different languages
voiceCommands: {
en: {
showMenu: ['show menu', 'open menu', 'accessibility menu', 'access menu'],
highContrast: ['high contrast', 'contrast', 'dark mode', 'increase contrast'],
biggerText: ['bigger text', 'large text', 'text size', 'increase text', 'bigger', 'larger text', 'text bigger', 'make text bigger', 'enlarge text'],
textSpacing: ['text spacing', 'spacing', 'letter spacing', 'text space'],
pauseAnimations: ['pause animations', 'stop animations', 'disable animations', 'no animations'],
hideImages: ['hide images', 'remove images', 'no images'],
dyslexiaFont: ['dyslexia friendly', 'dyslexia font', 'readable font', 'easy font'],
biggerCursor: ['bigger cursor', 'large cursor', 'cursor size', 'big cursor'],
lineHeight: ['line height', 'line spacing', 'space between lines', 'line space'],
textAlign: ['align text', 'text align', 'center text', 'alignment'],
screenReader: ['screen reader', 'read aloud', 'voice reader'],
voiceControl: ['voice command', 'voice control', 'voice commands'],
resetAll: ['reset all', 'reset everything', 'clear all', 'reset settings', 'reset']
},
de: {
showMenu: ['menü anzeigen', 'menü öffnen', 'barrierefreiheitsmenü', 'zugangsmenü'],
highContrast: ['hoher kontrast', 'kontrast', 'dunkler modus', 'kontrast erhöhen'],
biggerText: ['größerer text', 'großer text', 'textgröße', 'text vergrößern', 'größer', 'text größer'],
textSpacing: ['textabstand', 'abstand', 'buchstabenabstand', 'text abstand'],
pauseAnimations: ['animationen pausieren', 'animationen stoppen', 'animationen deaktivieren'],
hideImages: ['bilder ausblenden', 'bilder entfernen', 'keine bilder'],
dyslexiaFont: ['legasthenie freundlich', 'legasthenie schrift', 'lesbare schrift'],
biggerCursor: ['größerer cursor', 'großer cursor', 'cursor größe'],
lineHeight: ['zeilenhöhe', 'zeilenabstand', 'abstand zwischen zeilen'],
textAlign: ['text ausrichten', 'textausrichtung', 'text zentrieren'],
screenReader: ['screenreader', 'vorlesen', 'sprach reader'],
voiceControl: ['sprachbefehl', 'sprachsteuerung', 'sprachbefehle'],
resetAll: ['alles zurücksetzen', 'alle zurücksetzen', 'alle löschen', 'einstellungen zurücksetzen']
},
es: {
showMenu: ['mostrar menú', 'abrir menú', 'menú de accesibilidad', 'menú de acceso'],
highContrast: ['alto contraste', 'contraste', 'modo oscuro', 'aumentar contraste'],
biggerText: ['texto más grande', 'texto grande', 'tamaño de texto', 'aumentar texto', 'más grande'],
textSpacing: ['espaciado de texto', 'espaciado', 'espaciado de letras', 'espacio de texto'],
pauseAnimations: ['pausar animaciones', 'detener animaciones', 'desactivar animaciones'],
hideImages: ['ocultar imágenes', 'quitar imágenes', 'sin imágenes'],
dyslexiaFont: ['amigable para dislexia', 'fuente de dislexia', 'fuente legible'],
biggerCursor: ['cursor más grande', 'cursor grande', 'tamaño de cursor'],
lineHeight: ['altura de línea', 'espaciado de líneas', 'espacio entre líneas'],
textAlign: ['alinear texto', 'alineación de texto', 'centrar texto'],
screenReader: ['lector de pantalla', 'leer en voz alta', 'lector de voz'],
voiceControl: ['comando de voz', 'control de voz', 'comandos de voz'],
resetAll: ['restablecer todo', 'restablecer todo', 'borrar todo', 'restablecer configuración']
},
it: {
showMenu: ['mostra menu', 'apri menu', 'menu accessibilità', 'menu accesso'],
highContrast: ['alto contrasto', 'contrasto', 'modalità scura', 'aumenta contrasto'],
biggerText: ['testo più grande', 'testo grande', 'dimensione testo', 'aumenta testo', 'più grande'],
textSpacing: ['spaziatura testo', 'spaziatura', 'spaziatura lettere', 'spazio testo'],
pauseAnimations: ['pausa animazioni', 'ferma animazioni', 'disabilita animazioni'],
hideImages: ['nascondi immagini', 'rimuovi immagini', 'nessuna immagine'],
dyslexiaFont: ['adatto alla dislessia', 'font dislessia', 'font leggibile'],
biggerCursor: ['cursore più grande', 'cursore grande', 'dimensione cursore'],
lineHeight: ['altezza linea', 'spaziatura linee', 'spazio tra linee'],
textAlign: ['allinea testo', 'allineamento testo', 'centra testo'],
screenReader: ['lettore schermo', 'leggi ad alta voce', 'lettore vocale'],
voiceControl: ['comando vocale', 'controllo vocale', 'comandi vocali'],
resetAll: ['ripristina tutto', 'ripristina tutto', 'cancella tutto', 'ripristina impostazioni']
},
fr: {
showMenu: ['afficher menu', 'ouvrir menu', 'menu accessibilité', 'menu accès'],
highContrast: ['contraste élevé', 'contraste', 'mode sombre', 'augmenter contraste'],
biggerText: ['texte plus grand', 'grand texte', 'taille texte', 'augmenter texte', 'plus grand'],
textSpacing: ['espacement texte', 'espacement', 'espacement lettres', 'espace texte'],
pauseAnimations: ['mettre en pause animations', 'arrêter animations', 'désactiver animations'],
hideImages: ['masquer images', 'supprimer images', 'aucune image'],
dyslexiaFont: ['convivial dyslexie', 'police dyslexie', 'police lisible'],
biggerCursor: ['curseur plus grand', 'grand curseur', 'taille curseur'],
lineHeight: ['hauteur ligne', 'espacement lignes', 'espace entre lignes'],
textAlign: ['aligner texte', 'alignement texte', 'centrer texte'],
screenReader: ['lecteur écran', 'lire à haute voix', 'lecteur vocal'],
voiceControl: ['commande vocale', 'contrôle vocal', 'commandes vocales'],
resetAll: ['réinitialiser tout', 'réinitialiser tout', 'effacer tout', 'réinitialiser paramètres']
},
ru: {
showMenu: ['показать меню', 'открыть меню', 'меню доступности', 'меню доступа'],
highContrast: ['высокая контрастность', 'контрастность', 'темный режим', 'увеличить контрастность'],
biggerText: ['больший текст', 'большой текст', 'размер текста', 'увеличить текст', 'больше'],
textSpacing: ['межбуквенный интервал', 'интервал', 'интервал букв', 'пространство текста'],
pauseAnimations: ['приостановить анимацию', 'остановить анимацию', 'отключить анимацию'],
hideImages: ['скрыть изображения', 'убрать изображения', 'без изображений'],
dyslexiaFont: ['для дислексии', 'шрифт дислексии', 'читаемый шрифт'],
biggerCursor: ['увеличенный курсор', 'большой курсор', 'размер курсора'],
lineHeight: ['высота строки', 'интервал строк', 'пространство между строками'],
textAlign: ['выровнять текст', 'выравнивание текста', 'центрировать текст'],
screenReader: ['программа чтения', 'читать вслух', 'голосовой ридер'],
voiceControl: ['голосовая команда', 'голосовое управление', 'голосовые команды'],
resetAll: ['сбросить все', 'сбросить всё', 'очистить все', 'сбросить настройки']
},
tr: {
showMenu: ['menüyü göster', 'menü aç', 'erişilebilirlik menüsü', 'erişim menüsü'],
highContrast: ['yüksek kontrast', 'kontrast', 'karanlık mod', 'kontrastı artır'],
biggerText: ['daha büyük metin', 'büyük metin', 'metin boyutu', 'metni büyüt', 'daha büyük'],
textSpacing: ['metin aralığı', 'aralık', 'harf aralığı', 'metin boşluğu'],
pauseAnimations: ['animasyonları duraklat', 'animasyonları durdur', 'animasyonları kapat'],
hideImages: ['resimleri gizle', 'resimleri kaldır', 'resim yok'],
dyslexiaFont: ['disleksi dostu', 'disleksi yazı tipi', 'okunabilir yazı tipi'],
biggerCursor: ['daha büyük imleç', 'büyük imleç', 'imleç boyutu'],
lineHeight: ['satır yüksekliği', 'satır aralığı', 'satırlar arası boşluk'],
textAlign: ['metni hizala', 'metin hizalama', 'metni ortala'],
screenReader: ['ekran okuyucu', 'sesli oku', 'ses okuyucu'],
voiceControl: ['sesli komut', 'sesli kontrol', 'sesli komutlar'],
resetAll: ['hepsini sıfırla', 'tümünü sıfırla', 'hepsini temizle', 'ayarları sıfırla']
},
ar: {
showMenu: ['إظهار القائمة', 'فتح القائمة', 'قائمة إمكانية الوصول', 'قائمة الوصول'],
highContrast: ['تباين عالي', 'تباين', 'الوضع المظلم', 'زيادة التباين'],
biggerText: ['نص أكبر', 'نص كبير', 'حجم النص', 'تكبير النص', 'أكبر'],
textSpacing: ['تباعد النص', 'تباعد', 'تباعد الحروف', 'مساحة النص'],
pauseAnimations: ['إيقاف الرسوم المتحركة مؤقتا', 'إيقاف الرسوم المتحركة', 'تعطيل الرسوم المتحركة'],
hideImages: ['إخفاء الصور', 'إزالة الصور', 'بدون صور'],
dyslexiaFont: ['صديق لعسر القراءة', 'خط عسر القراءة', 'خط قابل للقراءة'],
biggerCursor: ['مؤشر أكبر', 'مؤشر كبير', 'حجم المؤشر'],
lineHeight: ['ارتفاع الخط', 'تباعد الأسطر', 'مساحة بين الأسطر'],
textAlign: ['محاذاة النص', 'محاذاة النص', 'توسيط النص'],
screenReader: ['قارئ الشاشة', 'اقرأ بصوت عالٍ', 'قارئ صوتي'],
voiceControl: ['الأمر الصوتي', 'التحكم الصوتي', 'الأوامر الصوتية'],
resetAll: ['إعادة تعيين الكل', 'إعادة تعيين جميع', 'مسح الكل', 'إعادة تعيين الإعدادات']
},
hi: {
showMenu: ['मेनू दिखाएं', 'मेनू खोलें', 'पहुंच मेनू', 'एक्सेस मेनू'],
highContrast: ['उच्च कंट्रास्ट', 'कंट्रास्ट', 'डार्क मोड', 'कंट्रास्ट बढ़ाएं'],
biggerText: ['बड़ा टेक्स्ट', 'बड़ा टेक्स्ट', 'टेक्स्ट का आकार', 'टेक्स्ट बढ़ाएं', 'बड़ा'],
textSpacing: ['टेक्स्ट स्पेसिंग', 'स्पेसिंग', 'अक्षर स्पेसिंग', 'टेक्स्ट स्पेस'],
pauseAnimations: ['एनिमेशन रोकें', 'एनिमेशन बंद करें', 'एनिमेशन अक्षम करें'],
hideImages: ['चित्र छिपाएं', 'चित्र हटाएं', 'कोई चित्र नहीं'],
dyslexiaFont: ['डिस्लेक्सिया के अनुकूल', 'डिस्लेक्सिया फ़ॉन्ट', 'पढ़ने योग्य फ़ॉन्ट'],
biggerCursor: ['बड़ा कर्सर', 'बड़ा कर्सर', 'कर्सर का आकार'],
lineHeight: ['लाइन की ऊंचाई', 'लाइन स्पेसिंग', 'लाइनों के बीच स्पेस'],
textAlign: ['टेक्स्ट अलाइन करें', 'टेक्स्ट संरेखण', 'टेक्स्ट केंद्र में करें'],
screenReader: ['स्क्रीन रीडर', 'जोर से पढ़ें', 'वॉयस रीडर'],
voiceControl: ['वॉयस कमांड', 'वॉयस नियंत्रण', 'वॉयस कमांड्स'],
resetAll: ['सभी रीसेट करें', 'सब कुछ रीसेट करें', 'सब साफ़ करें', 'सेटिंग्स रीसेट करें']
},
'zh-cn': {
showMenu: ['显示菜单', '打开菜单', '辅助功能菜单', '访问菜单'],
highContrast: ['高对比度', '对比度', '暗模式', '增加对比度'],
biggerText: ['更大的文本', '大文本', '文本大小', '增大文本', '更大'],
textSpacing: ['文本间距', '间距', '字母间距', '文本空间'],
pauseAnimations: ['暂停动画', '停止动画', '禁用动画'],
hideImages: ['隐藏图片', '删除图片', '无图片'],
dyslexiaFont: ['阅读障碍友好', '阅读障碍字体', '可读字体'],
biggerCursor: ['更大的光标', '大光标', '光标大小'],
lineHeight: ['行高', '行间距', '行之间的空间'],
textAlign: ['对齐文本', '文本对齐', '居中文本'],
screenReader: ['屏幕阅读器', '大声朗读', '语音阅读器'],
voiceControl: ['语音命令', '语音控制', '语音命令'],
resetAll: ['重置全部', '重置所有', '清除全部', '重置设置']
},
jp: {
showMenu: ['メニューを表示', 'メニューを開く', 'アクセシビリティメニュー', 'アクセスメニュー'],
highContrast: ['ハイコントラスト', 'コントラスト', 'ダークモード', 'コントラストを上げる'],
biggerText: ['大きいテキスト', '大きなテキスト', 'テキストサイズ', 'テキストを大きく', 'より大きい'],
textSpacing: ['テキスト間隔', '間隔', '文字間隔', 'テキストスペース'],
pauseAnimations: ['アニメーション一時停止', 'アニメーション停止', 'アニメーション無効'],
hideImages: ['画像を非表示', '画像を削除', '画像なし'],
dyslexiaFont: ['ディスレクシア対応', 'ディスレクシアフォント', '読みやすいフォント'],
biggerCursor: ['大きいカーソル', '大きなカーソル', 'カーソルサイズ'],
lineHeight: ['行の高さ', '行間隔', '行間のスペース'],
textAlign: ['テキスト配置', 'テキスト配置', 'テキストを中央'],
screenReader: ['スクリーンリーダー', '音声で読む', '音声リーダー'],
voiceControl: ['音声コマンド', '音声制御', '音声コマンド'],
resetAll: ['すべてリセット', 'すべてリセット', 'すべてクリア', '設定をリセット']
}
},
// Grid Layout Configuration
gridLayout: {
columns: '1fr 1fr', // Default 2-column layout
gap: '10px' // Gap between grid items
}
};
// Function to deep merge user configuration with defaults
function mergeConfigs(defaultConfig, userConfig) {
const result = { ...defaultConfig };
if (!userConfig) return result;
for (const key in userConfig) {
if (userConfig.hasOwnProperty(key)) {
if (typeof userConfig[key] === 'object' && userConfig[key] !== null && !Array.isArray(userConfig[key])) {
result[key] = mergeConfigs(defaultConfig[key] || {}, userConfig[key]);
} else {
result[key] = userConfig[key];
}
}
}
return result;
}
// Merge user configuration with defaults
const WIDGET_CONFIG = mergeConfigs(DEFAULT_WIDGET_CONFIG, window.ACCESSIBILITY_WIDGET_CONFIG || {});
// ===========================================
// STYLES & VISUAL ASSETS
// ===========================================
// Widget styles (will go inside Shadow DOM - NOT affected by page styles or accessibility features)
const widgetStyles = `
:host {
all: initial;
font-family: ${WIDGET_CONFIG.typography.fontFamily};
}
* {
box-sizing: border-box;
}
#snn-accessibility-fixed-button {
position: fixed !important;
${WIDGET_CONFIG.widgetPosition.side}: ${WIDGET_CONFIG.widgetPosition[WIDGET_CONFIG.widgetPosition.side]} !important;
bottom: ${WIDGET_CONFIG.widgetPosition.bottom} !important;
z-index: 9999;
background:${WIDGET_CONFIG.colors.primary};
padding:5px;
border-radius:100%;
}
#snn-accessibility-button {
background: ${WIDGET_CONFIG.colors.primary};
border: none;
border-radius: ${WIDGET_CONFIG.button.borderRadius};
cursor: pointer;
width: ${WIDGET_CONFIG.button.size};
height: ${WIDGET_CONFIG.button.size};
box-shadow: ${WIDGET_CONFIG.button.shadow};
transition: ${WIDGET_CONFIG.animation.transition} !important;
display: flex;
justify-content: center;
align-items: center;
border:solid 4px white;
}
#snn-accessibility-button:hover {
transform: scale(${WIDGET_CONFIG.animation.hoverScale});
}
#snn-accessibility-button:focus {
outline: 2px solid ${WIDGET_CONFIG.colors.secondary};
outline-offset: 2px;
}
#snn-accessibility-button svg {
width: ${WIDGET_CONFIG.button.iconSize};
height: ${WIDGET_CONFIG.button.iconSize};
fill: ${WIDGET_CONFIG.colors.secondary};
pointer-events: none;
}
#snn-accessibility-menu {
position: fixed;
top: 0;
${WIDGET_CONFIG.widgetPosition.side}: 0;
max-width: ${WIDGET_CONFIG.widgetWidth};
width:100%;
height: 100vh;
overflow-y: auto;
background-color: #e2e2e2;
padding: 0;
display: none;
font-family: ${WIDGET_CONFIG.typography.fontFamily};
z-index: 999999;
scrollbar-width: thin;
line-height:1 !important;
}
.snn-accessibility-option {
font-size: ${WIDGET_CONFIG.menu.fontSize};
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
padding: 5px;
width: 100%;
background-color: ${WIDGET_CONFIG.colors.optionBg};
color: ${WIDGET_CONFIG.colors.optionText};
border: 3px solid ${WIDGET_CONFIG.colors.optionBg};
cursor: pointer;
border-radius: ${WIDGET_CONFIG.menu.borderRadius};
transition: background-color ${WIDGET_CONFIG.animation.transition}, border-color ${WIDGET_CONFIG.animation.transition};
line-height: ${WIDGET_CONFIG.typography.lineHeight} !important;
gap: 5px;
min-height: 105px;
}
.snn-accessibility-option:hover {
border-color: ${WIDGET_CONFIG.colors.primary};
}
.snn-accessibility-option.active {
border-color: ${WIDGET_CONFIG.colors.primary};
}
.snn-accessibility-option:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.snn-icon {
width: ${WIDGET_CONFIG.button.iconSize};
height: ${WIDGET_CONFIG.button.iconSize};
fill: ${WIDGET_CONFIG.colors.optionIcon};
flex-shrink: 0;
}
.snn-icon svg {
width: 100%;
height: 100%;
fill: currentColor;
}
.snn-button-text {
text-align: center;
line-height: 1.2;
font-size:16px;
font-weight: 600;
}
.snn-option-steps {
display: flex;
gap: 5px;
align-items: center;
justify-content: center;
margin-top: 5px;
}
.snn-option-step {
width: 30px;
height: 6px;
border-radius: 3px;
background-color: #d0d0d0;
transition: background-color ${WIDGET_CONFIG.animation.transition};
}
.snn-option-step.active {
background-color: ${WIDGET_CONFIG.colors.primary};
}
.snn-close, .snn-reset-button {
background: none;
border: none;
font-size: ${WIDGET_CONFIG.menu.closeButtonSize};
color: ${WIDGET_CONFIG.colors.secondary};
cursor: pointer;
line-height: ${WIDGET_CONFIG.typography.lineHeight};
border-radius: ${WIDGET_CONFIG.button.borderRadius};
width: ${WIDGET_CONFIG.menu.closeButtonSize};
height: ${WIDGET_CONFIG.menu.closeButtonSize};
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.snn-close::before {
content: '×';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: ${WIDGET_CONFIG.menu.closeButtonSize};
line-height: 1;
}
.snn-reset-button svg {
width: 22px;
height: 22px;
fill: ${WIDGET_CONFIG.colors.secondary};
}
.snn-close:focus, .snn-reset-button:focus {
outline: solid 2px ${WIDGET_CONFIG.colors.secondary};
}
.snn-close:hover, .snn-reset-button:hover {
color: ${WIDGET_CONFIG.colors.secondary};
background: rgba(255, 255, 255, 0.2);
}
/* Tooltip styles */
.snn-tooltip {
position: absolute;
bottom: -35px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.8);
color: white;
padding: 6px 10px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
z-index: 1000;
}
.snn-tooltip::before {
content: '';
position: absolute;
top: -4px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid rgba(0, 0, 0, 0.8);
}
.snn-close:hover .snn-tooltip,
.snn-close:focus .snn-tooltip,
.snn-reset-button:hover .snn-tooltip,
.snn-reset-button:focus .snn-tooltip {
opacity: 1;
}
.snn-header {
display: flex;
align-items: center;
padding: 10px;
background: ${WIDGET_CONFIG.colors.primary};
height: ${WIDGET_CONFIG.menu.headerHeight};
position: sticky;
top: 0;
z-index: 10;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
gap: 8px;
}
.snn-content {
padding: 20px 20px 0px 20px;
}
.snn-language-selector {
width: 100%;
background: white;
color: black;
border: none;
padding: 14px;
font-size: 16px;
font-family: ${WIDGET_CONFIG.typography.fontFamily};
border-radius: 5px;
margin-bottom: 20px;
cursor: pointer;
outline: none;
}
.snn-language-selector:focus {
outline: 2px solid ${WIDGET_CONFIG.colors.primary};
outline-offset: 2px;
}
.snn-options-grid {
display: grid;
grid-template-columns: ${WIDGET_CONFIG.gridLayout.columns};
gap: ${WIDGET_CONFIG.gridLayout.gap};
margin-bottom: 20px;
}
.snn-title {
margin: 0;
font-size: ${WIDGET_CONFIG.menu.titleFontSize};
color: ${WIDGET_CONFIG.colors.secondary};
line-height: ${WIDGET_CONFIG.typography.lineHeight} !important;
margin-left: 5px;
font-weight: ${WIDGET_CONFIG.typography.titleFontWeight};
flex: 1;
letter-spacing: 1px !important;
word-spacing: 2px !important;
text-align: left;
}
`;
// Page accessibility styles (will go in main document - these affect the page, NOT the widget)
const pageStyles = `
/* High Contrast Modes */
.snn-high-contrast-medium {
filter: none !important;
}
.snn-high-contrast-medium *:not(#snn-accessibility-widget-container):not(#snn-accessibility-widget-container *) {
filter: contrast(1.3) !important;
}
.snn-high-contrast-high {
background-color: #000 !important;
color: #fff !important;
filter: none !important;
}
.snn-high-contrast-high *:not(#snn-accessibility-widget-container):not(#snn-accessibility-widget-container *) {
background-color: #000 !important;
color: #fff !important;
filter: contrast(1.5) !important;
}
.snn-high-contrast-ultra {
background-color: #000 !important;
color: #ffff00 !important;
filter: none !important;
}
.snn-high-contrast-ultra *:not(#snn-accessibility-widget-container):not(#snn-accessibility-widget-container *) {
background-color: #000 !important;
color: #ffff00 !important;
filter: contrast(2.0) !important;
}
/* Text Size */
.snn-bigger-text-medium * {
font-size: 20px !important;
}
.snn-bigger-text-large * {
font-size: 24px !important;
}
.snn-bigger-text-xlarge * {
font-size: 28px !important;
}
/* Text Spacing - 3 Options */
.snn-text-spacing-light * {
letter-spacing: 0.1em !important;
word-spacing: 0.5em !important;
}
.snn-text-spacing-medium * {
letter-spacing: 0.15em !important;
word-spacing: 1em !important;
}
.snn-text-spacing-heavy * {
letter-spacing: 0.25em !important;
word-spacing: 2em !important;
}
/* Pause Animations (Enhanced to include Reduced Motion features) */
.snn-pause-animations * {
animation: none !important;
transition: none !important;
}
.snn-pause-animations *::before {
animation: none !important;
transition: none !important;
}
.snn-pause-animations *::after {
animation: none !important;
transition: none !important;
}
/* Dyslexia Font */
.snn-dyslexia-font {
font-family: 'Comic Sans MS', 'Chalkboard SE', 'Bradley Hand', 'Brush Script MT', fantasy !important;
}
.snn-dyslexia-font * {
font-family: 'Comic Sans MS', 'Chalkboard SE', 'Bradley Hand', 'Brush Script MT', fantasy !important;
}
/* Line Height - 3 Options */
.snn-line-height-2em * {
line-height: 2 !important;
}
.snn-line-height-3em * {
line-height: 3 !important;
}
.snn-line-height-4em * {
line-height: 4 !important;
}
/* Text Alignment */
.snn-text-align-left * {
text-align: left !important;
}
.snn-text-align-center * {
text-align: center !important;
}
.snn-text-align-right * {
text-align: right !important;
}
/* Bigger Cursor */
.snn-bigger-cursor {
cursor: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNzIiIHZpZXdCb3g9IjAgMCA0OCA3MiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNCAyVjcwTDIwIDU0SDM2TDQgMloiIGZpbGw9IiMwMDAiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSI0Ii8+PC9zdmc+'), auto !important;
}
.snn-bigger-cursor * {
cursor: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNzIiIHZpZXdCb3g9IjAgMCA0OCA3MiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNCAyVjcwTDIwIDU0SDM2TDQgMloiIGZpbGw9IiMwMDAiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSI0Ii8+PC9zdmc+'), auto !important;
}
/* Font Selection */
.snn-font-arial {
font-family: Arial, sans-serif !important;
}
.snn-font-arial * {
font-family: Arial, sans-serif !important;
}
.snn-font-times {
font-family: 'Times New Roman', serif !important;
}
.snn-font-times * {
font-family: 'Times New Roman', serif !important;
}
.snn-font-verdana {
font-family: Verdana, sans-serif !important;
}
.snn-font-verdana * {
font-family: Verdana, sans-serif !important;
}
/* Color Filters */
.snn-filter-protanopia {
filter: none !important;
}
.snn-filter-protanopia body > *:not(#snn-accessibility-widget-container) {
filter: url('#protanopia-filter') !important;
}
.snn-filter-deuteranopia {
filter: none !important;
}
.snn-filter-deuteranopia body > *:not(#snn-accessibility-widget-container) {
filter: url('#deuteranopia-filter') !important;
}
.snn-filter-tritanopia {
filter: none !important;
}
.snn-filter-tritanopia body > *:not(#snn-accessibility-widget-container) {
filter: url('#tritanopia-filter') !important;
}
.snn-filter-grayscale {
filter: none !important;
}
.snn-filter-grayscale body > *:not(#snn-accessibility-widget-container) {
filter: grayscale(100%) !important;
}
/* Saturation Filters */
.snn-saturation-low {
filter: none !important;
}
.snn-saturation-low body > *:not(#snn-accessibility-widget-container) {
filter: saturate(0.5) !important;
}
.snn-saturation-high {
filter: none !important;
}
.snn-saturation-high body > *:not(#snn-accessibility-widget-container) {
filter: saturate(10) !important;
}
.snn-saturation-none {
filter: none !important;
}
.snn-saturation-none body > *:not(#snn-accessibility-widget-container) {
filter: grayscale(100%) saturate(0) !important;
}
/* Protect widget container from page styles */
#snn-accessibility-widget-container,
#snn-accessibility-widget-container * {
filter: none !important;
background-color: initial !important;
color: initial !important;
}
`;
// ===========================================
// SVG ICONS
// ===========================================
const icons = {
buttonsvg: ``,
highContrast: ``,
biggerText: ``,
textSpacing: ``,
pauseAnimations: ``,
hideImages: ``,
dyslexiaFont: ``,
biggerCursor: ``,
lineHeight: ``,
textAlign: ``,
screenReader: ``,
resetAll: ``,
voiceControl: ``,
fontSelection: ``,
colorFilter: ``,
saturation: ``,
reducedMotion: ``,
};
// ===========================================
// SHADOW DOM SETUP
// ===========================================
let shadowRoot = null;
// Inject styles into the page (NOT the widget)
function injectPageStyles() {
const styleSheet = document.createElement('style');
styleSheet.innerText = pageStyles;
styleSheet.id = 'snn-accessibility-page-styles';
document.head.appendChild(styleSheet);
// Add SVG color blindness filters to main document
const svgFilters = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svgFilters.style.position = 'absolute';
svgFilters.style.width = '0';
svgFilters.setAttribute('class', 'snn-accessibility-filters');
svgFilters.style.height = '0';
svgFilters.innerHTML = `