1/* ============================================================ 2 navigation.js â les menus de l'en-tete. 3 4 Le CSS attend une classe .is-open sur les deux composants 5 (.nav-dropdown et .mobile-menu) ; personne ne la posait, les 6 deroulants et le bouton burger etaient donc inertes au clic. 7 8 Tout passe par delegation sur le document : aucun ecouteur n'est 9 attache aux boutons eux-memes. C'est volontaire â sur ce site 10 l'en-tete peut etre en place apres l'execution du script (page 11 pre-rendue, balises tierces), et un ecouteur pose trop tot sur un 12 bouton disparait avec lui. Delegue, le menu repond quoi qu'il 13 arrive. 14 15 Un seul deroulant ouvert a la fois. Echap ferme, un clic hors du 16 menu ferme, et l'etat est annonce par aria-expanded. 17 ============================================================ */ 18(function () { 19 var DELAI_FERMETURE = 420; /* le temps d'atteindre le menu a la souris */ 20 var minuteur = null; 21 22 function annulerFermeture() { 23 if (minuteur) { clearTimeout(minuteur); minuteur = null; } 24 } 25 26 function fermerTout(sauf) { 27 var ouverts = document.querySelectorAll('[data-dropdown].is-open'); 28 [].forEach.call(ouverts, function (d) { 29 if (d === sauf) return; 30 d.classList.remove('is-open'); 31 var t = d.querySelector('.nav-dropdown__trigger'); 32 if (t) t.setAttribute('aria-expanded', 'false'); 33 }); 34 } 35 36 function ouvrir(d) { 37 annulerFermeture(); 38 fermerTout(d); 39 d.classList.add('is-open'); 40 var t = d.querySelector('.nav-dropdown__trigger'); 41 if (t) t.setAttribute('aria-expanded', 'true'); 42 } 43 44 function fermer(d) { 45 d.classList.remove('is-open'); 46 var t = d.querySelector('.nav-dropdown__trigger'); 47 if (t) t.setAttribute('aria-expanded', 'false'); 48 } 49 50 /* ---------- Les deroulants de la barre principale ---------- */ 51 document.addEventListener('click', function (e) { 52 var trigger = e.target.closest ? e.target.closest('.nav-dropdown__trigger') : null; 53 54 if (trigger) { 55 var d = trigger.closest('[data-dropdown]'); 56 if (!d) return; 57 e.preventDefault(); 58 if (d.classList.contains('is-open')) fermer(d); else ouvrir(d); 59 return; 60 } 61 /* un clic ailleurs referme, sauf s'il a lieu dans un menu ouvert */ 62 if (!e.target.closest || !e.target.closest('[data-dropdown]')) fermerTout(null); 63 }); 64 65 /* Survol : on ouvre en entrant, on ferme apres un delai de grace. 66 mouseover/mouseout bouillonnent, contrairement a mouseenter. */ 67 document.addEventListener('mouseover', function (e) { 68 if (!window.matchMedia('(hover: hover)').matches) return; 69 var d = e.target.closest ? e.target.closest('[data-dropdown]') : null; 70 if (!d) return; 71 annulerFermeture(); 72 if (!d.classList.contains('is-open')) ouvrir(d); 73 }); 74 75 document.addEventListener('mouseout', function (e) { 76 if (!window.matchMedia('(hover: hover)').matches) return; 77 var d = e.target.closest ? e.target.closest('[data-dropdown]') : null; 78 if (!d) return; 79 /* on ignore les deplacements internes au composant */ 80 if (e.relatedTarget && e.relatedTarget.closest && e.relatedTarget.closest('[data-dropdown]') === d) return; 81 annulerFermeture(); 82 minuteur = setTimeout(function () { fermer(d); }, DELAI_FERMETURE); 83 }); 84 85 /* ---------- Le menu plein ecran des petits ecrans ---------- */ 86 function panneau() { return document.getElementById('mobile-menu'); } 87 function bouton() { return document.getElementById('burger-btn'); } 88 89 function ouvrirMobile() { 90 var p = panneau(); if (!p) return; 91 p.classList.add('is-open'); 92 p.removeAttribute('inert'); 93 p.setAttribute('aria-hidden', 'false'); 94 var b = bouton(); if (b) b.setAttribute('aria-expanded', 'true'); 95 document.body.style.overflow = 'hidden'; 96 var premier = p.querySelector('a, button'); 97 if (premier) premier.focus({ preventScroll: true }); 98 } 99 100 function fermerMobile() { 101 var p = panneau(); 102 if (!p || !p.classList.contains('is-open')) return; 103 p.classList.remove('is-open'); 104 p.setAttribute('inert', ''); 105 p.setAttribute('aria-hidden', 'true'); 106 var b = bouton(); 107 if (b) { b.setAttribute('aria-expanded', 'false'); b.focus({ preventScroll: true }); } 108 document.body.style.overflow = ''; 109 } 110 111 document.addEventListener('click', function (e) { 112 if (!e.target.closest) return; 113 114 if (e.target.closest('#burger-btn')) { 115 e.preventDefault(); 116 var p = panneau(); 117 if (p && p.classList.contains('is-open')) fermerMobile(); else ouvrirMobile(); 118 return; 119 } 120 if (e.target.closest('#close-menu-btn')) { e.preventDefault(); fermerMobile(); return; } 121 /* un lien suivi referme le panneau : sinon il reste ouvert au retour */ 122 if (e.target.closest('#mobile-menu a')) fermerMobile(); 123 }); 124 125 document.addEventListener('keydown', function (e) { 126 if (e.key !== 'Escape') return; 127 fermerTout(null); 128 fermerMobile(); 129 }); 130 131 window.addEventListener('resize', function () { 132 if (window.innerWidth > 1024) fermerMobile(); 133 }); 134})();
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.