1const ModuleStickyNavAnchor = { 2 _: { 3 initialize: false, 4 stickyNav: null, 5 footer: null, 6 anchors: [], 7 scrollTimeout: null, 8 lastFooterState: null, 9 verticalOffset: 0.4, // Facteur d'ajustement pour le centrage vertical (0.5 = 50%) 10 }, 11 12 init() { 13 document.addEventListener("DOMContentLoaded", () => { 14 this.tryInit(); 15 }); 16 17 document.addEventListener("load", () => { 18 this.tryInit(); 19 }); 20 21 setTimeout(() => { 22 this.tryInit(); 23 }, 100); 24 }, 25 26 tryInit() { 27 if (this._.initialize) return; 28 29 this._.stickyNav = document.querySelector(".acf-block-sticky-nav-anchor"); 30 this._.footer = 31 document.querySelector(".wp-site-blocks > footer") || 32 document.querySelector("#colophon") || 33 document.querySelector("footer"); 34 35 if (!this._.stickyNav || !this._.footer) return; 36 37 this.collectAnchors(); 38 if (this._.anchors.length === 0) return; 39 40 this.bindEvents(); 41 this._.initialize = true; 42 }, 43 44 collectAnchors() { 45 const navLinks = this._.stickyNav.querySelectorAll( 46 ".sticky-nav-anchor__link" 47 ); 48 49 navLinks.forEach((link) => { 50 const anchorId = link.getAttribute("data-anchor"); 51 if (anchorId) { 52 const anchorElement = document.getElementById(anchorId); 53 if (anchorElement) { 54 this._.anchors.push({ 55 id: anchorId, 56 element: anchorElement, 57 link: link, 58 }); 59 } 60 } 61 }); 62 }, 63 64 bindEvents() { 65 window.addEventListener("scroll", () => this.onScroll(), { passive: true }); 66 window.addEventListener("resize", () => this.onScroll(), { passive: true }); 67 68 this._.anchors.forEach(({ link, id }) => { 69 link.addEventListener("click", (e) => this.handleAnchorClick(e, id)); 70 }); 71 72 // Vérification initiale 73 setTimeout(() => { 74 this.checkActiveAnchors(); 75 this.checkFooterVisibility(); 76 }, 300); 77 }, 78 79 checkActiveAnchors() { 80 const scrollTop = window.scrollY; 81 const viewportHeight = window.innerHeight; 82 const triggerPoint = scrollTop + viewportHeight / 2; 83 84 let activeAnchor = null; 85 86 for (const anchor of this._.anchors) { 87 const rect = anchor.element.getBoundingClientRect(); 88 const elementTopDoc = rect.top + scrollTop; 89 90 if (elementTopDoc <= triggerPoint) { 91 activeAnchor = anchor; 92 } 93 } 94 95 this._.anchors.forEach(({ link }) => link.classList.remove("active")); 96 97 if (activeAnchor) { 98 activeAnchor.link.classList.add("active"); 99 } 100 }, 101 102 checkFooterVisibility() { 103 const footerRect = this._.footer.getBoundingClientRect(); 104 const viewportHeight = window.innerHeight; 105 const footerTop = footerRect.top; 106 const threshold = 150; 107 const shouldHide = footerTop - viewportHeight < threshold; 108 109 if (shouldHide) { 110 if (!this._.stickyNav.classList.contains("hide")) { 111 this._.stickyNav.classList.add("hide"); 112 } 113 } else { 114 if (this._.stickyNav.classList.contains("hide")) { 115 this._.stickyNav.classList.remove("hide"); 116 } 117 } 118 }, 119 120 onScroll() { 121 if (this._.scrollTimeout) { 122 window.cancelAnimationFrame(this._.scrollTimeout); 123 } 124 125 this._.scrollTimeout = window.requestAnimationFrame(() => { 126 this.checkActiveAnchors(); 127 this.checkFooterVisibility(); 128 }); 129 }, 130 131 handleAnchorClick(e, anchorId) { 132 e.preventDefault(); 133 const targetElement = document.getElementById(anchorId); 134 135 if (targetElement) { 136 const viewportHeight = window.innerHeight; 137 const elementRect = targetElement.getBoundingClientRect(); 138 const elementHeight = elementRect.height; 139 140 // Calcul pour centrer l'élément dans la fenêtre avec facteur d'ajustement 141 const targetPosition = window.scrollY + elementRect.top; 142 const centerOffset = 143 (viewportHeight - elementHeight) * this._.verticalOffset; 144 const offsetTop = targetPosition - 140; 145 146 window.scrollTo({ 147 top: offsetTop, 148 behavior: "smooth", 149 }); 150 } 151 }, 152}; 153
154ModuleStickyNavAnchor.init();
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.