PageSourceSearch

https://nomsdefamille.net/_kit/js/nav.js?v=20260828-212211

js nomsdefamille.net collected 2026-09-25 05:44:44 UTC 6,238 bytes, 147 lines download raw bytes

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.