PageSourceSearch

https://easytocompost.com/assets/js/navigation.js?v=1787567287

js easytocompost.com collected 2026-10-10 00:19:12 UTC 5,038 bytes, 134 lines download raw bytes

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.