PageSourceSearch

https://www.sanvenero.com/wp-content/themes/sanvenero_eg/js/main.js?ver=1.4.24

js sanvenero.com collected 2026-10-06 00:36:14 UTC 34,250 bytes, 1,032 lines download raw bytes

1( () => {
2    const radios = document.querySelectorAll( `[data-radio-uncheckable="true"]` )
3
4    radios.forEach( ( radio ) => {
5        radio.addEventListener( "click", function ( event ) {
6            event.preventDefault()
7            if ( this.checked ) {
8                this.checked = false
9            }
10        } )
11
12        const labels = document.querySelectorAll( `label[for="${radio.id}"]` )
13
14        labels.forEach( ( label ) => {
15            label.addEventListener( "click", function ( event ) {
16                event.preventDefault()
17                radio.checked = !radio.checked
18            } )
19        } )
20    } )
21} )()
22
23const firstSectionButtons = document.querySelectorAll( "button[data-first-section]" )
24firstSectionButtons.forEach( ( btn ) => {
25    const firstSection = document.querySelector( "section.hero + section" )
26    if ( !firstSection ) {
27        btn.remove()
28        return
29    }
30
31    btn.addEventListener( "click", () => {
32        window.scrollTo( {
33            top: window.scrollY + firstSection.getBoundingClientRect().top,
34            left: 0,
35            behavior: "smooth",
36        } )
37    } )
38} )
39
40// to close dialogs on click outside
41const dialogs = document.querySelectorAll( "dialog" )
42dialogs.forEach( ( dialog ) => {
43    dialog.addEventListener( "click", () => {
44        dialog.close()
45        document.body.classList.remove( "overflow-hidden" )
46    } )
47
48    const contentWrapper = dialog.querySelector( ".dialog-content-wrapper" )
49    contentWrapper?.addEventListener( "click", ( e ) => {
50        e.stopPropagation()
51    } )
52} );
53
54// NEWSLETTER DIALOG
55( () => {
56    const dialog = document.querySelector( "#sales-dialog" )
57    const localStorageID = "sales-popup-opened-v2"
58    const sessionStorageID = "sales-popup-pageviews"
59    if ( localStorage.getItem( localStorageID ) ) return
60
61    // il popup non esce sulla prima pagina della sessione, ma dal primo cambio pagina in poi
62    const pageViews = Number( sessionStorage.getItem( sessionStorageID ) || 0 ) + 1
63    sessionStorage.setItem( sessionStorageID, pageViews )
64    if ( pageViews < 2 || !dialog ) return
65
66    const closeBtn = dialog.querySelector( ".close-btn" )
67    if ( closeBtn ) {
68        closeBtn.addEventListener( "click", () => {
69            dialog.close()
70            document.body.classList.remove( "overflow-hidden" )
71        } )
72    }
73
74    document.body.classList.add( "overflow-hidden" )
75    dialog.showModal()
76    localStorage.setItem( localStorageID, "true" )
77} )()
78
79// SWIPER
80const heroFullScreenSwiper = new Swiper( ".hero-fullscreen .swiper", {
81    loop: true,
82    grabCursor: true,
83    autoplay: {
84        delay: 3500,
85        disableOnInteraction: false,
86    },
87    speed: 1500,
88    pagination: {
89        el: ".hero-fullscreen .swiper-pagination",
90        clickable: true,
91    },
92} )
93
94const heroImagesSwiper = new Swiper( ".hero-images .swiper", {
95    enabled: true,
96    loop: true,
97    grabCursor: true,
98    autoplay: {
99        delay: 2500,
100        disableOnInteraction: false,
101        speed: 1000,
102    },
103    pagination: {
104        el: ".hero-images .swiper-pagination",
105        clickable: true,
106    },
107    breakpoints: {
108        768: {
109            enabled: false,
110        },
111    },
112} )
113
114const reviewsSwiper = new Swiper( "section.reviews .swiper", {
115    slidesPerView: 1,
116    grabCursor: true,
117    autoplay: {
118        delay: 8500,
119        disableOnInteraction: false,
120    },
121    speed: 1000,
122    pagination: {
123        el: "section.reviews .swiper .swiper-pagination",
124        clickable: true,
125    },
126    effect: "fade",
127} )
128
129const productGallery = new Swiper( "section.single-product .swiper-product-gallery", {
130    slidesPerView: 1,
131    spaceBetween: 20,
132    pagination: {
133        el: "section.single-product .swiper-product-gallery .swiper-pagination",
134    },
135} )
136
137const rowRepeaterImages = new Swiper( "section.row.row-repeater-images .swiper", {
138    slidesPerView: 1,
139    spaceBetween: 0,
140    enabled: true,
141    pagination: {
142        el: "section.row.row-repeater-images .swiper .swiper-pagination",
143    },
144    breakpoints: {
145        768: {
146            enabled: false,
147        },
148    },
149} )
150
151const relatedProducts = new Swiper( "section.product-related-products .swiper", {
152    slidesPerView: 1.25,
153    freeMode: true,
154    spaceBetween: 10,
155    breakpoints: {
156        768: {
157            enabled: false,
158        },
159    },
160} )
161
162// GSAP
163window.addEventListener( "load", () => {
164    let gsapLoaded = false
165    while ( !gsapLoaded ) {
166        document.body.classList.add( "loading-gsap" )
167        if ( gsap ) {
168            document.body.classList.remove( "loading-gsap" )
169            gsapLoaded = true
170        }
171    }
172
173    gsap.registerEffect( {
174        name: "floatY",
175        effect: ( targets, config ) => {
176            if ( !config.trigger ) {
177                console.warn( { targets: targets, warning: "Had no trigger" } )
178                return
179            }
180            return gsap.fromTo(
181                targets,
182                { y: config.startY },
183                {
184                    y: config.endY,
185                    scrollTrigger: {
186                        start: "top-=0% bottom-=20%",
187                        end: "center bottom-=5%",
188                        trigger: config.trigger,
189                        scrub: 1,
190                    },
191                },
192            )
193        },
194        extendTimeline: true,
195        defaults: {
196            startY: -25,
197            endY: 0,
198        },
199    } )
200
201    gsap.registerEffect( {
202        name: "scaler",
203        effect: ( targets, config ) => {
204            if ( !config.trigger ) {
205                console.warn( { targets: targets, warning: "Had no trigger" } )
206                return
207            }
208            return gsap.fromTo(
209                targets,
210                { scale: config.startScale },
211                {
212                    scale: config.endScale,
213                    scrollTrigger: {
214                        start: "top bottom-=20%",
215                        end: "bottom bottom-=20%",
216                        trigger: config.trigger,
217                        scrub: 1,
218                    },
219                },
220            )
221        },
222        defaults: {
223            startScale: 1.1,
224            endScale: 1,
225        },
226        extendTimeline: true,
227    } )
228
229    gsap.registerEffect( {
230        name: "fade",
231        effect: ( targets, config ) => {
232            if ( !config.trigger ) {
233                console.warn( { targets: targets, warning: "Had no trigger" } )
234                return
235            }
236            gsap.set( targets, { opacity: 0, y: config.startY } )
237            return gsap.to( targets, {
238                opacity: 1,
239                y: 0,
240                stagger: config.stagger,
241                scrollTrigger: {
242                    start: config.start,
243                    trigger: config.trigger,
244                    markers: config.markers,
245                },
246            } )
247        },
248        defaults: { startY: -20, stagger: 0.2, markers: false, start: "top bottom-=20%" },
249        extendTimeline: true,
250    } )
251
252    document.querySelectorAll( ".gsap-scaler-trigger" ).forEach( ( scalerTrigger ) => {
253        const query = scalerTrigger.dataset?.gsapScalerTriggerSelector ? scalerTrigger.dataset?.gsapScalerTriggerSelector : ".gsap-scaler"
254        const scalers = scalerTrigger.querySelectorAll( query )
255        scalers.forEach( ( scaler ) => {
256            const scalerConfig = {
257                trigger: scalerTrigger,
258            }
259
260            if ( scaler.dataset.gsapScalerStartScale ) {
261                scalerConfig.startScale = scaler.dataset.gsapScalerStartScale
262            }
263
264            gsap.effects.scaler( scaler, scalerConfig )
265        } )
266    } )
267
268    document.querySelectorAll( ".gsap-fader" ).forEach( ( fader ) => {
269        let selector = fader.children
270        const faderConfig = {
271            trigger: fader,
272        }
273
274        if ( fader.dataset.gsapFaderSelector ) {
275            const htmlElements = document.querySelectorAll( fader.dataset.gsapFaderSelector )
276
277            if ( htmlElements.length ) {
278                selector = htmlElements
279            } else {
280                console.warn( "The fader.dataset.gsapFaderSelector had no elements to target:", fader )
281            }
282        }
283
284        if ( fader.dataset.gsapFaderStartY ) {
285            faderConfig.startY = fader.dataset.gsapFaderStartY
286        }
287
288        gsap.effects.fade( selector, faderConfig )
289    } )
290
291    document.querySelectorAll( ".gsap-float-trigger" ).forEach( ( floatTrigger ) => {
292        const query = floatTrigger.dataset.gsapFloatTriggerSelector ? floatTrigger.dataset.gsapFloatTriggerSelector : ".gsap-float-y"
293        const floaters = floatTrigger.querySelectorAll( query )
294        floaters.forEach( ( floater ) => {
295            const floaterConfig = {
296                trigger: floatTrigger,
297            }
298
299            if ( floater.dataset.gsapFloatStartY ) {
300                floaterConfig.startY = floater.dataset.gsapFloatStartY
301            }
302
303            gsap.effects.floatY( floater, floaterConfig )
304        } )
305    } )
306} )
307
308// --------------------------------------------------------------------
309window.initMap = async () => {
310    const iconDims = {
311        width: 31.4,
312        height: 44.35,
313    }
314
315    const mapInitializers = Array.from( document.querySelectorAll( ".eg-google-map" ) ).map( async ( mapContainer ) => {
316        const { Map, Marker, InfoWindow, Size, LatLngBounds, Animation } = google.maps
317
318        const { defaults, pinIcons } = egGoogleMapsData || {
319            defaults: {},
320            pinIcons: {},
321        }
322        const markersData = mapContainer.dataset.markersData ? JSON.parse( atob( mapContainer.dataset.markersData ) ) : []
323
324        console.log( "markers", markersData )
325
326        // inizializzo la mappa
327        const map = new Map( mapContainer, {
328            center: {
329                lat: defaults?.lat || 45.4627042,
330                lng: defaults?.lng || 9.0953321,
331            },
332            zoom: defaults?.zoom || 12,
333            disableDefaultUI: true,
334            controlSize: 24,
335            zoomControl: true,
336
337            minZoom: 4, // Set a minimum zoom level
338            maxZoom: 17, // Set a maximum zoom level
339
340            styles: [
341                {
342                    featureType: "administrative",
343                    elementType: "labels.text.fill",
344                    stylers: [
345                        {
346                            color: "#444444",
347                        },
348                    ],
349                },
350                {
351                    featureType: "landscape",
352                    elementType: "all",
353                    stylers: [
354                        {
355                            color: "#f2f2f2",
356                        },
357                    ],
358                },
359                {
360                    featureType: "landscape.natural.terrain",
361                    elementType: "all",
362                    stylers: [
363                        {
364                            color: "#004a42",
365                        },
366                    ],
367                },
368                {
369                    featureType: "poi",
370                    elementType: "all",
371                    stylers: [
372                        {
373                            visibility: "off",
374                        },
375                    ],
376                },
377                {
378                    featureType: "road",
379                    elementType: "all",
380                    stylers: [
381                        {
382                            saturation: -100,
383                        },
384                        {
385                            lightness: 45,
386                        },
387                    ],
388                },
389                {
390                    featureType: "road.highway",
391                    elementType: "all",
392                    stylers: [
393                        {
394                            visibility: "simplified",
395                        },
396                    ],
397                },
398                {
399                    featureType: "road.arterial",
400                    elementType: "labels.icon",
401                    stylers: [
402                        {
403                            visibility: "off",
404                        },
405                    ],
406                },
407                {
408                    featureType: "transit",
409                    elementType: "all",
410                    stylers: [
411                        {
412                            visibility: "off",
413                        },
414                    ],
415                },
416                {
417                    featureType: "water",
418                    elementType: "all",
419                    stylers: [
420                        {
421                            color: "#DBD1C0",
422                        },
423                        {
424                            visibility: "on",
425                        },
426                    ],
427                },
428            ],
429        } )
430
431        // const service = new google.maps.places.PlacesService(map)
432
433        // const getPlaceDetails = placeId =>
434        //   new Promise((resolve, reject) => {
435        //     service.getDetails(
436        //       {
437        //         placeId
438        //       },
439        //       function (place, status) {
440        //         if (status === google.maps.places.PlacesServiceStatus.OK) {
441        //           // Qui puoi utilizzare le informazioni del luogo
442        //           resolve(place)
443        //         }
444
445        //         reject(status)
446        //       }
447        //     )
448        //   })
449
450        // dimensioni dell'icona
451        const scaledSize = new Size( iconDims.width, iconDims.height )
452
453        // serve per centrare la mappa su tutti i marker
454        const bounds = new LatLngBounds()
455
456        // creo i marker
457        const markers = markersData.map( ( markerData ) => {
458            const { position } = markerData
459
460            // const placeDetails = await getPlaceDetails(position.place_id)
461
462            // console.log(placeDetails)
463
464            const marker = new Marker( {
465                position,
466                map,
467                title: `${( markerData.title || position.city || "" ).toUpperCase()} (${( position?.state_short || "" ).toUpperCase()})`,
468                // title: `${position.city.toUpperCase()} (${position.state_short})`,
469                icon: {
470                    url: pinIcons.default,
471                    scaledSize,
472                },
473            } )
474
475            // aggiungo l'info window se presente contenuto
476            if ( markerData.infoWindow ) {
477                marker.infoWindow = new InfoWindow( {
478                    content: markerData.infoWindow,
479                } )
480
481                // al click del marker apro l'info window e chiudo le altre
482                marker.addListener( "click", () => {
483                    markers.forEach( ( lMarker ) => {
484                        if ( lMarker === marker ) {
485                            // lMarker.setAnimation(google.maps.Animation.BOUNCE)
486
487                            lMarker.infoWindow.open( map, lMarker )
488
489                            lMarker.setIcon( {
490                                url: pinIcons.active,
491                                scaledSize,
492                            } )
493                        } else {
494                            // lMarker.setAnimation(null)
495
496                            lMarker.infoWindow?.close()
497
498                            lMarker.setIcon( {
499                                url: pinIcons.default,
500                                scaledSize,
501                            } )
502                        }
503                    } )
504                } )
505
506                // al click sulla x dell'info window ripristino l'icona di default e annullo l'animazione (se presente)
507                marker.infoWindow.addListener( "closeclick", () => {
508                    marker.setIcon( {
509                        url: pinIcons.default,
510                        scaledSize,
511                    } )
512
513                    marker.setAnimation( null )
514                } )
515
516                // cerco nella pagina tutti i link che puntano a questo marker e ci aggiungo l'evento click
517                document.querySelectorAll( `[data-id="${markerData.id}"]` ).forEach( ( link ) => {
518                    link.addEventListener( "click", ( e ) => {
519                        e.preventDefault()
520
521                        markers.forEach( ( lMarker ) => {
522                            if ( lMarker === marker ) {
523                                lMarker.setAnimation( Animation.BOUNCE )
524                                setTimeout( () => lMarker.setAnimation( null ), 2000 )
525
526                                lMarker.infoWindow.open( map, lMarker )
527
528                                lMarker.setIcon( {
529                                    url: pinIcons.active,
530                                    scaledSize,
531                                } )
532                            } else {
533                                lMarker.setAnimation( null )
534
535                                lMarker.infoWindow?.close()
536
537                                lMarker.setIcon( {
538                                    url: pinIcons.default,
539                                    scaledSize,
540                                } )
541                            }
542                        } )
543
544                        smoothScrollTo( mapContainer, 600, parseInt( document.documentElement.style.getPropertyValue( "--header-height" ) || 200 ) )
545                    } )
546                } )
547            }
548
549            // aggiungo il marker ai bounds
550            bounds.extend( marker.getPosition() )
551
552            // aggiungo il brand al marker per poter poi cambiare l'icona
553            marker.brand = markerData.brand
554
555            return marker
556        } )
557
558        // centra la mappa su tutti i marker, ma forzo uno zoom massimo
559        map.fitBounds( bounds, 85 )
560    } )
561
562    // Seleziona i marker
563
564    return await Promise.all( mapInitializers )
565}
566
567// Mega menu
568//document.addEventListener("DOMContentLoaded", function () {
569//  const primaryMenuItems = document.querySelectorAll(".primary-menu-container .menu-item");
570//  const megaMenus = document.querySelector(".mega-menus");
571//  const megaMenuItems = document.querySelectorAll(".mega-menu-item");
572//  const header = document.querySelector("header");
573//  let activeMenuItemId = null;
574//
575//  primaryMenuItems.forEach(function (menuItem) {
576//    menuItem.addEventListener("mouseenter", function () {
577//      const menuItemIdAttr = menuItem.getAttribute("id");
578//      const menuItemId = menuItemIdAttr ? menuItemIdAttr.replace("menu-item-", "") : null;
579//      activeMenuItemId = menuItemIdAttr;
580//
581//      const correspondingMegaMenuItem = document.querySelector('.mega-menu-item[data-menu-id="' + menuItemId + '"]');
582//
583//      if (correspondingMegaMenuItem) {
584//        megaMenuItems.forEach(function (megaMenuItem) {
585//          megaMenuItem.classList.remove("active");
586//        });
587//
588//        megaMenus.classList.add("active");
589//        header.classList.add("active");
590//
591//        correspondingMegaMenuItem.classList.add("active");
592//      } else {
593//        megaMenus.classList.remove("active");
594//        header.classList.remove("active");
595//        megaMenuItems.forEach(function (megaMenuItem) {
596//          megaMenuItem.classList.remove("active");
597//        });
598//        activeMenuItemId = null;
599//      }
600//    });
601//
602//    menuItem.addEventListener("mouseleave", function (event) {
603//      const relatedTarget = event.relatedTarget;
604//
605//      if (!megaMenus.contains(relatedTarget)) {
606//        megaMenus.classList.remove("active");
607//        header.classList.remove("active");
608//        megaMenuItems.forEach(function (megaMenuItem) {
609//          megaMenuItem.classList.remove("active");
610//        });
611//        activeMenuItemId = null;
612//      }
613//    });
614//  });
615//
616//  megaMenus.addEventListener("mouseleave", function (event) {
617//    const relatedTarget = event.relatedTarget;
618//
619//    if (activeMenuItemId) {
620//      const activeMenuItem = document.getElementById(activeMenuItemId);
621//      if (activeMenuItem && !activeMenuItem.contains(relatedTarget)) {
622//        megaMenus.classList.remove("active");
623//        header.classList.remove("active");
624//        megaMenuItems.forEach(function (megaMenuItem) {
625//          megaMenuItem.classList.remove("active");
626//        });
627//        activeMenuItemId = null;
628//      }
629//    } else {
630//      megaMenus.classList.remove("active");
631//      header.classList.remove("active");
632//      megaMenuItems.forEach(function (megaMenuItem) {
633//        megaMenuItem.classList.remove("active");
634//      });
635//    }
636//  });
637//
638//  megaMenus.addEventListener("mouseenter", function () {});
639//});
640
641class AjaxRequest {
642    constructor( config ) {
643        this.cache = new Map()
644        this.config = config
645        this.filtersSelector = config.filters
646        this.formData = config.formData
647        this.wrapper = document.querySelector( config.wrapper )
648        this.pagination = document.querySelector( config.pagination )
649        this.action = config.action
650        this.urlParams = new URLSearchParams( window.location.search )
651        if ( !this.pagination || !this.wrapper || !this.action ) return
652        this.addEventListeners()
653    }
654
655    addEventListeners( firstTime = true ) {
656        const pages = this.pagination.querySelectorAll( "button" )
657        pages.forEach( ( button ) => {
658            const page = button.dataset.page
659            button.addEventListener( "click", this.handlePageClick.bind( this, page ) )
660        } )
661
662        if ( !this.filtersSelector || !firstTime ) return
663        this.filters = document.querySelectorAll( this.filtersSelector )
664        this.filters.forEach( ( filter ) => {
665            const urlFilterValue = this.urlParams.get( filter.dataset.filter )
666            if ( urlFilterValue ) {
667                filter.value = urlFilterValue
668                console.log( "done" )
669            }
670            filter.addEventListener( "change", this.handleFilterChange.bind( this ) )
671        } )
672    }
673
674    handleFilterChange() {
675        this.updateURL()
676        this.handlePageClick( 1 )
677    }
678
679    updateContent( { wrapper: wrapperHtml, pagination: paginationHtml, page } ) {
680        this.wrapper.innerHTML = wrapperHtml
681        this.pagination.innerHTML = paginationHtml
682        this.addEventListeners( false )
683        this.wrapper.classList.remove( "loading" )
684        this.updateURL( page )
685    }
686
687    updateView( params ) {
688        if ( document.startViewTransition ) {
689            document.startViewTransition( () => {
690                this.updateContent( params )
691            } )
692            return
693        }
694
695        this.updateContent( params )
696    }
697
698    updateURL( page = null ) {
699        const urlParams = new URLSearchParams()
700        this.filters.forEach( ( filter ) => {
701            const filterID = filter.dataset.filter
702            if ( filterID && filter.value ) {
703                urlParams.set( filterID, filter.value )
704            }
705        } )
706        if ( page ) {
707            urlParams.set( "page", page )
708        }
709        if ( this.wrapper.dataset.categorySlug ) {
710            urlParams.set( "product_cat", this.wrapper.dataset.categorySlug )
711        }
712        window.history.pushState( {}, "", `${window.location.pathname}?${urlParams.toString()}` )
713    }
714
715    async handlePageClick( page ) {
716        window.scrollTo( {
717            top: window.scrollY + this.wrapper.getBoundingClientRect().top - 250,
718            behavior: "smooth",
719        } )
720
721        const cached = this.cache.get( this.getUniqueKey( page ) )
722        if ( cached ) {
723            console.log( "using cache" )
724            this.updateView( { wrapper: cached.wrapper, pagination: cached.pagination, page: page } )
725            return
726        }
727
728        const formData = new FormData()
729        formData.append( "action", this.action )
730        formData.append( "page", page )
731
732        if ( this.formData ) {
733            Object.entries( this.formData ).forEach( ( [ key, value ] ) => {
734                formData.append( key, value )
735            } )
736        }
737
738        if ( this.filtersSelector ) {
739            const filtersObj = {}
740            this.filters.forEach( ( filter ) => {
741                const filterName = filter.dataset.filter
742                console.log( filterName )
743                if ( filterName ) {
744                    filtersObj[filterName] = filter.value
745                }
746            } )
747
748            if ( this.wrapper.dataset.categorySlug ) {
749                filtersObj["product_cat"] = this.wrapper.dataset.categorySlug
750            }
751            formData.append( "filters", JSON.stringify( filtersObj ) )
752        }
753
754        try {
755            this.wrapper.classList.add( "loading" )
756            console.log( "fetching" )
757            const res = await fetch( "/wp-admin/admin-ajax.php", { method: "POST", body: formData } )
758            const data = await res.json()
759
760            if ( !data.success ) throw new Error( "News Ajax didn't succeed" )
761            console.log( data )
762
763            const wrapperHtml = data.data.html
764            const paginationHtml = data.data.pagination
765            this.updateView( { wrapper: wrapperHtml, pagination: paginationHtml, page: page } )
766            this.cache.set( this.getUniqueKey( page ), {
767                wrapper: wrapperHtml,
768                pagination: paginationHtml,
769                page: page
770            } )
771        } catch ( e ) {
772            this.wrapper.classList.remove( "loading" )
773            console.log( e )
774        }
775    }
776
777    getUniqueKey( page ) {
778        const keys = [ page ]
779
780        if ( this.filters ) {
781            this.filters.forEach( ( filter ) => {
782                keys.push( filter.value )
783            } )
784        }
785
786        return keys.join( "-" )
787    }
788}
789
790new AjaxRequest( {
791    pagination: ".news-cards-wrapper .pagination",
792    wrapper: ".news-cards-wrapper .news-wrapper",
793    action: "filter_news",
794    scrollTo: false,
795} )
796
797new AjaxRequest( {
798    pagination: ".blog-archive .pagination",
799    wrapper: ".blog-archive .articles-wrapper",
800    action: "filter_blog",
801    scrollTo: false,
802} );
803
804( () => {
805    const mostRecent = document.querySelector( ".blog-archive .most-recent" )
806    if ( !mostRecent ) return
807
808    document.querySelector( ".blog-archive .pagination" )?.addEventListener( "click", ( e ) => {
809        const btn = e.target.closest( "button[data-page]" )
810        if ( !btn ) return
811        const page = parseInt( btn.dataset.page )
812        mostRecent.style.display = page === 1 ? "" : "none"
813    } )
814} )();
815
816new AjaxRequest( {
817    pagination: ".product-lister .pagination",
818    wrapper: ".product-lister .products-wrapper",
819    action: "filter_products",
820    scrollTo: false,
821    formData: {
822        only_content: true,
823    },
824    filters: ".product-lister .filters .filters-wrapper select",
825} );
826
827( () => {
828    const productChips = document.querySelectorAll( "section.single-product .columns .product-info .infos .chips-content input" )
829    const labels = Array.from( productChips )
830        .map( ( chip ) => {
831            return document.querySelector( `label[for="${chip.id}"]` )
832        } )
833        .filter( ( e ) => e )
834
835    productChips.forEach( ( chip ) => {
836        chip.addEventListener( "change", () => {
837            labels.forEach( ( label ) => {
838                if ( label.getAttribute( "for" ) == chip.id ) {
839                    label.classList.add( "active" )
840                } else {
841                    label.classList.remove( "active" )
842                }
843            } )
844        } )
845    } )
846} )()
847
848function revealingHeader( options = {} ) {
849    const config = {
850        header: document.querySelector( "header" ),
851        scrollDownTreshold: 250,
852        scrollUpTreshold: 250,
853        hideTreshold: document.querySelector( "header" )?.getBoundingClientRect().height / 2,
854        floatingClass: "floating",
855        floatingClassActive: "floating-active",
856        debug: false,
857        ...options,
858    }
859
860    const header = config.header
861    if ( !header ) {
862        console.error( "The header was not detected" )
863        return
864    }
865
866    const scrollUpThreshold = config.scrollUpTreshold
867    const scrollDownThreshold = config.scrollDownTreshold
868    const hideThreshold = config.hideTreshold
869    const floatingClass = config.floatingClass
870    const floatingClassActive = config.floatingClassActive
871
872    let previousY = window.scrollY
873    let changedDirectionYUp = 1
874    let changedDirectionYDown = 1
875    let scrolledUp = false
876    let isScrollingUp = false
877
878    // Initial class assignment based on scroll position
879    if ( window.scrollY < hideThreshold ) {
880        header.classList.remove( floatingClass )
881    } else {
882        header.classList.add( floatingClass )
883        if ( config.debug ) console.log( "Adding class floating" )
884    }
885
886    // Add scroll event listener
887    window.addEventListener( "scroll", () => {
888        const currentY = window.scrollY
889
890        // Determine scroll direction
891        if ( previousY >= currentY ) {
892            isScrollingUp = true
893            changedDirectionYDown = currentY
894        } else {
895            isScrollingUp = false
896            scrolledUp = false
897            changedDirectionYUp = currentY
898            if ( currentY - changedDirectionYDown >= scrollDownThreshold ) {
899                header.classList.remove( floatingClassActive )
900            }
901        }
902
903        // Manage scroll up state
904        if ( isScrollingUp && !scrolledUp ) {
905            changedDirectionYUp = currentY
906            scrolledUp = true
907        }
908
909        // Manage header floating class based on scroll up threshold
910        if ( isScrollingUp ) {
911            if ( changedDirectionYUp - currentY >= scrollUpThreshold && currentY != 0 ) {
912                header.classList.add( floatingClassActive )
913            } else {
914                header.classList.remove( floatingClassActive )
915                if ( config.debug ) console.log( "Not has class" )
916            }
917        }
918
919        previousY = currentY
920
921        // Manage header visibility based on thresholds
922        if ( currentY < hideThreshold ) {
923            header.classList.remove( floatingClass )
924            return
925        }
926        header.classList.add( floatingClass )
927        if ( config.debug ) console.log( "Adding class floating" )
928    } )
929}
930
931revealingHeader();
932
933( () => {
934    const menuToggler = document.querySelector( ".menu-toggler" )
935    if ( !menuToggler ) return
936
937    menuToggler.addEventListener( "click", () => {
938        document.body.classList.toggle( "mobile-open" )
939    } )
940} )()
941
942jQuery( function ( $ ) {
943    // Account mobile
944    $( "body.woocommerce-account.loggedin .woocommerce" ).on( "click", ".account-title", function () {
945        $( "body.woocommerce-account.loggedin .woocommerce .account-title" ).toggleClass( "active" )
946    } )
947
948    // Sposto checkout form
949    if ( $( ".woocommerce-checkout-review-order-table" ).length ) {
950        $( ".woocommerce-checkout-review-order-table" ).clone().appendTo( $( ".checkout-your-order" ) )
951    }
952
953    $( "body" ).on( "click", ".login-form .register-now", function () {
954        $( ".woocommerce-account .login-form" ).hide().animate( { opacity: 0 }, 500 )
955        $( ".woocommerce-account .register-form" ).show().animate( { opacity: 1 }, 500 )
956    } )
957
958    $( "body" ).on( "click", ".register-form .login-now", function () {
959        $( ".woocommerce-account .register-form" ).hide().animate( { opacity: 0 }, 500 )
960        $( ".woocommerce-account .login-form" ).show().animate( { opacity: 1 }, 500 )
961    } )
962} );
963
964( () => {
965    const atelierBookingForm = document.querySelector( ".atelier-booking-form .form-types" )
966    const iframe = document.querySelector( ".atelier-booking-form iframe" )
967    const back = document.querySelector( ".atelier-booking-form .back" )
968    if ( !atelierBookingForm || !iframe ) return
969    atelierBookingForm.querySelectorAll( ".form-type" ).forEach( ( formType ) => {
970        const button = formType.querySelector( "button" )
971        if ( !button ) return
972        button.addEventListener( "click", () => {
973            iframe.src = formType.dataset.url + "?embed=true"
974            atelierBookingForm.classList.add( "display-none" )
975            iframe.classList.remove( "display-none" )
976            back.classList.remove( "display-none" )
977        } )
978
979        back.addEventListener( "click", () => {
980            atelierBookingForm.classList.remove( "display-none" )
981            iframe.classList.add( "display-none" )
982            back.classList.add( "display-none" )
983        } )
984    } )
985} )();
986
987( () => {
988    document.querySelectorAll( '.accordion' ).forEach( accordion => {
989        const lines = accordion.querySelectorAll( '.list-line' )
990
991        lines.forEach( line => {
992            line.toggleOpen = ( open = true ) => line.classList.toggle( 'open', open )
993
994            const contentAbove = line.querySelector( '.content-above' )
995            const contentBelow = line.querySelector( '.content-below' )
996            const triggerBtn = line.querySelector( '.trigger-btn' )
997
998            if ( !contentBelow ) {
999                triggerBtn?.remove()
1000                return
1001            }
1002
1003            //if ( !triggerBtn ) return
1004
1005            function listenerFn( e ) {
1006                const wasOpen = line.classList.contains( 'open' )
1007                line.toggleOpen( !wasOpen )
1008
1009                if ( !wasOpen ) lines.forEach( l => l !== line && l.toggleOpen( false ) )
1010            }
1011
1012            //triggerBtn.addEventListener( 'click', listenerFn )
1013            contentAbove?.addEventListener( 'click', listenerFn )
1014            contentAbove?.style.setProperty( "cursor", "pointer" )
1015        } )
1016    } )
1017} )();
1018
1019( () => {
1020    const openers = document.querySelectorAll( ".ai-chat-opener" )
1021    openers.forEach( ( opener ) => {
1022        opener.addEventListener( "click", ( e ) => {
1023            e.preventDefault()
1024            e.stopPropagation()
1025            const host = document.querySelector( "#zipchat-shadow-host" )
1026            if ( !host || !host.shadowRoot ) return
1027            const chatBtn = host.shadowRoot.querySelector( "#widget-chat-button" )
1028            if ( !chatBtn ) return
1029            setTimeout( () => chatBtn.click(), 0 )
1030        } )
1031    } )
1032} )()

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.