PageSourceSearch

https://decorfooditaly.it/wp-content/themes/decorfood/assets/js/main.js?ver=1.7.6

js decorfooditaly.it collected 2026-10-02 13:45:19 UTC 17,057 bytes, 613 lines download raw bytes

1document.addEventListener('DOMContentLoaded', () => {
2  const megaItems = Array.from(document.querySelectorAll('.nav-item--mega'));
3  let megaCloseTimer = null;
4
5  const clearMegaCloseTimer = () => {
6    if (megaCloseTimer) {
7      window.clearTimeout(megaCloseTimer);
8      megaCloseTimer = null;
9    }
10  };
11
12  const closeMegaItems = (exceptItem = null) => {
13    clearMegaCloseTimer();
14
15    megaItems.forEach((item) => {
16      if (item === exceptItem) {
17        return;
18      }
19
20      const itemToggle = item.querySelector('.nav-toggle');
21      item.classList.remove('is-open');
22
23      if (itemToggle) {
24        itemToggle.setAttribute('aria-expanded', 'false');
25      }
26    });
27  };
28
29  const openMegaItem = (megaItem) => {
30    const toggle = megaItem.querySelector('.nav-toggle');
31
32    clearMegaCloseTimer();
33    closeMegaItems(megaItem);
34    megaItem.classList.add('is-open');
35
36    if (toggle) {
37      toggle.setAttribute('aria-expanded', 'true');
38    }
39  };
40
41  const scheduleMegaClose = () => {
42    clearMegaCloseTimer();
43    megaCloseTimer = window.setTimeout(() => {
44      closeMegaItems();
45    }, 420);
46  };
47
48  megaItems.forEach((megaItem) => {
49    const toggle = megaItem.querySelector('.nav-toggle');
50
51    if (!toggle) {
52      return;
53    }
54
55    megaItem.addEventListener('pointerenter', () => {
56      openMegaItem(megaItem);
57    });
58
59    megaItem.addEventListener('pointerleave', () => {
60      scheduleMegaClose();
61    });
62
63    toggle.addEventListener('click', (e) => {
64      e.preventDefault();
65      const shouldOpen = !megaItem.classList.contains('is-open');
66
67      if (shouldOpen) {
68        openMegaItem(megaItem);
69      } else {
70        closeMegaItems();
71      }
72    });
73  });
74
75  if (megaItems.length) {
76    document.addEventListener('click', (e) => {
77      const clickInsideMega = megaItems.some((item) => item.contains(e.target));
78
79      if (!clickInsideMega) {
80        closeMegaItems();
81      }
82    });
83
84    document.addEventListener('keydown', (e) => {
85      if (e.key === 'Escape') {
86        closeMegaItems();
87      }
88    });
89  }
90
91  const languageMenus = Array.from(document.querySelectorAll('.header-lang'));
92
93  const closeLanguageMenus = (exceptMenu = null) => {
94    languageMenus.forEach((menu) => {
95      if (menu === exceptMenu) {
96        return;
97      }
98
99      menu.classList.remove('is-open');
100      const button = menu.querySelector('.header-lang__current');
101
102      if (button) {
103        button.setAttribute('aria-expanded', 'false');
104      }
105    });
106  };
107
108  languageMenus.forEach((menu) => {
109    const button = menu.querySelector('.header-lang__current');
110
111    if (!button) {
112      return;
113    }
114
115    button.setAttribute('aria-expanded', 'false');
116
117    button.addEventListener('click', (e) => {
118      e.preventDefault();
119      e.stopPropagation();
120
121      const shouldOpen = !menu.classList.contains('is-open');
122      closeLanguageMenus(menu);
123      menu.classList.toggle('is-open', shouldOpen);
124      button.setAttribute('aria-expanded', shouldOpen ? 'true' : 'false');
125    });
126  });
127
128  if (languageMenus.length) {
129    document.addEventListener('click', (e) => {
130      const insideLanguage = languageMenus.some((menu) => menu.contains(e.target));
131
132      if (!insideLanguage) {
133        closeLanguageMenus();
134      }
135    });
136
137    document.addEventListener('keydown', (e) => {
138      if (e.key === 'Escape') {
139        closeLanguageMenus();
140      }
141    });
142  }
143
144  document.querySelectorAll('.wpml-ls [role="menu"], .wpml-ls [role="menuitem"], .wpml-ls [role="none"]').forEach((element) => {
145    element.removeAttribute('role');
146  });
147
148  const categoriesPanel = document.getElementById('mobile-categories-panel');
149  const openCategories = document.querySelectorAll('.js-open-categories');
150  const closeCategories = document.querySelectorAll('.js-close-categories');
151
152  if (categoriesPanel) {
153    openCategories.forEach((btn) => {
154      btn.addEventListener('click', () => {
155        categoriesPanel.hidden = false;
156        categoriesPanel.classList.add('is-open');
157        categoriesPanel.removeAttribute('aria-hidden');
158        document.body.classList.add('panel-open');
159      });
160    });
161
162    closeCategories.forEach((btn) => {
163      btn.addEventListener('click', () => {
164        categoriesPanel.classList.remove('is-open');
165        categoriesPanel.removeAttribute('aria-hidden');
166        categoriesPanel.hidden = true;
167        document.body.classList.remove('panel-open');
168      });
169    });
170  }
171
172  const mobileSearchPanel = document.getElementById('mobile-search-panel');
173  const desktopSearchPanel = document.getElementById('search-overlay');
174  const searchPanels = [mobileSearchPanel, desktopSearchPanel].filter(Boolean);
175  const openSearch = document.querySelectorAll('.js-open-search');
176  const closeSearch = document.querySelectorAll('.js-close-search');
177
178  const getSearchPanel = () => {
179    if (window.matchMedia('(min-width: 1025px)').matches && desktopSearchPanel) {
180      return desktopSearchPanel;
181    }
182
183    return mobileSearchPanel || desktopSearchPanel;
184  };
185
186  const closeSearchPanels = () => {
187    searchPanels.forEach((panel) => {
188      panel.classList.remove('is-open');
189      panel.removeAttribute('aria-hidden');
190      panel.hidden = true;
191    });
192    document.body.classList.remove('panel-open');
193  };
194
195  if (searchPanels.length) {
196    openSearch.forEach((btn) => {
197      btn.addEventListener('click', () => {
198        const panel = getSearchPanel();
199
200        if (!panel) {
201          return;
202        }
203
204        closeSearchPanels();
205        panel.hidden = false;
206        panel.classList.add('is-open');
207        panel.removeAttribute('aria-hidden');
208        document.body.classList.add('panel-open');
209
210        const input = panel.querySelector('[data-ai-search-input], input[type="search"]');
211
212        if (input) {
213          window.setTimeout(() => input.focus(), 80);
214        }
215      });
216    });
217
218    closeSearch.forEach((btn) => {
219      btn.addEventListener('click', () => {
220        closeSearchPanels();
221      });
222    });
223
224    document.addEventListener('keydown', (e) => {
225      if (e.key === 'Escape') {
226        closeSearchPanels();
227      }
228    });
229  }
230
231  const productGalleries = Array.from(document.querySelectorAll('[data-product-gallery]'));
232
233  productGalleries.forEach((gallery) => {
234    const mainImage = gallery.querySelector('[data-product-gallery-main]');
235    const mainFrame = mainImage ? mainImage.closest('.product-gallery__main') : null;
236    const thumbs = Array.from(gallery.querySelectorAll('[data-product-gallery-thumb]'));
237
238    if (!mainImage) {
239      return;
240    }
241
242    const originalImage = {
243      src: mainImage.getAttribute('src') || '',
244      alt: mainImage.getAttribute('alt') || '',
245      thumb: thumbs.find((thumb) => thumb.classList.contains('is-active')) || null
246    };
247
248    const setActiveThumb = (activeThumb) => {
249      thumbs.forEach((thumb) => {
250        const isActive = thumb === activeThumb;
251        thumb.classList.toggle('is-active', isActive);
252        thumb.setAttribute('aria-pressed', isActive ? 'true' : 'false');
253      });
254    };
255
256    const normalizeImageUrl = (url) => (url || '').split('?')[0];
257
258    const findThumbBySrc = (src) => {
259      const normalizedSrc = normalizeImageUrl(src);
260
261      return thumbs.find((thumb) => normalizeImageUrl(thumb.getAttribute('data-large')) === normalizedSrc) || null;
262    };
263
264    const switchMainImage = (nextSrc, nextAlt, activeThumb = null) => {
265      if (!nextSrc || mainImage.getAttribute('src') === nextSrc) {
266        setActiveThumb(activeThumb);
267        return;
268      }
269
270      const applyImage = () => {
271        mainImage.setAttribute('src', nextSrc);
272        mainImage.setAttribute('alt', nextAlt);
273        mainImage.removeAttribute('srcset');
274        mainImage.removeAttribute('sizes');
275        setActiveThumb(activeThumb);
276
277        if (mainFrame) {
278          window.requestAnimationFrame(() => {
279            mainFrame.classList.remove('is-switching');
280          });
281        }
282      };
283
284      if (mainFrame) {
285        mainFrame.classList.add('is-switching');
286      }
287
288      const preload = new Image();
289      preload.onload = applyImage;
290      preload.onerror = applyImage;
291      preload.src = nextSrc;
292    };
293
294    const switchProductImage = (thumb) => {
295      const nextSrc = thumb.getAttribute('data-large');
296      const nextAlt = thumb.getAttribute('data-alt') || mainImage.getAttribute('alt') || '';
297
298      switchMainImage(nextSrc, nextAlt, thumb);
299    };
300
301    thumbs.forEach((thumb) => {
302      thumb.addEventListener('click', () => {
303        switchProductImage(thumb);
304      });
305    });
306
307    const productLayout = gallery.closest('.product-layout');
308    const variationForm = productLayout ? productLayout.querySelector('.variations_form') : document.querySelector('.variations_form');
309
310    if (variationForm && window.jQuery) {
311      window.jQuery(variationForm)
312        .on('found_variation', (event, variation) => {
313          const variationImage = variation && variation.image ? variation.image : null;
314          const variationSrc = variationImage ? (variationImage.full_src || variationImage.src || variationImage.url) : '';
315
316          if (!variationSrc) {
317            return;
318          }
319
320          switchMainImage(
321            variationSrc,
322            variationImage.alt || variationImage.title || originalImage.alt,
323            findThumbBySrc(variationSrc)
324          );
325        })
326        .on('reset_data hide_variation', () => {
327          switchMainImage(originalImage.src, originalImage.alt, originalImage.thumb);
328        });
329    }
330  });
331
332  const shopGrid = document.querySelector('[data-shop-grid]');
333  const shopPagination = document.querySelector('[data-shop-pagination]');
334
335  if (shopGrid && shopPagination) {
336    let isLoadingMoreProducts = false;
337
338    const getNextPageLink = () => shopPagination.querySelector('a.next');
339
340    const setShopLoading = (isLoading) => {
341      shopPagination.classList.toggle('is-loading', isLoading);
342      shopPagination.setAttribute('aria-busy', isLoading ? 'true' : 'false');
343    };
344
345    const loadMoreProducts = async () => {
346      const nextLink = getNextPageLink();
347
348      if (!nextLink || isLoadingMoreProducts) {
349        return;
350      }
351
352      isLoadingMoreProducts = true;
353      setShopLoading(true);
354
355      try {
356        const response = await fetch(nextLink.href, {
357          credentials: 'same-origin'
358        });
359
360        if (!response.ok) {
361          throw new Error('Shop page request failed');
362        }
363
364        const html = await response.text();
365        const doc = new DOMParser().parseFromString(html, 'text/html');
366        const nextProducts = Array.from(doc.querySelectorAll('[data-shop-grid] .shop-product-card'));
367        const nextPagination = doc.querySelector('[data-shop-pagination]');
368
369        nextProducts.forEach((productCard) => {
370          shopGrid.appendChild(productCard);
371        });
372
373        if (nextPagination) {
374          shopPagination.innerHTML = nextPagination.innerHTML;
375        } else {
376          shopPagination.innerHTML = '';
377        }
378      } catch (error) {
379        shopPagination.classList.add('has-error');
380      } finally {
381        isLoadingMoreProducts = false;
382        setShopLoading(false);
383      }
384    };
385
386    const observeShopPagination = () => {
387      if (!('IntersectionObserver' in window)) {
388        return;
389      }
390
391      const observer = new IntersectionObserver((entries) => {
392        entries.forEach((entry) => {
393          if (entry.isIntersecting) {
394            loadMoreProducts();
395          }
396        });
397      }, {
398        rootMargin: '520px 0px'
399      });
400
401      observer.observe(shopPagination);
402    };
403
404    observeShopPagination();
405  }
406
407  const cookieBanner = document.querySelector('[data-cookie-banner]');
408  const cookieModal = document.querySelector('[data-cookie-modal]');
409  const cookieManage = document.querySelector('[data-cookie-manage]');
410  const cookieButtons = document.querySelectorAll('[data-cookie-action]');
411  const cookieCloseButtons = document.querySelectorAll('[data-cookie-close]');
412  const cookieAnalytics = document.querySelector('[data-cookie-preference="analytics"]');
413  const cookieName = 'decorfood_cookie_consent_v2';
414
415  const setSpokiHidden = (hidden) => {
416    const spokiButton = document.querySelector('#spoki-shadowed-fixed-button');
417    if (!spokiButton) {
418      return false;
419    }
420
421    if (hidden) {
422      spokiButton.style.setProperty('display', 'none', 'important');
423    } else {
424      spokiButton.style.removeProperty('display');
425    }
426
427    return true;
428  };
429
430  const waitForSpoki = (hidden) => {
431    if (setSpokiHidden(hidden)) {
432      return;
433    }
434
435    const observer = new MutationObserver(() => {
436      if (setSpokiHidden(hidden)) {
437        observer.disconnect();
438      }
439    });
440    observer.observe(document.body, { childList: true, subtree: true });
441    window.setTimeout(() => observer.disconnect(), 10000);
442  };
443
444  const getCookieConsent = () => {
445    const match = document.cookie.match(new RegExp(`(?:^|; )${cookieName}=([^;]*)`));
446
447    if (!match) {
448      return null;
449    }
450
451    try {
452      return JSON.parse(decodeURIComponent(match[1]));
453    } catch (error) {
454      return null;
455    }
456  };
457
458  const setCookieConsent = (preferences) => {
459    const consent = {
460      necessary: true,
461      analytics: Boolean(preferences.analytics),
462      marketing: false,
463      version: 2,
464      savedAt: new Date().toISOString()
465    };
466
467    document.cookie = `${cookieName}=${encodeURIComponent(JSON.stringify(consent))}; path=/; max-age=15552000; SameSite=Lax`;
468    window.dispatchEvent(new CustomEvent('decorfood:cookie-consent', { detail: consent }));
469
470    if (typeof window.gtag === 'function') {
471      window.gtag('consent', 'update', {
472        analytics_storage: consent.analytics ? 'granted' : 'denied',
473        ad_storage: 'denied',
474        ad_user_data: 'denied',
475        ad_personalization: 'denied',
476        personalization_storage: 'denied',
477        functionality_storage: 'granted',
478        security_storage: 'granted'
479      });
480    }
481
482    return consent;
483  };
484
485  const syncCookieInputs = (consent = {}) => {
486    if (cookieAnalytics) {
487      cookieAnalytics.checked = Boolean(consent.analytics);
488    }
489
490  };
491
492  const showCookieBanner = () => {
493    if (cookieBanner) {
494      cookieBanner.hidden = false;
495    }
496
497    if (cookieManage) {
498      cookieManage.hidden = true;
499    }
500
501    waitForSpoki(true);
502  };
503
504  const hideCookieBanner = () => {
505    if (cookieBanner) {
506      cookieBanner.hidden = true;
507    }
508
509    if (cookieManage) {
510      cookieManage.hidden = false;
511    }
512
513    setSpokiHidden(false);
514  };
515
516  const openCookieModal = () => {
517    const consent = getCookieConsent();
518
519    syncCookieInputs(consent || {});
520
521    if (cookieModal) {
522      cookieModal.hidden = false;
523      cookieModal.setAttribute('aria-hidden', 'false');
524      document.body.classList.add('panel-open');
525      const firstControl = cookieModal.querySelector('button, input');
526      if (firstControl) {
527        firstControl.focus();
528      }
529    }
530
531    waitForSpoki(true);
532  };
533
534  const closeCookieModal = () => {
535    if (cookieModal) {
536      cookieModal.hidden = true;
537      cookieModal.setAttribute('aria-hidden', 'true');
538      document.body.classList.remove('panel-open');
539    }
540
541
542    if (!cookieBanner || cookieBanner.hidden) {
543      setSpokiHidden(false);
544    }
545  };
546
547  const saveCookieChoice = (action) => {
548    let consent;
549
550    if (action === 'accept') {
551      consent = setCookieConsent({ analytics: true });
552    } else if (action === 'save') {
553      consent = setCookieConsent({
554        analytics: cookieAnalytics ? cookieAnalytics.checked : false
555      });
556    } else {
557      consent = setCookieConsent({ analytics: false });
558    }
559
560    syncCookieInputs(consent);
561    hideCookieBanner();
562    closeCookieModal();
563  };
564
565  if (cookieBanner || cookieModal || cookieManage) {
566    const currentConsent = getCookieConsent();
567
568    if (currentConsent) {
569      syncCookieInputs(currentConsent);
570      if (typeof window.gtag === 'function') {
571        window.gtag('consent', 'update', {
572          analytics_storage: currentConsent.analytics ? 'granted' : 'denied',
573          ad_storage: 'denied',
574          ad_user_data: 'denied',
575          ad_personalization: 'denied',
576          personalization_storage: 'denied',
577          functionality_storage: 'granted',
578          security_storage: 'granted'
579        });
580      }
581      hideCookieBanner();
582    } else {
583      showCookieBanner();
584    }
585
586    cookieButtons.forEach((button) => {
587      button.addEventListener('click', () => {
588        const action = button.getAttribute('data-cookie-action');
589
590        if (action === 'customize') {
591          openCookieModal();
592          return;
593        }
594
595        saveCookieChoice(action);
596      });
597    });
598
599    cookieCloseButtons.forEach((button) => {
600      button.addEventListener('click', closeCookieModal);
601    });
602
603    if (cookieManage) {
604      cookieManage.addEventListener('click', openCookieModal);
605    }
606
607    document.addEventListener('keydown', (event) => {
608      if (event.key === 'Escape' && cookieModal && !cookieModal.hidden) {
609        closeCookieModal();
610      }
611    });
612  }
613});

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.