/** * Accesibilidad domavit.com - Correcciones WCAG 2.1 AA * Incluye: popup fix + imagenes + figures + autocomplete + labels + carrusel pausa * Cargar via WPCode con snippet minimo */ document.addEventListener('DOMContentLoaded', function() { // ============================================================ // 1. POPUP FIX - Enlaces de Elementor a popups (9.4.1.2, 9.2.4.4) // ============================================================ (function() { var popupLinks = document.querySelectorAll('a[href*="elementor-action"]'); var addedAnchors = new Set(); popupLinks.forEach(function(link) { var originalHref = link.getAttribute('href'); var match = originalHref.match(/settings%3D([A-Za-z0-9%+\/=]+)/); if (!match) { link.setAttribute('role', 'button'); return; } try { var b64 = match[1]; var jsonStr = atob(b64); var settings = JSON.parse(jsonStr); var popupId = settings.id; var anchorId = 'popup-' + popupId; link.setAttribute('href', '#' + anchorId); link.setAttribute('role', 'button'); var text = link.textContent.trim().toLowerCase(); var labels = { 'faq': 'Abrir ventana de preguntas frecuentes', 'ver mas': 'Ver mas proyectos', 'ver m\u00e1s': 'Ver m\u00e1s proyectos', 'comencemos': 'Iniciar proyecto', 'envianos un mensaje': 'Abrir formulario de contacto', 'env\u00edanos un mensaje': 'Abrir formulario de contacto', 'contacto': 'Ir al formulario de contacto' }; link.setAttribute('aria-label', labels[text] || 'Abrir ' + text); if (!addedAnchors.has(anchorId)) { addedAnchors.add(anchorId); var anchor = document.createElement('span'); anchor.id = anchorId; // Visually hidden pero accesible (no display:none para evitar broken link en WAVE) anchor.style.cssText = 'position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;'; document.body.appendChild(anchor); } var isProcessing = false; link.addEventListener('click', function(e) { if (isProcessing) return; isProcessing = true; e.preventDefault(); e.stopPropagation(); link.setAttribute('href', originalHref); link.click(); setTimeout(function() { link.setAttribute('href', '#' + anchorId); isProcessing = false; }, 50); }); } catch(e) { link.setAttribute('role', 'button'); } }); })(); // ============================================================ // 2. Imagenes decorativas (9.1.1.1) // ============================================================ document.querySelectorAll('img[alt=""]').forEach(function(img) { img.setAttribute('role', 'presentation'); }); // ============================================================ // 3. Figures sin figcaption (9.1.3.1) // ============================================================ document.querySelectorAll('figure:not([aria-label]):not([aria-labelledby])').forEach(function(figure) { var img = figure.querySelector('img'); if (img && img.getAttribute('alt')) { figure.setAttribute('aria-label', 'Imagen: ' + img.getAttribute('alt')); } else if (img) { figure.setAttribute('aria-label', 'Imagen decorativa'); } }); // ============================================================ // 4. Autocomplete en formularios (9.1.3.5) // ============================================================ document.querySelectorAll('form input:not([autocomplete]), form textarea:not([autocomplete])').forEach(function(input) { var type = input.getAttribute('type'); var name = (input.getAttribute('name') || '').toLowerCase(); var id = (input.getAttribute('id') || '').toLowerCase(); var ph = (input.getAttribute('placeholder') || '').toLowerCase(); var val = 'on'; if (type === 'email' || name.indexOf('email') !== -1 || id.indexOf('email') !== -1) { val = 'email'; } else if (type === 'tel' || name.indexOf('tel') !== -1 || name.indexOf('phone') !== -1) { val = 'tel'; } else if (name.indexOf('name') !== -1 || ph.indexOf('nombre') !== -1 || ph.indexOf('name') !== -1) { val = 'name'; } else if (name.indexOf('mensaje') !== -1 || name.indexOf('message') !== -1) { val = 'off'; } if (val !== 'off') input.setAttribute('autocomplete', val); }); // ============================================================ // 5. Aria-label en inputs (9.3.3.2) // ============================================================ document.querySelectorAll('form input:not([aria-label]):not([aria-labelledby]), form textarea:not([aria-label]):not([aria-labelledby])').forEach(function(input) { var ph = input.getAttribute('placeholder'); if (ph && ph.trim()) { input.setAttribute('aria-label', ph.trim()); } else { var name = input.getAttribute('name'); if (name) input.setAttribute('aria-label', 'Campo: ' + name.replace(/[-_]/g, ' ')); } }); // ============================================================ // 6. Boton de pausa en carrusel (9.2.2.2) // Enfoque DOM-based: no depende de la API interna de Swiper // Congela/descongela la animacion manipulando el transform // ============================================================ function initPause() { var carousels = document.querySelectorAll('.elementor-image-carousel-wrapper'); carousels.forEach(function(container) { if (container.querySelector('.acc-pause')) return; var wrapper = container.querySelector('.swiper-wrapper'); if (!wrapper) return; var btn = document.createElement('button'); btn.className = 'acc-pause'; btn.setAttribute('aria-label', 'Pausar carrusel'); btn.innerHTML = ''; btn.style.cssText = 'position:absolute;top:10px;right:10px;z-index:10;' + 'background:none;color:#fff;border:none;' + 'cursor:pointer;font-size:20px;line-height:1;' + 'opacity:0.7;text-shadow:0 1px 3px rgba(0,0,0,0.3);'; var paused = false; btn.onclick = function() { paused = !paused; if (paused) { // Congelar: capturar transform actual y fijarlo sin transicion var currentTransform = window.getComputedStyle(wrapper).transform; wrapper.style.transition = 'none'; wrapper.style.transform = currentTransform; btn.setAttribute('aria-label', 'Reanudar carrusel'); btn.innerHTML = ''; } else { // Descongelar: restaurar transicion y dejar que Swiper continue wrapper.style.transition = ''; wrapper.style.transform = ''; btn.setAttribute('aria-label', 'Pausar carrusel'); btn.innerHTML = ''; } }; container.style.position = 'relative'; container.appendChild(btn); }); } // Ejecutar varias veces para asegurar que el DOM este listo [500, 1500, 3000].forEach(function(delay) { setTimeout(initPause, delay); }); document.addEventListener('elementor/popup/show', function() { setTimeout(initPause, 1000); }); // ============================================================ // 7. Enlaces vacios de redes sociales (9.2.4.4, 9.4.1.2) // Anade aria-label a iconos de Instagram y LinkedIn sin texto // ============================================================ document.querySelectorAll('a[href*="instagram.com"], a[href*="linkedin.com"]').forEach(function(link) { if (!link.getAttribute('aria-label') && !link.textContent.trim()) { var href = link.getAttribute('href') || ''; if (href.indexOf('instagram') !== -1) { link.setAttribute('aria-label', 'Visitar Instagram de Domavit'); } else if (href.indexOf('linkedin') !== -1) { link.setAttribute('aria-label', 'Visitar LinkedIn de Domavit'); } // No necesidad de role=link explicito en con href } }); // ============================================================ // 8. Correccion de contraste (9.1.4.3) // Oscurece #CC3366 a #B82D5A (~6:1 contraste sobre blanco) // Solo afecta al widget de contenido principal (evita footer) // ============================================================ (function() { var style = document.createElement('style'); style.id = 'acces-contrast-fix'; style.textContent = '' + '.elementor-widget-text-editor a,' + '.elementor-widget-text-editor .elementor-icon-list-text {' + 'color:#B82D5A!important}'; document.head.appendChild(style); })(); // ============================================================ // 9. Anclar anchors faltantes para same-page links (9.2.4.4, 9.2.1.1) // Anade targets ocultos para #servicios, #proyectos, #blog, // #contacto y #content en paginas donde no existen // ============================================================ (function() { var neededAnchors = ['servicios', 'proyectos', 'blog', 'contacto', 'content']; neededAnchors.forEach(function(id) { if (!document.getElementById(id)) { var anchor = document.createElement('span'); anchor.id = id; anchor.style.cssText = 'position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;'; document.body.appendChild(anchor); } }); })(); // ============================================================ // 10. Enlaces redundantes (9.2.4.4) // El email tecnologia@domavit.com aparece duplicado en la // pagina de privacidad. Convertimos el segundo a texto plano. // ============================================================ (function() { var mailtoLinks = document.querySelectorAll('a[href="mailto:tecnologia@domavit.com"]'); // Si hay mas de uno, los siguientes se convierten a texto plano if (mailtoLinks.length > 1) { for (var i = 1; i < mailtoLinks.length; i++) { var link = mailtoLinks[i]; var text = link.textContent || 'tecnologia@domavit.com'; var span = document.createElement('span'); span.textContent = text; link.parentNode.replaceChild(span, link); } } })(); });