1/* Source and licensing information for the line(s) below can be found at https://www.thierryphilip.fr/sites/all/themes/tfactory/js/scrollnav.min.js. */ 2!function (f, h) { "object" == typeof exports && "undefined" != typeof module ? module.exports = h() : "function" == typeof define && define.amd ? define(h) : f.scrollnav = h() }(this, function () { function f(f, h) { var y, E = {}; for (y in f) Object.prototype.hasOwnProperty.call(f, y) && (E[y] = f[y]); for (y in h) Object.prototype.hasOwnProperty.call(h, y) && (E[y] = h[y]); return E } function h(f, h) { if ("object" != typeof f) return Promise.reject(new Error("First argument must be an object")); if ("object" != typeof (h = h || document.body)) return Promise.reject(new Error("Second argument must be an object")); var y = h.getBoundingClientRect(); return f.getBoundingClientRect().top - y.top } function y(f, E, w) { void 0 === w && (w = "scroll-nav"); var L = []; return w += "__", f.forEach(function (f, O) { var x = [], j = function (f, h) { if ("object" != typeof f) return Promise.reject(new Error("First argument must be an object")); var y = f.id; if (!y) { if ("string" != typeof h) return Promise.reject(new Error("Second argument must be a string")); f.id = y = h } return y }(f, w + (O + 1)); E.subSections && f.matches(E.sections) && (x = y(function (f, h, y) { var E = []; for (f = f.nextElementSibling; f && !f.matches(h);)!y || f.matches(y) ? (E.push(f), f = f.nextElementSibling) : f = f.nextElementSibling; return E }(f, E.sections, E.subSections), E, j)); L.push({ id: j, text: f.innerText || f.textContent, offsetTop: h(f), subSections: x }) }), L } function E(f) { var h = document.createElement("nav"); return h.className = "scroll-nav", h.innerHTML = function f(h, y) { void 0 === y && (y = !1); var E = "scroll-nav" + (y ? "__sub-" : "__"), w = "\n " + h.map(function (h) { return '<li class="' + E + 'item" data-sn-section="' + h.id + '">\n <a class="' + E + 'link" href="#' + h.id + '">' + h.text + "</a>\n " + (h.subSections && h.subSections.length ? "" + f(h.subSections, !0) : "") + "\n </li>" }).join("") + "\n "; return '\n <ol class="' + E + 'list">\n ' + w + "\n </ol>\n " }(f), h } function w(f) { return f.forEach(function (f) { var y = document.querySelector("#" + f.id); f.offsetTop = h(y), f.subSections.length && (f.subSections = w(f.subSections)) }), f } function L(f, h) { var y = f.getAttribute("href"); return "#" === y.charAt(0) && (y = y.substr(1)), function f(h, y) { var E; h.forEach(function (h) { h.id === y && (E = h), h.subSections && void 0 === E && (E = f(h.subSections, y)) }); return E }(h, y).offsetTop } var O, x, j, _ = function (f) { return function (h) { return Math.pow(h, f) } }, M = function (f) { return function (h) { return 1 - Math.abs(Math.pow(h - 1, f)) } }, I = function (f) { return function (h) { return h < .5 ? _(f)(2 * h) / 2 : M(f)(2 * h - 1) / 2 + .5 } }, Q = { linear: I(1), easeInQuad: _(2), easeOutQuad: M(2), easeInOutQuad: I(2), easeInCubic: _(3), easeOutCubic: M(3), easeInOutCubic: I(3), easeInQuart: _(4), easeOutQuart: M(4), easeInOutQuart: I(4), easeInQuint: _(5), easeOutQuint: M(5), easeInOutQuint: I(5) }; function C(f, h) { return new Promise(function (y, E) { if ("number" != typeof f) return E(new Error("First argument must be a number")); if ("string" != typeof (h = h || "linear")) return E(new Error("Second argument must be a string")); var w, L = window.pageYOffset, O = f - L, x = function (f) { var h = Math.abs(f / 2); return Math.min(Math.max(h, 250), 1200) }(O), j = 20, _ = 0; !function f() { w = Q[h]((_ += j) / x), window.scroll(0, w * O + L), _ < x ? setTimeout(f, j) : y(window.pageYOffset) }() }) } function q(f) { function h() { var h = window.scrollY || window.pageYOffset || document.body.scrollTop, y = h + .4 * window.innerHeight, E = function f(h, y, E) { var w, L; h.forEach(function (f) { f.offsetTop > E ? !w && f.offsetTop < y && (w = f) : w = f }), w && w.subSections.length && (L = f(w.subSections, y, E)) && (w = L); return w }(f.data, h, y); return function (f, h) { var y = h.querySelector("[data-sn-active]"); if (f) { var E = h.querySelector("[data-sn-section=" + f.id + "]"); E && E !== y && (y && (y.classList.remove("scroll-nav__item--active"), y.removeAttribute("data-sn-active")), E.classList.add("scroll-nav__item--active"), E.setAttribute("data-sn-active", !0)) } else y && (y.classList.remove("scroll-nav__item--active"), y.removeAttribute("data-sn-active")) }
2(E, f.nav), E } return window.addEventListener("scroll", h), h } function B(f) { return f instanceof Element } return Element.prototype.matches || (Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector), { init: function (h, _) { if (this.settings = f({ sections: "h2", insertTarget: h, insertLocation: "before", easingStyle: "easeOutQuad", updateHistory: !0 }, _), B(h)) if (!this.settings.insertTarget || B(this.settings.insertTarget)) if (["append", "prepend", "after", "before"].includes(this.settings.insertLocation)) { var M, I, Q, F, R = h.querySelectorAll(this.settings.sections); if (R.length) return this.data = y(R, this.settings), this.nav = E(this.data), I = (M = this).settings.insertTarget, "append" === (Q = M.settings.insertLocation) ? I.appendChild(M.nav) : "prepend" === Q ? I.insertBefore(M.nav, I.firstChild) : "before" === Q ? I.parentNode.insertBefore(M.nav, I) : "after" === Q && I.parentNode.insertBefore(M.nav, I.nextSibling), O = function (f) { var h = f.settings; function y(y) { y.preventDefault(); var E = .39 * window.innerHeight; return C(L(y.target, f.data) - E, h.easingStyle).then(function () { h.updateHistory && history.replaceState({}, "", y.target.getAttribute("href")), h.onScroll && h.onScroll() }) } return f.nav.querySelectorAll("a").forEach(function (f) { f.addEventListener("click", y) }), y }(this), x = q(this), j = function (f) { function h() { f.data = w(f.data) } return window.addEventListener("resize", h), h }(this), this.settings.debug && ((F = document.createElement("div")).className = "snDebugger", F.setAttribute("style", "\n position: fixed;\n top: 40%;\n height: 0px;\n border-bottom:5px solid red;\n border-top: 5px solid blue;\n width: 100%;\n opacity: .5;\n pointer-events: none;\n "), document.body.appendChild(F)), this.settings.onInit ? this.settings.onInit() : void 0; this.settings.debug && console.error('\n scrollnav build failed, could not find any "' + this.settings.sections + '"\n elements inside of "' + h + '"\n ') } else this.settings.debug && console.error('\n scrollnav build failed, options.insertLocation "' + this.settings.insertLocation + '" is not a valid option\n '); else this.settings.debug && console.error('\n scrollnav build failed, options.insertTarget "' + h + '" is not an HTML Element\n '); else this.settings.debug && console.error('\n scrollnav build failed, content argument "' + h + '" is not an HTML Element\n ') }, destroy: function (h) { if (this.settings = f(this.settings, h), function (f, h) { f.querySelectorAll("a").forEach(function (f) { f.removeEventListener("click", h) }) }(this.nav, O), function (f) { window.removeEventListener("scroll", f) }(x), function (f) { window.removeEventListener("resize", f) }(j), this.nav.remove(), this.settings.onDestroy) return this.settings.onDestroy() }, updatePositions: function (h) { if (this.settings = f(this.settings, h), this.data = w(this.data), this.settings.onUpdatePositions) return this.settings.onUpdatePositions() } } }); 3//# sourceMappingURL=scrollnav.min.umd.js.map 4;/*})'"*/ 5; 6/* Source and licensing information for the above line(s) can be found at https://www.thierryphilip.fr/sites/all/themes/tfactory/js/scrollnav.min.js. */;/*})'"*/ 7(function (window, document) { 8 "use strict"; 9 10 class StickMe { 11 /** 12 * @param {HTMLElement} element - L'élément à rendre sticky 13 * @param {Object} [options] 14 * @param {number} [options.topSpacing=10] - Espace en px entre le haut de la fenêtre et l'élément sticky 15 * @param {number} [options.minWidth=1024] - Seuil de largeur d'écran (en px) au-dessus duquel le sticky est activé 16 */ 17 constructor(element, options = {}) { 18 if (!element) return; 19 20 // Propriétés 21 this.el = element; 22 this.parent = element.parentElement; 23 this.options = { 24 topSpacing: options.topSpacing || 10, 25 minWidth: options.minWidth || 1024 26 }; 27 28 // Ãtat 29 this.isSticky = false;
30 31 // Sauvegarde des styles initiaux 32 this.initialStyles = { 33 position: this.el.style.position || '', 34 top: this.el.style.top || '', 35 width: this.el.style.width || '' 36 }; 37 38 // Détection mobile (en dessous d'un certain breakpoint) 39 // Vous pouvez ajuster la valeur selon vos besoins. 40 this.isMobile = window.innerWidth < 768; 41 42 // Barre de progression 43 this.progressBar = null; 44 45 // Bind des méthodes 46 this.onScroll = this.onScroll.bind(this); 47 this.onResize = this.onResize.bind(this); 48 49 // Initialisation 50 this.setup(); 51 } 52 53 /** 54 * Lance lâinitialisation : calcul des positions et mise en place des écouteurs. 55 */ 56 setup() { 57 // Création de la barre de progression 58 this.createProgressBar(); 59 60 window.addEventListener('scroll', this.onScroll); 61 window.addEventListener('resize', this.onResize); 62 63 // Calcul des positions initiales et application 64 this.updateRects(); 65 this.onScroll(); // première mise à jour 66 } 67 68 /** 69 * Crée la barre de progression en haut de lâécran (uniquement sur mobile). 70 */ 71 createProgressBar() { 72 this.progressBar = document.createElement('div'); 73 // Style basique 74 this.progressBar.style.position = 'fixed'; 75 this.progressBar.style.top = '0'; 76 this.progressBar.style.left = '0'; 77 this.progressBar.style.height = '4px'; 78 this.progressBar.style.backgroundColor = '#00bfff'; 79 this.progressBar.style.width = '0%'; 80 this.progressBar.style.zIndex = '9999'; 81 this.progressBar.style.transition = 'width 0.2s ease'; 82 83 // Affiché uniquement si mobile 84 if (!this.isMobile) { 85 this.progressBar.style.display = 'none'; 86 } 87 88 // On ajoute la barre au body 89 document.body.appendChild(this.progressBar); 90 } 91 92 /** 93 * Calcule et met à jour les paramètres de position (limites de sticky). 94 */ 95 updateRects() { 96 // Récupère la largeur du parent (pour lâappliquer en "width" au sticky) 97 this.parentRect = this.parent.getBoundingClientRect(); 98 this.elRect = this.el.getBoundingClientRect(); 99 100 // Position absolue de lâélément dans la page 101 const parentOffsetTop = this.getOffsetTop(this.parent); 102 const elOffsetTop = this.getOffsetTop(this.el); 103 104 // Point de déclenchement : quand le haut de la fenêtre (scrollY) 105 // atteint le haut de l'élément (moins topSpacing si souhaité). 106 this.stickStart = elOffsetTop - this.options.topSpacing; 107 108 // Point dâarrêt : le bas du parent - la hauteur de lâélément - topSpacing 109 this.stickStop = 110 parentOffsetTop + this.parent.offsetHeight 111 - this.el.offsetHeight 112 - this.options.topSpacing; 113 114 // Largeur identique à celle du parent 115 this.elWidth = `${this.parentRect.width}px`; 116 } 117 118 /** 119 * Gère le comportement lors du scroll. 120 */ 121 onScroll() { 122 // Désactive si la fenêtre est trop étroite 123 if (window.innerWidth < this.options.minWidth) { 124 this.reset(); 125 } else { 126 const scrollY = window.scrollY || document.documentElement.scrollTop; 127 128 // 1) En-dessous du point de déclenchement : reset 129 if (scrollY < this.stickStart) { 130 if (this.isSticky) { 131 this.reset(); 132 } 133 } 134 // 2) Entre le point de déclenchement et la fin du parent 135 else if (scrollY >= this.stickStart && scrollY < this.stickStop) { 136 if (!this.isSticky || this.el.style.position !== 'fixed') { 137 this.setFixed(); 138 } 139 } 140 // 3) Plus bas que la fin du parent 141 else if (scrollY >= this.stickStop) { 142 this.setFixed(); 143 } 144 } 145 146 // Mise à jour de la barre de progression (si mobile) 147 if (this.isMobile && this.progressBar) { 148 this.updateProgressBar(); 149 } 150 } 151 152 /** 153 * Mise à jour lors d'un redimensionnement de la fenêtre. 154 */ 155 onResize() { 156 // Redéfinit si on est en mobile ou non 157 this.isMobile = window.innerWidth < 768; 158 // Affichage ou masquage de la barre de progression 159 if (this.progressBar) { 160 this.progressBar.style.display = this.isMobile ? 'block' : 'none'; 161 } 162 163 // Restaure lâétat initial avant de recalculer 164 this.reset(); 165 this.updateRects(); 166 this.onScroll(); 167 } 168 169 /** 170 * Positionne lâélément en `fixed` à la bonne largeur et en haut de lâécran. 171 */ 172 setFixed() { 173 this.el.style.position = 'fixed'; 174 this.el.style.top = `${this.options.topSpacing}px`; 175 this.el.style.width = this.elWidth; 176 this.isSticky = true; 177 } 178 179 /** 180 * Réinitialise le style de lâélément (retour à lâétat initial). 181 */ 182 reset() { 183 this.el.style.position = this.initialStyles.position; 184 this.el.style.top = this.initialStyles.top; 185 this.el.style.width = this.initialStyles.width; 186 this.isSticky = false;
187 } 188 189 /** 190 * Met à jour la largeur de la barre de progression en fonction du scroll. 191 */ 192 updateProgressBar() { 193 // Hauteur de tout le document - hauteur de la fenêtre 194 const docHeight = document.documentElement.scrollHeight - window.innerHeight; 195 // Scroll actuel 196 const scrollTop = window.scrollY || document.documentElement.scrollTop; 197 198 // Calcul du pourcentage 199 const progress = (scrollTop / docHeight) * 100; 200 // On borne entre 0% et 100% 201 const clampedProgress = Math.max(0, Math.min(progress, 100)); 202 this.progressBar.style.width = clampedProgress + '%'; 203 } 204 205 /** 206 * Calcule la distance entre le haut de la page et lâélément donné. 207 * @param {HTMLElement} el - lâélément dont on veut la position 208 * @returns {number} - nombre de px entre le haut de la page et lâélément 209 */ 210 getOffsetTop(el) { 211 let offsetTop = 0; 212 while (el) { 213 offsetTop += el.offsetTop; 214 el = el.offsetParent; 215 } 216 return offsetTop; 217 } 218 219 /** 220 * Nettoie tous les écouteurs et restaure le style initial. 221 */ 222 destroy() { 223 window.removeEventListener('scroll', this.onScroll); 224 window.removeEventListener('resize', this.onResize); 225 226 // Suppression de la barre de progression du DOM si elle existe 227 if (this.progressBar && this.progressBar.parentNode) { 228 this.progressBar.parentNode.removeChild(this.progressBar); 229 } 230 231 this.reset(); 232 } 233 } 234 235 window.StickMe = StickMe; 236}(window, document)); 237;/*})'"*/;/*})'"*/ 238/* Source and licensing information for the line(s) below can be found at https://www.thierryphilip.fr/sites/all/themes/tfactory/js/init.js. */ 239(function($){jQuery(document).ready(function(){if(typeof scrollnav!=='undefined'){const content=document.querySelector('article.node-article');scrollnav.init(content,{insertLocation:'append',insertTarget:document.querySelector('div.custscroll-nav .inner'),sections:'h2'});
239var stickySidebar=new StickMe(document.querySelector('.stickthis'))}})})(jQuery);; 240/* Source and licensing information for the above line(s) can be found at https://www.thierryphilip.fr/sites/all/themes/tfactory/js/init.js. */;/*})'"*/
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.