1$(document).ready(function () { 2 $(".zoning").click(function (a) { 3 if ($(this).find("a").attr("href") != undefined) window.location = $(this).find("a").attr("href") 4 return false; 5 }).css({ 6 cursor: "pointer" 7 }); 8 9 const $slider = $('#slider-home .slider-slides'); 10 const $sliderHome = $('#slider-home'); 11 const $bloc = $('#slider-home .bloc-container'); 12 const bgClasses = 'bg-1 bg-2 bg-3 bg-4'; 13 14 // -------------------------------------------------- 15 // SETUP : créer le background desktop UNE FOIS 16 // -------------------------------------------------- 17 let $desktopBg = $('#slider-home > .background-slider'); 18 19 if (!$desktopBg.length) { 20 $sliderHome.prepend('<div class="background-slider bg-1"></div>'); 21 $desktopBg = $('#slider-home > .background-slider'); 22 } 23 24 // -------------------------------------------------- 25 // UTILS 26 // -------------------------------------------------- 27 function isMobile() { 28 return window.matchMedia('(max-width: 768px)').matches; 29 } 30 31 function getBackgroundTarget() { 32 return isMobile() ? $bloc : $desktopBg; 33 } 34 35 // -------------------------------------------------- 36 // MODE MOBILE / DESKTOP (CLASSES SEULEMENT) 37 // -------------------------------------------------- 38 function handleBackgroundMode() { 39 40 if (isMobile()) { 41 // MOBILE 42 $desktopBg.removeClass('is-active'); 43 $bloc.addClass('background-slider is-active bg-1'); 44 45 } else { 46 // DESKTOP 47 $bloc.removeClass('background-slider is-active ' + bgClasses); 48 $desktopBg.addClass('is-active'); 49 } 50 } 51 52 // -------------------------------------------------- 53 // BACKGROUND SYNC 54 // -------------------------------------------------- 55 function setBackgroundBySlide(index) { 56 const $slide = $slider.find( 57 '.slick-slide[data-slick-index="' + index + '"]' 58 ); 59 60 const bgIndex = $slide.data('bg'); 61 if (!bgIndex) return; 62 63 const $target = getBackgroundTarget(); 64 $target.removeClass(bgClasses).addClass('bg-' + bgIndex); 65 } 66 67 // -------------------------------------------------- 68 // INIT 69 // -------------------------------------------------- 70 handleBackgroundMode(); 71 72 // Resize SAFE 73 $(window).on('resize', function () { 74 handleBackgroundMode(); 75 }); 76 77 // -------------------------------------------------- 78 // SLICK 79 // -------------------------------------------------- 80 let isSwiping = false; 81 82 $slider 83 .on('init', function (e, slick) { 84 setBackgroundBySlide(slick.currentSlide); 85 86 // rendre visible seulement quand prêt 87 $sliderHome.addClass('is-ready'); 88 }) 89 .on('beforeChange', function (e, slick, current, next) { 90 isSwiping = true; 91 setBackgroundBySlide(next); 92 }) 93 .on('afterChange', function () { 94 requestAnimationFrame(() => { 95 isSwiping = false; 96 }); 97 }) 98 .slick({ 99 swipe: true, 100 draggable: true, 101 touchMove: true, 102 slidesToScroll: 1, 103 infinite: true, 104 dots: false, 105 arrows: true, 106 autoplay: true, 107 autoplaySpeed: 4000, 108 speed: 1300, 109 pauseOnFocus: true, 110 fade: true, 111 slidesToShow: 1, 112 preventClicks: true, 113 preventClicksPropagation: true, 114 touchThreshold: 8, 115 responsive: [ 116 { 117 breakpoint: 768, 118 settings: { 119 arrows: false, 120 dots: true 121 } 122 } 123 ] 124 }) 125 .on('click', 'a, button, [data-clickable]', function (e) { 126 if (isSwiping) { 127 e.preventDefault(); 128 e.stopImmediatePropagation(); 129 } 130 }); 131}); 132 133document.addEventListener('DOMContentLoaded', () => { 134 let isSwiping = false;
135 136 // Vérifie si le slider doit être infini 137 const isInfinite = (slider, slidesToShow) => 138 slider.children.length > slidesToShow; 139 140 // Initialise Slick sur un slider donné 141 const initSlick = (slider, slidesToShow = 3) => { 142 $(slider) 143 .on('beforeChange', function () { 144 isSwiping = true 145 }) 146 .on('afterChange', function () { 147 setTimeout(() => { 148 isSwiping = false 149 }, 0) 150 }) 151 .slick({ 152 swipe: true, 153 draggable: true, 154 touchMove: true, 155 slidesToShow, 156 slidesToScroll: 1, 157 infinite: isInfinite(slider, slidesToShow), 158 dots: true, 159 autoplay: true, 160 arrows: false, 161 autoplaySpeed: 4000, 162 speed: 1300, 163 pauseOnFocus: true, 164 preventClicks: true, 165 preventClicksPropagation: true, 166 touchThreshold: 8, // équilibre desktop / mobile 167 responsive: [ 168 { breakpoint: 1200, settings: { slidesToShow: 2, slidesToScroll: 1, infinite: isInfinite(slider, 2) } }, 169 { breakpoint: 991, settings: { slidesToShow: 2, slidesToScroll: 1, infinite: isInfinite(slider, 2) } }, 170 { breakpoint: 767, settings: { slidesToShow: 1, slidesToScroll: 1, infinite: isInfinite(slider, 1) } }, 171 { breakpoint: 479, settings: { slidesToShow: 1, slidesToScroll: 1, infinite: isInfinite(slider, 1) } } 172 ] 173 }) 174 .on('click', 'a, button, [data-clickable]', function (e) { 175 if (isSwiping) { 176 e.preventDefault() 177 e.stopImmediatePropagation() 178 } 179 }); 180 }; 181 182 // Gère lâactivation des sliders selon leur type 183 const handleSlider = (slider) => { 184 const isMobileOnly = slider.classList.contains('mobile-only'); 185 let active = false; 186 187 const updateSlider = () => { 188 const width = window.innerWidth; 189 190 if (isMobileOnly) { 191 // Active seulement sous 768px 192 if (width < 768 && !active) { 193 initSlick(slider, 1); 194 active = true; 195 } else if (width >= 768 && active && $(slider).hasClass('slick-initialized')) { 196 $(slider).slick('unslick'); 197 active = false; 198 } 199 } else if (!active) { 200 // Toujours actif 201 initSlick(slider, 3); 202 active = true; 203 } 204 }; 205 206 updateSlider(); 207 window.addEventListener('resize', updateSlider); 208 }; 209 210 // Active tous les sliders 211 document.querySelectorAll('#third-part-content-page .slider-slides').forEach(handleSlider); 212 213 // --- ð Correction du bug Slick dans les tabs cachés --- 214 // Observer pour détecter quand un tab devient actif (class .active) 215 /*const observer = new MutationObserver(mutations => { 216 mutations.forEach(mutation => { 217 if (mutation.type === 'attributes' && mutation.attributeName === 'class') { 218 const tab = mutation.target; 219 if (tab.classList.contains('active')) { 220 // Forcer recalcul des sliders visibles dans ce tab 221 $(tab).find('.slider-slides.slick-initialized').slick('setPosition'); 222 } 223 } 224 }); 225 });*/ 226 227 // Observer tous les tab-contents 228 /*document.querySelectorAll('.tab-content').forEach(tab => { 229 observer.observe(tab, { attributes: true }); 230 });*/ 231 232 // Affiche les conteneurs 233 document.querySelectorAll('#third-part-content-page .slider').forEach(el => el.style.display = 'block'); 234}); 235 236document.addEventListener("DOMContentLoaded", () => { 237 document.querySelectorAll('.tabs').forEach(tabGroup => { 238 const tabContainer = tabGroup.querySelector('.tab-buttons'); 239 const buttons = tabGroup.querySelectorAll('.tab-button'); 240 const countButtons = buttons.length; 241 const contents = tabGroup.querySelectorAll('.tab-content'); 242 const offreHeader = document.querySelector('.offre-header'); 243 const stickyBloc = document.querySelector('.tab-buttons'); 244 const maxScroll = (offreHeader ? 164 : 0) + (stickyBloc?.offsetHeight || 0
244); 245 const initialActive = tabContainer.querySelector('.tab-button.active'); 246 const bgClasses = 'bg-1 bg-2 bg-3 bg-4'; 247 const desktopBg = $('#second-part-content-page .tabs > .tabs-background'); 248 if (initialActive) tabContainer.scrollTo({ left: initialActive.offsetLeft, behavior: 'auto' }); 249 250 buttons.forEach(btn => { 251 btn.addEventListener('click', () => { 252 buttons.forEach(b => b.classList.remove('active')); 253 contents.forEach(c => c.classList.remove('active')); 254 255 btn.classList.add('active'); 256 const target = tabGroup.querySelector(`#${btn.dataset.tab}`); 257 if (target) { 258 target.classList.add('active'); 259 260 if (desktopBg.length) { 261 const bgIndex = ((Number(btn.dataset.bg) - 1) % 4) + 1; 262 desktopBg.removeClass(bgClasses).addClass('bg-' + bgIndex); 263 } 264 /*const isInsideAssociated = tabGroup.closest('#associated-content') !== null; 265 266 if (!isInsideAssociated) { 267 const y = target.getBoundingClientRect().top + window.scrollY - maxScroll; 268 window.scrollTo({ top: y }); 269 }*/ 270 271 requestAnimationFrame(() => { 272 $(target).find('.slider-slides.slick-initialized').slick('setPosition'); 273 }); 274 } 275 276 const scrollLeft = btn.offsetLeft - (tabContainer.offsetWidth / 2) + (btn.offsetWidth / 2); 277 tabContainer.scrollTo({ left: scrollLeft, behavior: 'smooth' }); 278 }); 279 }); 280 }); 281}); 282 283function lazyload() { 284 const lazyImages = document.querySelectorAll('.lazy'); 285 286 // --- Fonction d'affichage d'une image --- 287 function showImage(img) { 288 const dataSrc = img.getAttribute('data-src'); 289 if (dataSrc) { 290 img.src = dataSrc; 291 img.classList.add('lazy-show'); 292 img.classList.remove('lazy'); 293 img.removeAttribute('data-src'); 294 295 // Effet fade-in 296 img.style.opacity = 0; 297 img.style.transition = 'opacity 0.6s ease'; 298 requestAnimationFrame(() => { 299 img.style.opacity = 1; 300 }); 301 } 302 } 303 304 // --- Initialisation de l'observer (si supporté) --- 305 if ('IntersectionObserver' in window) { 306 const observer = new IntersectionObserver((entries, obs) => { 307 entries.forEach(entry => { 308 if (entry.isIntersecting) { 309 const img = entry.target; 310 const tabContent = img.closest('.tab-content'); 311 const hasTabs = document.querySelector('.tab-content') !== null; 312 313 // Charge seulement si le tab est actif (ou sâil nây a pas de tabs) 314 if (!hasTabs || (tabContent && tabContent.classList.contains('active'))) { 315 showImage(img); 316 obs.unobserve(img); 317 } 318 } 319 }); 320 }, { 321 rootMargin: '150px 0px', 322 threshold: 0.01 323 }); 324 325 lazyImages.forEach(img => observer.observe(img)); 326 327 // --- Observer les changements d'état "active" sur les .tab-content --- 328 const tabContents = document.querySelectorAll('.tab-content'); 329 const tabObserver = new MutationObserver(mutations => { 330 mutations.forEach(mutation => { 331 if ( 332 mutation.attributeName === 'class' && 333 mutation.target.classList.contains('active') 334 ) { 335 // Quand un tab devient actif â charger ses images immédiatement 336 const imgs = mutation.target.querySelectorAll('.lazy'); 337 imgs.forEach(img => showImage(img)); 338 } 339 }); 340 }); 341 342 tabContents.forEach(tab => tabObserver.observe(tab, { attributes: true })); 343 344 } else { 345 // --- Fallback (scroll) pour anciens navigateurs --- 346 const fallback = () => { 347 document.querySelectorAll('.lazy').forEach(img => { 348 const rect = img.getBoundingClientRect(); 349 const tabContent = img.closest('.tab-content'); 350 const hasTabs = document.querySelector('.tab-content') !== null; 351 352 if (rect.top < window.innerHeight + 150 && rect.bottom > 0) { 353 if (!hasTabs || (tabContent && tabContent.classList.contains('active'))) { 354 showImage(img); 355 } 356 } 357 }); 358 }; 359 window.addEventListener('scroll', fallback); 360 window.addEventListener('resize', fallback); 361 document.addEventListener('DOMContentLoaded', fallback); 362 } 363} 364 365document.addEventListener('DOMContentLoaded', lazyload);
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.