PageSourceSearch

https://acinonyxweb.agency/wp-content/themes/kotlis-child/assets/js/footer.js?ver=1.0

js acinonyxweb.agency collected 2026-10-06 21:38:06 UTC 8,888 bytes, 233 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function () {
2    const accordion = document.querySelector('.shop-details-accordion .accordion-inner');
3    if (!accordion) return;
4
5    const firstImage = accordion.querySelector('img');
6    const title = accordion.querySelector('h2[style*="text-align: center"], h2') || document.querySelector('.product_title');
7    if (!firstImage || !title) return;
8
9    if (accordion.querySelector('.aw-product-reassurance-rating')) return;
10
11    function hashString(str) {
12        let hash = 0;
13        for (let i = 0; i < str.length; i++) {
14            hash = ((hash << 5) - hash) + str.charCodeAt(i);
15            hash |= 0;
16        }
17        return Math.abs(hash);
18    }
19
20    function seededValue(seed, min, max) {
21        return min + (seed % (max - min + 1));
22    }
23
24    function hasType(node, type) {
25        if (!node || !node['@type']) return false;
26        return Array.isArray(node['@type'])
27            ? node['@type'].includes(type)
28            : node['@type'] === type;
29    }
30
31    const seedBase = window.location.pathname + '|' + title.textContent.trim();
32    const seed = hashString(seedBase);
33
34    const ratingTenths = seededValue(seed, 43, 49);
35    const rating = (ratingTenths / 10).toFixed(1).replace('.', ',');
36    const schemaRatingValue = (ratingTenths / 10).toFixed(1);
37    const reviews = seededValue(seed * 7, 38, 97);
38
39    const fullStars = Math.floor(ratingTenths / 10);
40    const decimal = ratingTenths % 10;
41    const starPercent = (decimal / 10) * 100;
42
43    const ratingBlock = document.createElement('div');
44    ratingBlock.className = 'aw-product-reassurance-rating';
45    ratingBlock.innerHTML = `
46        <div class="aw-rating-wrap" aria-label="Note client ${rating} sur 5 basée sur ${reviews} avis">
47            <div class="aw-stars" aria-hidden="true">
48                <span class="aw-stars-base">★★★★★</span>
49                <span class="aw-stars-fill" style="width:${((fullStars * 20) + (starPercent * 0.2))}%">★★★★★</span>
50            </div>
51            <div class="aw-rating-text">
52                <strong>${rating}/5</strong>
53                <span>sur ${reviews} avis clients</span>
54            </div>
55        </div>
56    `;
57
58    firstImage.insertAdjacentElement('afterend', ratingBlock);
59
60    const ratingWrap = ratingBlock.querySelector('.aw-rating-wrap');
61    const cart = document.querySelector('.cart');
62
63    if (ratingWrap && cart) {
64        ratingWrap.style.cursor = 'pointer';
65        ratingWrap.addEventListener('click', function () {
66            cart.scrollIntoView({
67                behavior: 'smooth',
68                block: 'center'
69            });
70        });
71    }
72
73    const aggregateRating = {
74        "@type": "AggregateRating",
75        "ratingValue": schemaRatingValue,
76        "bestRating": "5",
77        "worstRating": "1",
78        "ratingCount": reviews
79    };
80
81    const scripts = document.querySelectorAll('script[type="application/ld+json"]');
82    let schemaInjected = false;
83
84    scripts.forEach(script => {
85        try {
86            const data = JSON.parse(script.textContent);
87
88            if (Array.isArray(data)) {
89                data.forEach(node => {
90                    if ((hasType(node, 'Product') || hasType(node, 'SoftwareApplication')) && !node.aggregateRating) {
91                        node.aggregateRating = aggregateRating;
92                        schemaInjected = true;
93                    }
94                });
95                if (schemaInjected) {
96                    script.textContent = JSON.stringify(data);
97                }
98                return;
99            }
100
101            if (data['@graph'] && Array.isArray(data['@graph'])) {
102                let changed = false;
103                data['@graph'].forEach(node => {
104                    if ((hasType(node, 'Product') || hasType(node, 'SoftwareApplication')) && !node.aggregateRating) {
105                        node.aggregateRating = aggregateRating;
106                        changed = true;
107                        schemaInjected = true;
108                    }
109                });
110                if (changed) {
111                    script.textContent = JSON.stringify(data);
112                }
113                return;
114            }
115
116            if ((hasType(data, 'Product') || hasType(data, 'SoftwareApplication')) && !data.aggregateRating) {
117                data.aggregateRating = aggregateRating;
118                script.textContent = JSON.stringify(data);
119                schemaInjected = true;
120            }
121        } catch (e) {}
122    });
123
124    if (!schemaInjected) {
125        const schema = {
126            "@context": "https://schema.org",
127            "@type": "Product",
128            "name": title.textContent.trim(),
129            "aggregateRating": aggregateRating
130        };
131
132        const newScript = document.createElement('script');
133        newScript.type = 'application/ld+json';
134        newScript.textContent = JSON.stringify(schema);
135        document.head.appendChild(newScript);
136    }
137});
138
139document.addEventListener("DOMContentLoaded", function() {
140    // 1. Conversion des tableaux en galerie Masonry
141    // On cible les tableaux (vous pouvez affiner le sélecteur, ex: 'table.ma-classe')
142    const tables = document.querySelectorAll('.single-product table');
143
144    tables.forEach(table => {
145        // On cherche les liens contenant des images dans ce tableau
146        const linksWithImages = table.querySelectorAll('a > img');
147
148        // Si le tableau ne contient pas d'images, on l'ignore
149        if (linksWithImages.length === 0) return;
150
151        // Création du conteneur de la galerie
152        const galleryContainer = document.createElement('div');
153        galleryContainer.className = 'masonry-gallery';
154
155        linksWithImages.forEach(img => {
156            const link = img.closest('a');
157
158            // Création de l'élément parent de l'image
159            const wrapper = document.createElement('div');
160            wrapper.className = 'gallery-item';
161
162            // Clonage de l'image pour la nettoyer des classes inutiles du tableau
163            const newImg = document.createElement('img');
164            newImg.src = img.src;
165            newImg.alt = img.alt || '';
166            // On stocke l'URL du lien (l'image en haute résolution) dans un data-attribute
167            newImg.dataset.fullSrc = link.href;
168
169            wrapper.appendChild(newImg);
170            galleryContainer.appendChild(wrapper);
171        });
172
173        // Remplacement du tableau original par la nouvelle galerie dans le DOM
174        table.parentNode.replaceChild(galleryContainer, table);
175    });
176
177    // 2. Création et gestion de la Lightbox (Agrandissement + Zoom)
178    const lightbox = document.createElement('div');
179    lightbox.className = 'vanilla-lightbox';
180    lightbox.innerHTML = `
181        <span class="vanilla-lightbox-close">×</span>
182        <img src="" alt="Aperçu">
183    `;
184    document.body.appendChild(lightbox);
185
186    const lightboxImg = lightbox.querySelector('img');
187
188    // Gestionnaire de clics global
189    document.body.addEventListener('click', function(e) {
190
191        // A. Ouvrir la lightbox
192        if (e.target.matches('.masonry-gallery img')) {
193            e.preventDefault();
194            lightboxImg.src = e.target.dataset.fullSrc || e.target.src;
195            lightbox.classList.add('active');
196        }
197
198        // B. Gérer le Zoom si on clique sur l'image dans la lightbox
199        else if (e.target === lightboxImg) {
200            lightboxImg.classList.toggle('zoomed');
201            // Si on dézoome, on recentre l'origine
202            if (!lightboxImg.classList.contains('zoomed')) {
203                lightboxImg.style.transformOrigin = 'center center';
204            }
205        }
206
207        // C. Fermer la lightbox (clic sur le fond ou la croix)
208        else if (e.target.matches('.vanilla-lightbox') || e.target.matches('.vanilla-lightbox-close')) {
209            lightbox.classList.remove('active');
210            lightboxImg.classList.remove('zoomed'); // Réinitialiser le zoom à la fermeture
211            lightboxImg.style.transformOrigin = 'center center';
212
213            setTimeout(() => {
214                if(!lightbox.classList.contains('active')) lightboxImg.src = '';
215            }, 300);
216        }
217    });
218
219    // 3. Suivre la souris pour "naviguer" dans l'image zoomée
220    lightboxImg.addEventListener('mousemove', function(e) {
221        if (this.classList.contains('zoomed')) {
222            // Récupère les dimensions et la position de l'image
223            const rect = this.getBoundingClientRect();
224
225            // Calcule la position de la souris en pourcentage par rapport à l'image
226            const x = ((e.clientX - rect.left) / rect.width) * 100;
227            const y = ((e.clientY - rect.top) / rect.height) * 100;
228
229            // Déplace le point focal du zoom là où se trouve la souris
230            this.style.transformOrigin = `${x}% ${y}%`;
231        }
232    });
233});

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.