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.