PageSourceSearch

https://audition-morand.fr/shared-nav.js?v=3

js audition-morand.fr collected 2026-10-03 18:43:35 UTC 4,445 bytes, 119 lines download raw bytes

1// Audition Morand — Comportements de la nav et du footer
2// (la nav et le footer sont rendus en HTML statique dans chaque page —
3// ce script gère uniquement le burger mobile, le lien actif, le décodage
4// des emails anti-spam, et un nettoyage défensif des éventuels doublons)
5
6(function() {
7  if (window.__amNavInit) return;
8  window.__amNavInit = true;
9
10  // ----- Nettoyage défensif : retire tout doublon de footer/nav -----
11  // (utile si un ancien shared-nav.js encore en cache injecte un footer/nav)
12  function dedupe(selector) {
13    const els = document.querySelectorAll(selector);
14    if (els.length > 1) {
15      els.forEach((el, i) => { if (i > 0) el.remove(); });
16    }
17  }
18  function cleanup() {
19    dedupe('footer');
20    dedupe('nav#main-nav');
21  }
22  cleanup();
23  if (document.readyState !== 'complete') {
24    window.addEventListener('load', cleanup);
25  }
26  // Redondance sûre : un dernier passage après tous les scripts
27  setTimeout(cleanup, 0);
28
29  // ----- Lien actif dans la nav -----
30  const currentPage = window.location.pathname.split('/').pop() || 'index.html';
31  document.querySelectorAll('#nav-links a').forEach(a => {
32    const href = a.getAttribute('href');
33    if (href === currentPage || (currentPage === '' && href === 'index.html')) {
34      a.style.opacity = '1';
35      a.style.color = 'var(--teal)';
36    }
37  });
38
39  // ----- Décodage des emails encodés en base64 -----
40  function decodeEmails() {
41    document.querySelectorAll('a[data-em]').forEach(a => {
42      try {
43        const email = atob(a.getAttribute('data-em'));
44        a.setAttribute('href', 'mailto:' + email);
45        a.removeAttribute('data-em');
46      } catch (e) {}
47    });
48    document.querySelectorAll('.em-prot').forEach(span => {
49      try {
50        const email = atob(span.textContent.trim());
51        span.textContent = email;
52        span.classList.remove('em-prot');
53      } catch (e) {}
54    });
55  }
56  decodeEmails();
57})();
58
59function toggleMenu() {
60  const links = document.getElementById('nav-links');
61  const burger = document.getElementById('nav-burger');
62  links.classList.toggle('open');
63  burger.classList.toggle('open');
64}
65function closeMenu() {
66  document.getElementById('nav-links').classList.remove('open');
67  document.getElementById('nav-burger').classList.remove('open');
68}
69
70/* ===== Révélations au défilement — IntersectionObserver natif (léger, ~0 Ko) =====
71   Remplace GSAP (gain perf). Sécurité : ne masque QUE sous la ligne de flottaison
72   (zéro flash, LCP préservé), ne fait rien sans IntersectionObserver, et un minuteur
73   de secours révèle tout après 6 s. L'accueil garde son propre système (.reveal). */
74(function () {
75  if (window.__amRevealInit) return;
76  window.__amRevealInit = true;
77
78  function start() {
79    if (document.querySelector('.reveal')) return;            // accueil : système existant
80    if (!('IntersectionObserver' in window)) return;          // fail-safe : rien masqué
81    if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
82
83    var style = document.createElement('style');
84    style.textContent =
85      '.am-reveal{opacity:0;transform:translateY(28px);will-change:opacity,transform;' +
86      'transition:opacity .9s cubic-bezier(.22,1,.36,1),transform .9s cubic-bezier(.22,1,.36,1);}' +
87      '.am-reveal.am-in{opacity:1;transform:none;}';
88    document.head.appendChild(style);
89
90    var fold = window.innerHeight * 0.92;
91    var observed = [];
92    Array.prototype.forEach.call(
93      document.querySelectorAll('section, .article-container > *, .related-grid > *'),
94      function (el) {
95        if (el.getBoundingClientRect().top > fold) {            // sous le pli uniquement
96          el.classList.add('am-reveal');
97          observed.push(el);
98        }
99      }
100    );
101    if (!observed.length) return;
102
103    var io = new IntersectionObserver(function (entries) {
104      entries.forEach(function (e) {
105        if (e.isIntersecting) { e.target.classList.add('am-in'); io.unobserve(e.target); }
106      });
107    }, { rootMargin: '0px 0px -8% 0px' });
108    observed.forEach(function (el) { io.observe(el); });
109
110    // Minuteur de secours : tout révéler après 6 s quoi qu'il arrive
111    setTimeout(function () { observed.forEach(function (el) { el.classList.add('am-in'); }); }, 6000);
112  }
113
114  if (document.readyState === 'loading') {
115    document.addEventListener('DOMContentLoaded', start);
116  } else {
117    start();
118  }
119})();

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.