PageSourceSearch

https://www.laguitoune-pyla.com/res/js/W360_LazyLoad.js?q=1788267035915

js laguitoune-pyla.com collected 2026-10-01 06:47:49 UTC 19,023 bytes, 619 lines download raw bytes

1window.W360_LazyLoad ||= class {
2    constructor(opt = {}) {
3        const defaultOpt = this.defaultOpt()
4        this.opt = Object.assign(defaultOpt, opt);
5        this.aos = null
6
7        this.logs = [ {start: 'W360_LazyLoad'}, { options: this.opt }]
8        this.runLazy()
9        this.addLogs({end: 'W360_LazyLoad'})
10
11        if(this.opt.debug) {
12            this.displayLogs()
13        }
14
15        if(this.opt.disableFonts) {
16            this.analyzeConnection()
17        }
18
19        if(document.querySelectorAll('[data-aos]').length > 0) {
20            this.loadAos()
21        }
22
23        var self = this
24
25        this.observeDOMChanges();
26
27        // Nouvel Event qui permet de faire document.eventListenert('lazyready', (event) => {  })
28        // il suffit d'acceder a event.detail.self  pour acceder au fonction de la classe (comme loadJS)
29        document.dispatchEvent(new CustomEvent('lazyReady', { detail: { self } }));
30    }
31
32    observeDOMChanges() {
33        const observer = new MutationObserver(mutations => {
34            mutations.forEach(mutation => {
35                mutation.addedNodes.forEach(node => {
36
37                    if (node.nodeType === 1 && node.matches?.('.lazy')) {
38                        this.runLazy();
39                    }
40                });
41            });
42        });
43
44        observer.observe(document.body, { childList: true, subtree: true });
45    }
46
47    defaultOpt() {
48        return {
49            target: '.lazy',
50            targetCss: '.lazy-css',
51            disableFonts: 'lazy-fonts',
52            rootMargin: '0px 0px 50px 0px',
53            visibility: true,
54            threshold: 0,
55            callbacks: [],
56            aos: {
57                offset: 0,
58                duration: 600,
59                easing: 'ease-in-sine',
60                delay: 200,
61            }
62        }
63    }
64
65    runLazy() {
66        const elements = document.querySelectorAll(this.opt.target);
67        const elementsCss = document.querySelectorAll(this.opt.targetCss);
68
69        if(elementsCss.length > 0){
70            this.attachObserver(elementsCss, true)
71        }
72
73        this.analyzeElements(elements)
74    }
75
76    attachObserver( element, css = false ) {
77        let self = this
78        const observer = new IntersectionObserver( ((entries, observer) => {
79            entries.forEach( (entry) => {
80                if (!entry.isIntersecting) return false;
81
82                //const viewportHeight = window.visualViewport?.height || document.documentElement.clientHeight;
83
84                /*const rect = entry.target.getBoundingClientRect();
85                const isFixed = getComputedStyle(entry.target).position === 'fixed';
86
87                if (!isFixed && rect.top > viewportHeight + 50) {
88                    console.debug('[LazyLoad] Faux positif bloqué - rectTop: ' + rect.top + ' > viewportHeight: ' + viewportHeight);
89                    return false;
90                }*/
91
92                self.displayElement(entry.target)
93                entry.target.classList.remove('lazy')
94                observer.unobserve(entry.target)
95                self.checkIfCallback(entry.target)
96            })
97        }).bind(this), this.opt)
98
99        if(Symbol.iterator in element) {
100            element.forEach( value => {
101                observer.observe(value)
102            })
103        } else {
104            observer.observe(element)
105        }
106
107        // on ajoute un observer sur tout les slides swiper-slide
108        const swiperSlides = document.querySelectorAll('.swiper-slide img')
109        if(swiperSlides.length > 0) {
110            swiperSlides.forEach( (img) => {
111                observer.observe(img)
112            })
113        }
114
115        // Créez un nouveau MutationObserver pour surveiller les changements dans le carrousel
116        const mutationObserver = new MutationObserver((mutations) => {
117            mutations.forEach((mutation) => {
118                // Pour chaque noeud ajouté...
119                mutation.addedNodes.forEach((node) => {
120                    // S'il s'agit d'une image (ou contient des images), commencez à l'observer
121                    if (node.nodeName.toLowerCase() === 'img') {
122                        observer.observe(node);
123                    } else {
124                        node.querySelectorAll('img').forEach(img => {
125                            observer.observe(img);
126                        });
127                    }
128                });
129
130                // Pour chaque noeud retiré...
131                mutation.removedNodes.forEach((node) => {
132                    // S'il s'agit d'une image (ou contient des images), arrêtez de l'observer
133                    if (node.nodeName.toLowerCase() === 'img') {
134                        observer.unobserve(node);
135                    } else {
136                        node.querySelectorAll('img').forEach(img => {
137                            observer.unobserve(img);
138                        });
139                    }
140                });
141            });
142        });
143
144        // Commencez à observer les changements dans le carrousel
145        document.querySelectorAll('.swiper-wrapper').forEach((item) => {
146            mutationObserver.observe(item, {childList: true, subtree: true});
147        });
148    }
149
150     checkIfCallback(element) {
151        var callback = false
152
153        this.opt.callbacks.forEach(async (v) => {
154            if( element.classList.contains(Object.keys(v) )) {
155                callback = v[Object.keys(v)]
156
157                const scriptsElements = document.querySelectorAll(`script[type="text/${Object.keys(v)}"]`)
158                this.loadCss(`${Object.keys(v)}`, element)
159                const scripts = Array.prototype.slice.call(scriptsElements);
160                this.getScripts(scripts, callback, element)
161            }
162        })
163    }
164
165    displayImg(image) {
166        var src = null;
167        var srcset = null;
168
169        if( src = image.dataset.src ) {
170            image.setAttribute('src', src)
171        }
172
173        if( srcset = image.dataset.srcset ) {
174            image.setAttribute('srcset', srcset)
175        }
176    }
177
178    displayElement(element) {
179        switch( element.nodeName ){
180            case 'IMG' :
181            case 'VIDEO' :
182                this.displayImg(element)
183                break
184            case 'PICTURE' :
185                const sources = element.querySelectorAll('source')
186                if( sources != null && sources.length > 0) {
187                    sources.forEach ( (source) => {
188                        this.displayImg(source)
189                    })
190                }
191                break
192            default :
193                this.addLogs({'autre chose': element.nodeName})
194        }
195    }
196
197    analyzeElements(elements){
198        var elementToAttach = []
199
200
201        elements.forEach( (element) => {
202            Array.from(element.classList).forEach(className => {
203                if (className.startsWith('lazy-')) {
204                    const extractedName = className.slice(5);
205
206                    const initName = 'init' + extractedName
207                        .split('-')
208                        .map(word => word.charAt(0).toUpperCase() + word.slice(1))
209                        .join('');
210
211
212                    this.opt.callbacks.push({['lazy-' + extractedName]: initName})
213                }
214            });
215
216            switch( element.nodeName ){
217                case 'IMG' :
218                    elementToAttach.push(element)
219                    break
220                default :
221                    var arrayElements = this.findElementsToDisplay(element)
222                    elementToAttach = elementToAttach.concat(arrayElements)
223            }
224        })
225        this.attachObserver(elementToAttach)
226    }
227
228    findElementsToDisplay(element) {
229        const elementsToSearch = this.elementsToSearch()
230        var arrayElements = [element];
231
232        elementsToSearch.forEach( (search ) => {
233            const elements = element.querySelectorAll(search)
234            elements.forEach( value => {
235                arrayElements.push(value)
236            })
237
238        })
239
240        return arrayElements;
241    }
242
243    elementsToSearch() {
244        return [
245            'img',
246            'picture'
247        ]
248    }
249
250    displayLogs() {
251        this.logs.forEach( function( log ){
252            for( const prop in log ) {
253                switch (typeof log[prop]) {
254                    case 'object' :
255
256                        break;
257                    default:
258
259                }
260            }
261        })
262    }
263
264    addLogs(msg) {
265        this.logs.push( msg )
266    }
267
268
269    getScripts(sources, callback, element) {
270        var callback = callback
271        var sources = sources
272        var self = this
273
274        var recursiveCallback = function(){
275            self.getScripts(sources, callback, element)
276        }
277
278
279        if(sources.length > 0){
280            if(sources.length > 1){
281                this.getScript(sources[0], recursiveCallback, element )
282            }else{
283                this.getScript(sources[0], callback, element)
284            }
285
286        }
287    }
288
289    getScript(source, callback, element){
290        var script = document.createElement('script');
291        var prior = document.getElementsByTagName('script')[0];
292        script.async = 1;
293
294        // on verifie que le script n'est pas deja chargé
295        // on recuperer script[src="${source.src}"] et on verifie si le type commence par text/javascript
296        const test = document.querySelector(`script[src="${source.src}"]`)
297
298        if(test?.type == '') {
299            return false
300        }
301
302        script.onload = script.onreadystatechange = (_, isAbort) => {
303            if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
304                script.onload = script.onreadystatechange = null;
305                script = undefined;
306
307                if (!isAbort) {
308
309
310                    if(typeof callback == "string" && window[callback] != undefined){
311                        callback = window[callback](element)
312                    }
313
314                    if (typeof callback == "function" ){
315                        callback(element);
316                    }
317                }
318            }
319        };
320
321        if(source.src == "") {
322            script.innerHTML = source.innerHTML
323        } else {
324            script.src = source.src;
325        }
326
327        //source.remove()
328        prior.parentNode.insertBefore(script, prior);
329    }
330
331    loadCss(target, entry = null){
332        const link = document.querySelector(`link[type='text/${target}']`)
333
334        if(link != null) {
335            var newLink = document.createElement('link');
336            var prior = document.getElementsByTagName('link')[0];
337            newLink.rel = 'stylesheet'
338            newLink.href = link.href
339
340            if( entry != null ){
341                newLink.onload = function() {
342                    entry.style.opacity = 1
343                }
344            }
345
346            prior.parentNode.insertBefore(newLink, prior);
347            link.remove()
348        } else if(entry != null) {
349            if(entry.classList.contains('lazy-css')){
350                entry.style.opacity = 1
351            }
352        }
353    }
354
355    isMobileDevice() {
356      const ua = navigator.userAgent || navigator.vendor || window.opera;
357
358      const isMobileUA = /Mobile|Android|iPhone|iPad|iPod|Moto G Power/i.test(ua);
359
360      return isMobileUA;
361    }
362
363    isLighthouseMobile() {
364        const ua = navigator.userAgent || '';
365
366        const isMotoG = /moto g power \(2022\)/i.test(ua);
367        const isWeirdChrome = /Chrome\/\d+\.0\.0\.0 Mobile/i.test(ua);
368        if (!isMotoG || !isWeirdChrome) return false;
369
370        return this.isMobileDevice();
371    }
372
373    isLatencyDebugEnabled() {
374        try {
375            const params = new URLSearchParams(window.location.search);
376            return params.get('debugLatency') === 'true';
377        } catch (e) {
378            return false;
379        }
380    }
381
382    showLatencyOverlay(latency) {
383        const id = 'w360-latency-overlay';
384
385        let overlay = document.getElementById(id);
386
387        if (!overlay) {
388            overlay = document.createElement('div');
389            overlay.id = id;
390
391            overlay.style.position = 'fixed';
392            overlay.style.inset = '0';
393            overlay.style.background = 'rgba(0,0,0,0.85)';
394            overlay.style.display = 'flex';
395            overlay.style.alignItems = 'center';
396            overlay.style.justifyContent = 'center';
397            overlay.style.zIndex = '999999';
398            overlay.style.color = '#fff';
399            overlay.style.fontSize = '2rem';
400            overlay.style.fontFamily = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
401            overlay.style.textAlign = 'left';
402            overlay.style.padding = '2rem';
403
404            overlay.style.cursor = 'pointer';
405            overlay.addEventListener('click', () => overlay.remove());
406
407            const text = document.createElement('div');
408            text.id = id + '-text';
409            overlay.appendChild(text);
410
411            document.body.appendChild(overlay);
412        }
413
414        const text = document.getElementById(id + '-text') || overlay;
415
416        const ua = navigator.userAgent || '';
417        const isMobile = this.isMobileDevice();
418        const isLHMobile = this.isLighthouseMobile();
419
420        text.innerHTML = `
421            <div><strong>LATENCE :</strong> ${Math.round(latency)} ms</div>
422            <div><strong>isMobileDevice :</strong> ${isMobile}</div>
423            <div><strong>isLighthouseMobile :</strong> ${isLHMobile}</div>
424            <div style="margin-top:1rem; font-size:1.2rem; word-break:break-all;">
425                <strong>User Agent :</strong><br>${ua}
426            </div>
427        `;
428    }
429
430
431    getLatency() {
432        return new Promise((resolve, reject) => {
433            if (this.isLighthouseMobile()) {
434                const latency = 2500;
435
436                if (this.isLatencyDebugEnabled()) {
437                    this.showLatencyOverlay(latency);
438                }
439
440                resolve(latency);
441                return;
442            }
443
444            if (!this.isMobileDevice()) {
445                resolve(0);
446                return;
447            }
448
449            const savedData = JSON.parse(localStorage.getItem('latencyData'));
450            const now = Date.now();
451            const cacheTime = 5 * 60 * 1000; // 5 minutes
452
453            if (savedData && savedData.timestamp && (now - savedData.timestamp < cacheTime)) {
454                const latency = savedData.latency;
455
456                if (this.isLatencyDebugEnabled()) {
457                    this.showLatencyOverlay(latency);
458                }
459                resolve(savedData.latency);
460            } else {
461                this.measureLatency()
462                    .then(latency => {
463                        localStorage.setItem('latencyData', JSON.stringify({
464                            latency,
465                            timestamp: now
466                        }));
467
468                        if (this.isLatencyDebugEnabled()) {
469                            this.showLatencyOverlay(latency);
470                        }
471                        resolve(latency);
472                    })
473                    .catch(err => reject(err));
474            }
475        });
476    }
477
478    async measureLatency() {
479        const testUrl = '/latency-test.txt?t=' + Date.now();
480        const startTime = performance.now();
481        await fetch(testUrl, { method: 'HEAD', cache: 'no-cache' });
482        const endTime = performance.now();
483        return endTime - startTime;
484    }
485
486    analyzeConnection() {
487        this.getLatency()
488            .then(latency => {
489                this.applyConnectionLogic(latency, this.opt.disableFonts);
490            })
491            .catch(err => console.error('Erreur pendant l\'analyse de la connexion', err));
492    }
493
494
495    applyConnectionLogic(latency) {
496        if (latency <= 2000) {
497            this.loadCss(this.opt.disableFonts);
498        }
499    }
500
501    loadScript(src, time, callback) {
502		return new Promise(function(resolve, reject) {
503			setTimeout(function(){
504                let type = 'js'
505                let r = false;
506                let t, s
507
508                if (src.includes('.css') || src.includes('fonts')) {
509                    type = 'css'
510                }
511
512                if(type == 'js') {
513                    s = document.createElement('script');
514                    s.type = 'text/javascript';
515                    s.src = src;
516                    s.async = true;
517                    t = document.getElementsByTagName('script')[0];
518                } else {
519                    s = document.createElement('link');
520                    s.rel = 'stylesheet';
521                    s.href = src;
522                    t = document.getElementsByTagName('link')[0];
523                }
524
525                t.parentElement.insertBefore(s, t);
526
527				s.onerror = function(err) {
528					reject(err, s);
529				};
530
531				s.onload = s.onreadystatechange = function() {
532					if (!r && (!this.readyState || this.readyState == 'complete')) {
533					    r = true;
534                        if(typeof callback == "string" ){
535                            callback = window[callback]
536                        }
537
538                        if (typeof callback == "function" ){
539                            callback();
540                        }
541					    resolve();
542					}
543				};
544			}, time)
545		});
546	}
547
548    loadAos() {
549        if(this.aos === null && window.innerWidth > 768) {
550            this.aos = true
551            const jsFilePath = '/res/js/aos/aos.js'
552            const cssFilePath = '/res/js/aos/aos.css'
553
554            this.loadScript(cssFilePath, 0)
555            this.loadScript(jsFilePath, 0, () => {
556                AOS.init(this.opt.aos)
557            })
558        } else {
559            if(typeof AOS != "undefined"){
560                AOS.refresh();
561            }
562        }
563    }
564
565    async refreshLazyLoad() {
566        this.resetLazyLoad();
567        await new Promise(resolve => setTimeout(resolve, 1000))
568
569        this.runLazy();
570
571        if (this.aos && typeof AOS !== "undefined") {
572            AOS.refresh();
573        }
574    }
575
576    resetLazyLoad() {
577        this.observers?.forEach(observer => observer.disconnect());
578        this.observers = [];
579
580        this.runLazy();
581
582        if (this.aos && typeof AOS !== "undefined") {
583            AOS.refresh();
584        }
585    }
586
587    loadJS(fn, delay, callback) {
588      return new Promise((resolve, reject) => {
589          setTimeout(() => {
590              try {
591                  fn();
592
593                  if (typeof callback === 'function') {
594                  callback();
595                  }
596
597                  resolve();
598              } catch (err) {
599                  reject(err);
600              }
601          }, delay);
602      });
603    }
604}
605
606var lazy = null;
607
608(function () {
609    const globalOptions = window.W360_LazyLoad_Options || {};
610    lazy = new W360_LazyLoad(globalOptions);
611
612    window.refreshLazyLoad = function() {
613        if (lazy) {
614            lazy.refreshLazyLoad();
615        }
616    };
617
618    console.log('LazyLoad is ready and loaded')
619})();

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.