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.