// accessibility-widget.js (function() { 'use strict'; // Проверяем, не добавлен ли уже виджет if (window.accessibilityWidgetLoaded) return; window.accessibilityWidgetLoaded = true; // Получаем base URL автоматически const scriptSrc = document.currentScript?.src; const baseUrl = scriptSrc ? scriptSrc.substring(0, scriptSrc.lastIndexOf('/') + 1) : ''; // Создаем элементы виджета const widgetHTML = `
`; // Создаем стили с динамическим URL const widgetCSS = ` `; // Вставляем HTML и CSS в документ document.body.insertAdjacentHTML('beforeend', widgetHTML); document.head.insertAdjacentHTML('beforeend', widgetCSS); // Запускаем функциональность виджета после загрузки DOM if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initAccessibilityWidget); } else { initAccessibilityWidget(); } function initAccessibilityWidget() { // Language translations const translations = { en: { panelTitle: "Accessibility Settings", textSizeTitle: "Text Size", contrastTitle: "Color & Contrast", readingTitle: "Reading", languageTitle: "Language", textIncrease: "Increase Text (+)", textNormal: "Normal Text", textDecrease: "Decrease Text (-)", contrastDark: "Dark Contrast", contrastLight: "Light Contrast", contrastMono: "Monochrome", contrastReset: "Reset Colors", dyslexiaFontDyslexic: "Dyslexic Font", dyslexiaFontComic: "Comic Sans Font", dyslexiaFontNormal: "Normal Font", highlightLinks: "Highlight Links", bigCursor: "Big Cursor", resetAll: "Reset All Settings", close: "Close", toggleLabel: "Accessibility Settings" }, he: { panelTitle: "הגדרות נגישות", textSizeTitle: "גודל טקסט", contrastTitle: "צבע וניגודיות", readingTitle: "קריאה", languageTitle: "שפה", textIncrease: "הגדל טקסט (+)", textNormal: "גודל רגיל", textDecrease: "הקטן טקסט (-)", contrastDark: "ניגודיות כהה", contrastLight: "ניגודיות בהירה", contrastMono: "מונוכרום", contrastReset: "איפוס צבעים", dyslexiaFontDyslexic: "גופן דיסלקטי", dyslexiaFontComic: "גופן Comic Sans", dyslexiaFontNormal: "גופן רגיל", highlightLinks: "הדגש קישורים", bigCursor: "סמן גדול", resetAll: "אפס כל ההגדרות", close: "סגור", toggleLabel: "הגדרות נגישות" }, ru: { panelTitle: "Настройки доступности", textSizeTitle: "Размер текста", contrastTitle: "Цвет и контраст", readingTitle: "Чтение", languageTitle: "Язык", textIncrease: "Увеличить текст (+)", textNormal: "Обычный текст", textDecrease: "Уменьшить текст (-)", contrastDark: "Темный контраст", contrastLight: "Светлый контраст", contrastMono: "Монохромный", contrastReset: "Сбросить цвета", dyslexiaFontDyslexic: "Дислексический шрифт", dyslexiaFontComic: "Шрифт Comic Sans", dyslexiaFontNormal: "Обычный шрифт", highlightLinks: "Подчеркнуть ссылки", bigCursor: "Большой курсор", resetAll: "Сбросить все настройки", close: "Закрыть", toggleLabel: "Настройки доступности" } }; const toggleBtn = document.getElementById('accessibilityToggle'); const panel = document.getElementById('accessibilityPanel'); const closeBtn = document.getElementById('closePanel'); const overlay = document.getElementById('accessibilityOverlay'); if (!toggleBtn || !panel || !closeBtn || !overlay) return; // ARIA live region for announcements const live = document.createElement('div'); live.setAttribute('aria-live', 'polite'); live.className = 'sr-only'; document.body.appendChild(live); function announce(msg) { live.textContent = ''; setTimeout(() => live.textContent = msg, 50); } // Apply translations function applyTranslations(lang) { const trans = translations[lang]; if (!trans) return; const elements = { 'panelTitle': trans.panelTitle, 'textSizeTitle': trans.textSizeTitle, 'contrastTitle': trans.contrastTitle, 'readingTitle': trans.readingTitle, 'languageTitle': trans.languageTitle, 'textIncrease': trans.textIncrease, 'textNormal': trans.textNormal, 'textDecrease': trans.textDecrease, 'contrastDark': trans.contrastDark, 'contrastLight': trans.contrastLight, 'contrastMono': trans.contrastMono, 'contrastReset': trans.contrastReset, 'dyslexiaFontDyslexic': trans.dyslexiaFontDyslexic, 'dyslexiaFontComic': trans.dyslexiaFontComic, 'dyslexiaFontNormal': trans.dyslexiaFontNormal, 'highlightLinks': trans.highlightLinks, 'bigCursor': trans.bigCursor, 'resetAll': trans.resetAll }; for (const [id, text] of Object.entries(elements)) { const element = document.getElementById(id); if (element) element.textContent = text; } if (closeBtn) closeBtn.setAttribute('aria-label', trans.close); if (toggleBtn) toggleBtn.setAttribute('aria-label', trans.toggleLabel); // Set direction for RTL languages if (lang === 'he') { panel.setAttribute('dir', 'rtl'); } else { panel.setAttribute('dir', 'ltr'); } } // Set active language button function setActiveLanguage(lang) { document.querySelectorAll('.language-btn').forEach(btn => { btn.classList.remove('active'); if (btn.dataset.lang === lang) { btn.classList.add('active'); } }); } // Toggle panel function togglePanel() { const isHidden = panel.getAttribute('aria-hidden') === 'true'; panel.setAttribute('aria-hidden', !isHidden); overlay.style.display = isHidden ? 'block' : 'none'; if (isHidden) { panel.focus(); } } // Close panel function closePanel() { panel.setAttribute('aria-hidden', 'true'); overlay.style.display = 'none'; } // Event listeners toggleBtn.addEventListener('click', togglePanel); closeBtn.addEventListener('click', closePanel); overlay.addEventListener('click', closePanel); // Keyboard navigation toggleBtn.addEventListener('keypress', function(e) { if (e.key === 'Enter' || e.key === ' ') { togglePanel(); } }); // Language selection document.querySelectorAll('.language-btn').forEach(btn => { btn.addEventListener('click', function() { const lang = this.dataset.lang; applyTranslations(lang); setActiveLanguage(lang); localStorage.setItem('accessibilityLanguage', lang); announce(`Language changed to ${lang}`); }); }); // Handle accessibility actions panel.addEventListener('click', function(e) { if (e.target.tagName === 'BUTTON' && e.target !== closeBtn) { const action = e.target.dataset.action; const value = e.target.dataset.value; const font = e.target.dataset.font; switch(action) { case 'font-size': changeFontSize(value); break; case 'contrast': changeContrast(value); break; case 'dyslexia-font': changeDyslexiaFont(font); break; case 'highlight-links': toggleClass('accessibility-highlight-links', 'userHighlightLinks'); break; case 'big-cursor': toggleClass('accessibility-big-cursor', 'userBigCursor'); break; case 'reset': resetAll(); break; } } }); // Accessibility functions function changeFontSize(value) { const html = document.documentElement; let currentSize = parseFloat(getComputedStyle(html).fontSize) || 16; const step = 2; if (value === '1') currentSize += step; else if (value === '-1') currentSize -= step; else currentSize = 16; html.style.fontSize = currentSize + 'px'; localStorage.setItem('userFontSize', currentSize); announce(`Font size changed to ${currentSize}px`); } function changeContrast(mode) { const body = document.body; body.classList.remove('accessibility-contrast-dark', 'accessibility-contrast-light', 'accessibility-monochrome'); if (mode !== 'reset') { body.classList.add('accessibility-' + (mode === 'monochrome' ? 'monochrome' : 'contrast-' + mode)); } localStorage.setItem('userContrast', mode); announce(`Contrast mode: ${mode}`); } function changeDyslexiaFont(fontType) { document.body.classList.remove('accessibility-dyslexic', 'accessibility-comicsans', 'accessibility-normal-font'); document.querySelectorAll('[data-action="dyslexia-font"]').forEach(btn => { btn.classList.remove('active-font'); }); if (fontType !== 'normal') { document.body.classList.add('accessibility-' + fontType); const activeBtn = document.querySelector(`[data-font="${fontType}"]`); if (activeBtn) activeBtn.classList.add('active-font'); } localStorage.setItem('userDyslexiaFont', fontType); announce(`Font: ${fontType}`); } function toggleClass(className, storageKey) { document.body.classList.toggle(className); localStorage.setItem(storageKey, document.body.classList.contains(className)); announce(`${className} ${document.body.classList.contains(className) ? 'enabled' : 'disabled'}`); } function resetAll() { document.body.className = document.body.className.replace(/\baccessibility-\w+/g, ''); document.documentElement.style.fontSize = ''; document.querySelectorAll('[data-action="dyslexia-font"]').forEach(btn => { btn.classList.remove('active-font'); }); ['userFontSize', 'userContrast', 'userDyslexiaFont', 'userHighlightLinks', 'userBigCursor'].forEach(key => { localStorage.removeItem(key); }); announce('All settings reset'); } // Load saved preferences function loadSavedPreferences() { const savedSize = localStorage.getItem('userFontSize'); if (savedSize) { document.documentElement.style.fontSize = savedSize + 'px'; } const savedContrast = localStorage.getItem('userContrast'); if (savedContrast && savedContrast !== 'reset') { changeContrast(savedContrast); } const savedFont = localStorage.getItem('userDyslexiaFont'); if (savedFont && savedFont !== 'normal') { changeDyslexiaFont(savedFont); } ['userHighlightLinks', 'userBigCursor'].forEach(key => { if (localStorage.getItem(key) === 'true') { const className = key.replace('user', '').toLowerCase(); document.body.classList.add('accessibility-' + className); } }); // Load language preference const savedLang = localStorage.getItem('accessibilityLanguage') || 'en'; applyTranslations(savedLang); setActiveLanguage(savedLang); } // Load preferences loadSavedPreferences(); // Close panel on Escape document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && panel.getAttribute('aria-hidden') === 'false') { closePanel(); } }); } })();