PageSourceSearch

https://cdn.techniques-ingenieur.fr/lucy/ti/cdn.prod.v5.3.0/js/home-site.js

js techniques-ingenieur.fr collected 2026-09-24 09:16:56 UTC 13,597 bytes, 365 lines download raw bytes

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.