1/* Barra de navegacion de la red. Lo unico que necesita JavaScript. 2 * 3 * Los desplegables de la BARRA se abren con :hover y :focus-within, que es CSS 4 * puro. Aqui hay tres cosas: 5 * 6 * 1. El cajon lateral de movil. apellidos.net, que es la referencia, tiene el 7 * CSS del cajon pero no emite el boton que lo abre: por debajo de 768 px 8 * .nav-right se queda en right:-100% y el sitio se queda sin navegacion. 9 * El kit emite el boton siempre y esto lo mueve. 10 * 11 * 2. El desplegable de idiomas, que se abre al pulsar (no al pasar por 12 * encima) para que no se despliegue solo al mover el raton por la barra. 13 * 14 * 3. Los desplegables de CONTENIDO --`.desplegable`, el boton "A-Z" y el de 15 * la segunda letra--, que no son de la barra y no tienen apertura por 16 * CSS: sin este fichero no abren en ningun sitio. 17 * 18 * Sin dependencias, sin framework y con defer: no bloquea el render. Si el 19 * script no llega, en escritorio la barra sigue funcionando entera; se pierden 20 * el cajon de movil y los desplegables de contenido. 21 */ 22(function () { 23 'use strict'; 24 25 // --- cajon de movil --------------------------------------------------- 26 var toggle = document.querySelector('.mobile-toggle'); 27 var drawer = document.querySelector('.nav-right'); 28 29 if (toggle && drawer) { 30 var setOpen = function (open) { 31 drawer.classList.toggle('active', open); 32 toggle.classList.toggle('active', open); 33 document.body.classList.toggle('menu-open', open); 34 toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); 35 }; 36 37 toggle.addEventListener('click', function (e) { 38 e.stopPropagation(); 39 setOpen(!drawer.classList.contains('active')); 40 }); 41 42 // Al tocar fuera se cierra. 43 document.addEventListener('click', function (e) { 44 if (!drawer.contains(e.target) && !toggle.contains(e.target)) { 45 setOpen(false); 46 } 47 }); 48 49 // Y al elegir un destino: si no, al volver atras el cajon sigue abierto. 50 drawer.querySelectorAll('a').forEach(function (a) { 51 a.addEventListener('click', function () { setOpen(false); }); 52 }); 53 54 // Escape cierra, que es lo que espera cualquiera que use teclado. 55 document.addEventListener('keydown', function (e) { 56 if (e.key === 'Escape' && drawer.classList.contains('active')) { 57 setOpen(false); 58 toggle.focus(); 59 } 60 }); 61 } 62 63 // --- desplegable de idiomas ------------------------------------------- 64 var langBtn = document.querySelector('.lang-button'); 65 var langMenu = document.querySelector('.lang-dropdown'); 66 67 if (langBtn && langMenu) { 68 langBtn.addEventListener('click', function (e) { 69 e.stopPropagation(); 70 langMenu.classList.toggle('active'); 71 }); 72 document.addEventListener('click', function (e) { 73 if (!langBtn.contains(e.target) && !langMenu.contains(e.target)) { 74 langMenu.classList.remove('active'); 75 } 76 }); 77 document.addEventListener('keydown', function (e) { 78 if (e.key === 'Escape') { langMenu.classList.remove('active'); } 79 }); 80 } 81 82 // --- desplegables de contenido (.desplegable / .dropdown) -------------- 83 // 84 // Los dos selectores van juntos porque son el MISMO mecanismo: un boton y, 85 // justo detras, un menu que solo se abre si alguien le pone `.show`. El 86 // nombre distinto es historia --uno viene de apellidos.net y el otro de 87 // apellidos.de-- y no un componente distinto. 88 var SEL_BOTON = '.desplegable-toggle, .dropdown-toggle'; 89 var SEL_MENU = '.desplegable-menu, .dropdown-menu'; 90 91 // 92 // EL BOTON "A-Z" NO ABRIA NADA EN TRES SITIOS. 93 // 94 // `.desplegable-menu` esta en `display:none` y lo unico que lo abre es la 95 // clase `.show`. No hay regla de :hover ni de :focus-within que la 96 // sustituya, asi que sin JavaScript el boton es un boton muerto: se pinta, 97 // se puede pulsar, tiene su :hover, y no pasa nada. 98 // 99 // El JavaScript que la ponia vivia copiado dentro de `common/footer.php` 100 // de apellidos.net y apellidos.de, y no en el kit. Los otros tres sitios 101 // que heredaron el MARCADO --escudoheraldico.de, apellidosignificado.com y 102 // paises.org-- no heredaron el script. Medido en produccion: la pagina de 103 // letra de escudoheraldico.de sirve cinco `.desplegable-menu` y cero 104 // referencias a `.desplegable-toggle` en todo el HTML. 105 // 106 // Aqui llega a los dieciocho a la vez, que es de lo que va este fichero. 107 // La delegacion se engancha en `document` a proposito: las paginas de 108 // letra pintan el segundo desplegable dentro de un bucle de PHP y algunas 109 // lo hacen despues de este script. 110 document.addEventListener('click', function (e) { 111 var btn = e.target.closest ? e.target.closest(SEL_BOTON) : null; 112 113 // Fuera de cualquier desplegable: cerrar todos y salir. 114 if (!btn) { 115 if (!(e.target.closest && e.target.closest(SEL_MENU))) { 116 cerrarDesplegables(null); 117 } 118 return; 119 } 120 121 e.preventDefault(); 122 e.stopPropagation(); 123 var menu = btn.nextElementSibling; 124 if (!menu || !menu.matches(SEL_MENU)) { return; } 125 126 var abierto = menu.classList.contains('show'); 127 cerrarDesplegables(menu); 128 menu.classList.toggle('show', !abierto); 129 btn.setAttribute('aria-expanded', !abierto ? 'true' : 'false'); 130 }); 131 132 document.addEventListener('keydown', function (e) { 133 if (e.key === 'Escape') { cerrarDesplegables(null); } 134 }); 135 136 function cerrarDesplegables(salvo) { 137 var abiertos = document.querySelectorAll('.desplegable-menu.show, .dropdown-menu.show'); 138 for (var i = 0; i < abiertos.length; i++) { 139 if (abiertos[i] === salvo) { continue; } 140 abiertos[i].classList.remove('show'); 141 var b = abiertos[i].previousElementSibling; 142 if (b && b.matches(SEL_BOTON)) { 143 b.setAttribute('aria-expanded', 'false'); 144 } 145 } 146 } 147}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.