Версия сайта для слабовидящих на Тильде

Скрипт добавляет версию сайта для слабовидящих, соответствующую всем регламентам для прохождения сертификации
Добавьте элементу класс eyebtn и вставьте код в блок T123
<style>
    .eyebtn {
        cursor: pointer !important;
        user-select: none !important;
    }
</style>
<script defer src="https://cdn.jsdelivr.net/gh/veks/button-visually-impaired-javascript@master/dist/js/bvi.min.js"></script>
<script>
    // Обработчик ошибок загрузки ресурсов
    window.addEventListener('error', function(e) {
        if (e.target.tagName === 'SCRIPT' || e.target.tagName === 'LINK') {
            console.error('Resource loading failed:', e.target.src || e.target.href);
        }
    });

    // Функция debounce для оптимизации производительности
    function debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func(...args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    document.addEventListener('DOMContentLoaded', function() {
        console.log('DOMContentLoaded event fired');
        let altDisplayEnabled = false;

        // Инициализация Bvi
        try {
            new isvek.Bvi({
                target: '.eyebtn',
                theme: 'white',
                builtElements: true,
                fontSize: 16,
                letterSpacing: 'normal',
                lineHeight: 'normal',
                speech: true,
                fontFamily: 'arial',
                panelFixed: true,
                reload: false,
                lang: 'ru-RU',
                // Дополнительные параметры
                images: true, // Включить поддержку изображений
                panelHide: false, // Показывать панель управления
                speechVolume: 1, // Громкость синтеза речи
                speechRate: 1, // Скорость синтеза речи
                speechPitch: 1, // Тон синтеза речи
                modes: ['font', 'spacing', 'speech', 'images'], // Доступные режимы
            });
            console.log('isvek.Bvi initialized');
        } catch (error) {
            console.error('Error initializing isvek.Bvi:', error);
        }

        // Функция добавления стилей
        function addStyles() {
            console.log('addStyles function called');
            const cssUrl = 'https://cdn.jsdelivr.net/gh/veks/button-visually-impaired-javascript@master/dist/css/bvi.min.css';
            
            if (!document.querySelector(`link[href="${cssUrl}"]`)) {
                const linkElement = document.createElement('link');
                linkElement.rel = 'stylesheet';
                linkElement.type = 'text/css';
                linkElement.href = cssUrl;
                linkElement.addEventListener('error', () => console.error('Error loading stylesheet:', cssUrl));
                document.head.appendChild(linkElement);
                console.log('Stylesheet added');

                const eyeElement = document.querySelector('.tn-elem__6804599361705334185737');
                if (eyeElement) {
                    const eye = eyeElement.children[0]?.children[0];
                    if (eye && !eye.src && eye.dataset.original) {
                        eye.src = eye.dataset.original;
                        console.log('Eye src updated');
                    }
                } else {
                    console.warn('Eye element not found');
                }
            } else {
                console.log('Stylesheet already exists');
            }
        }

        // Функция удаления стилей
        function removeStyles() {
            console.log('removeStyles function called');
            return new Promise((resolve) => {
                const linkElement = document.querySelector(`link[href="https://cdn.jsdelivr.net/gh/veks/button-visually-impaired-javascript@master/dist/css/bvi.min.css"]`);
                if (linkElement) {
                    linkElement.parentNode.removeChild(linkElement);
                    console.log('Stylesheet removed');
                    setTimeout(() => {
                        window.location.reload();
                        resolve();
                    }, 100);
                } else {
                    console.log('Stylesheet not found');
                    resolve();
                }
            });
        }

        // Функция включения отображения alt-текста
        function enableAltDisplay() {
            console.log('enableAltDisplay function called');
            if (altDisplayEnabled) return;
            altDisplayEnabled = true;

            document.querySelectorAll('[alt]').forEach(element => {
                const altText = element.getAttribute('alt');
                if (!altText) return;

                const altContainer = document.createElement('div');
                altContainer.textContent = altText;
                altContainer.dataset.bvi = 'alt-container';
                altContainer.setAttribute('field', 'alt');
                altContainer.classList.add('bvi-speech');
                
                if (!element.nextElementSibling?.hasAttribute('data-bvi')) {
                    element.parentNode.insertBefore(altContainer, element.nextSibling);
                    console.log('altContainer added for element with alt');
                }
            });
        }

        // Функция отключения отображения alt-текста
        function disableAltDisplay() {
            console.log('disableAltDisplay function called');
            altDisplayEnabled = false;

            document.querySelectorAll('div[data-bvi="alt-container"]').forEach(container => {
                container.parentNode.removeChild(container);
                console.log('altContainer removed');
            });
        }

        // Создаем debounced версии функций
        const debouncedEnableAltDisplay = debounce(enableAltDisplay, 250);
        const debouncedDisableAltDisplay = debounce(disableAltDisplay, 250);

        // Добавляем обработчики событий
        const eyebtn = document.querySelector('.eyebtn');
        if (eyebtn) {
            console.log('eyebtn found');
            eyebtn.addEventListener('click', function() {
                console.log('eyebtn clicked');
                addStyles();
                debouncedEnableAltDisplay();
            });
        } else {
            console.warn('eyebtn not found');
        }

        // Обработчик закрытия панели
        document.addEventListener('click', function(event) {
            if (event.target && event.target.getAttribute('data-bvi') === 'close') {
                console.log('Close button clicked');
                removeStyles().then(() => {
                    debouncedDisableAltDisplay();
                });
            }
        });

        // Добавляем классы для речевого воспроизведения
        document.querySelectorAll('[field]').forEach(field => {
            field.classList.add('bvi-speech');
            console.log('bvi-speech class added to field');
        });

        // Копируем aria-label в alt атрибуты
        document.querySelectorAll('[aria-label]').forEach(element => {
            const ariaLabelValue = element.getAttribute('aria-label');
            if (ariaLabelValue) {
                element.setAttribute('alt', ariaLabelValue);
                console.log('alt attribute added to element with aria-label');
            }
        });

        // Добавляем обработчик изменения размера окна
        window.addEventListener('resize', debounce(() => {
            if (altDisplayEnabled) {
                debouncedEnableAltDisplay();
            }
        }, 250));
    });
</script>
Спасибо за библиотеку Oleg Korotenko
Вам помогла эта модификация?