PageSourceSearch

https://www.sebastiani.com/_static/??/wp-content/plugins/foley-c7-…/foley/dist/js/frontend.js?m=1790376510j

js sebastiani.com collected 2026-09-26 05:50:57 UTC 68,808 bytes, 1,748 lines download raw bytes

1// Shared front-end Commerce7 UI enhancements.
2
3const foleyC7UiGa4Analytics = (() => {
4  const CHECKOUT_LINK_SELECTOR = '[data-testid="proceed-to-checkout-link"]';
5  const CHECKOUT_MARKER_MAX_AGE = 24 * 60 * 60 * 1000;
6  const DATA_LAYER_WRAPPER_MARKER = '__foleyC7UiGa4Normalizer';
7  const LIST_ITEM_SELECTOR = '.foley-c7-ui-wine-card[data-ga4-item-id][data-ga4-item-name]';
8  const PDP_SELECTOR = '[data-ga4-product-context="pdp"][data-ga4-item-id][data-ga4-item-name]';
9  const STORAGE_NAMESPACE = 'foley-c7-ui:ga4';
10  const REMOVE_FROM_CART_MAX_AGE = 15000;
11  const RECEIPT_SEGMENT = 'order-receipt';
12  const settings = window.foleyC7UiGa4Settings || {};
13  const suppressedDataLayerEntry = Symbol('suppressedDataLayerEntry');
14  const listImpressionStates = new WeakMap();
15  const pdpViewFingerprints = new Set();
16
17  let checkoutListenerRegistered = false;
18  let lastCheckoutActivation = 0;
19  let pendingRemovals = [];
20  let pluginPushDepth = 0;
21  let removeListenerRegistered = false;
22
23  function getDataLayer() {
24    window.dataLayer = window.dataLayer || [];
25    return 'function' === typeof window.dataLayer.push ? window.dataLayer : null;
26  }
27
28  function getDataLayerLength() {
29    const dataLayer = getDataLayer();
30    return dataLayer && 'number' === typeof dataLayer.length ? dataLayer.length : 0;
31  }
32
33  function pushEcommerceEvent(eventName, ecommerce) {
34    const dataLayer = getDataLayer();
35    const requiresCheckoutMarker = 'begin_checkout' === eventName;
36
37    if (!dataLayer || !eventName || !ecommerce) {
38      return false;
39    }
40
41    if (requiresCheckoutMarker && !setCheckoutMarker()) {
42      return false;
43    }
44
45    try {
46      pluginPushDepth++;
47
48      try {
49        dataLayer.push({ ecommerce: null });
50        dataLayer.push({
51          event: eventName,
52          ecommerce
53        });
54      } finally {
55        pluginPushDepth--;
56      }
57
58      return true;
59    } catch (error) {
60      if (requiresCheckoutMarker) {
61        clearCheckoutMarker();
62      }
63
64      return false;
65    }
66  }
67
68  function cloneEcommerce(ecommerce) {
69    if (!ecommerce || 'object' !== typeof ecommerce || Array.isArray(ecommerce)) {
70      return null;
71    }
72
73    try {
74      return stripUndefinedProperties(ecommerce);
75    } catch (error) {
76      return null;
77    }
78  }
79
80  function parseCents(value) {
81    if (null === value || '' === value || 'boolean' === typeof value) {
82      return null;
83    }
84
85    const cents = Number(value);
86    return Number.isFinite(cents) && cents >= 0 ? cents : null;
87  }
88
89  function centsToCurrency(value) {
90    const cents = parseCents(value);
91    return null === cents ? null : cents / 100;
92  }
93
94  function isNumericValue(value) {
95    return (
96      null !== value &&
97      '' !== value &&
98      'boolean' !== typeof value &&
99      Number.isFinite(Number(value))
100    );
101  }
102
103  function getCurrency() {
104    return String(settings.currency || '').trim().toUpperCase();
105  }
106
107  function isValidCurrency(value) {
108    return 'string' === typeof value && '' !== value.trim();
109  }
110
111  function normalizeComparableText(value) {
112    return String(value || '').trim().replace(/\s+/g, ' ').toLowerCase();
113  }
114
115  function stripUndefinedProperties(value) {
116    if (Array.isArray(value)) {
117      return value
118        .filter(item => undefined !== item)
119        .map(stripUndefinedProperties);
120    }
121
122    if (value && 'object' === typeof value) {
123      const clonedValue = {};
124
125      Object.keys(value).forEach(key => {
126        if (undefined !== value[key]) {
127          clonedValue[key] = stripUndefinedProperties(value[key]);
128        }
129      });
130
131      return clonedValue;
132    }
133
134    return value;
135  }
136
137  function ensureEventCurrency(ecommerce) {
138    if (!ecommerce || 'object' !== typeof ecommerce || Array.isArray(ecommerce)) {
139      return;
140    }
141
142    if (!isValidCurrency(ecommerce.currency)) {
143      const currency = getCurrency();
144
145      if (currency) {
146        ecommerce.currency = currency;
147      } else {
148        delete ecommerce.currency;
149      }
150    }
151  }
152
153  function cleanItemCurrencies(items) {
154    if (!Array.isArray(items)) {
155      return;
156    }
157
158    items.forEach(item => {
159      if (
160        item &&
161        'object' === typeof item &&
162        !Array.isArray(item) &&
163        Object.prototype.hasOwnProperty.call(item, 'currency') &&
164        !isValidCurrency(item.currency)
165      ) {
166        delete item.currency;
167      }
168    });
169  }
170
171  function cloneDataLayerEntry(entry) {
172    if (!entry || 'object' !== typeof entry || Array.isArray(entry)) {
173      return null;
174    }
175
176    try {
177      return stripUndefinedProperties(entry);
178    } catch (error) {
179      return null;
180    }
181  }
182
183  function analyticsElementMatchesItem(element, item) {
184    const eventItemId = String(item?.item_id || '').trim();
185    const eventItemName = normalizeComparableText(item?.item_name);
186    const candidateIds = [
187      element.dataset.ga4ItemId,
188      element.dataset.ga4Commerce7Id
189    ].map(value => String(value || '').trim()).filter(Boolean);
190    const candidateName = normalizeComparableText(element.dataset.ga4ItemName);
191
192    return Boolean(
193      (eventItemId && candidateIds.includes(eventItemId)) ||
194      (eventItemName && candidateName && eventItemName === candidateName)
195    );
196  }
197
198  function shouldSuppressCustomContextViewItem(entry) {
199    const items = entry?.ecommerce?.items;
200
201    if (!Array.isArray(items) || 1 !== items.length || !items[0]) {
202      return false;
203    }
204
205    const candidates = [
206      ...document.querySelectorAll(PDP_SELECTOR),
207      ...document.querySelectorAll(`.js-foley-c7-ui-wine-listing ${LIST_ITEM_SELECTOR}`),
208      ...document.querySelectorAll(`.foley-c7-ui-wine-detail ${L
208IST_ITEM_SELECTOR}`)
209    ];
210
211    return candidates.some(element => analyticsElementMatchesItem(element, items[0]));
212  }
213
214  function normalizeViewCartEntry(entry) {
215    const normalizedEntry = cloneDataLayerEntry(entry);
216
217    if (!normalizedEntry?.ecommerce) {
218      return entry;
219    }
220
221    ensureEventCurrency(normalizedEntry.ecommerce);
222    cleanItemCurrencies(normalizedEntry.ecommerce.items);
223    return normalizedEntry;
224  }
225
226  function normalizeViewItemEntry(entry) {
227    if (shouldSuppressCustomContextViewItem(entry)) {
228      return suppressedDataLayerEntry;
229    }
230
231    const normalizedEntry = cloneDataLayerEntry(entry);
232    const ecommerce = normalizedEntry?.ecommerce;
233
234    if (!ecommerce) {
235      return entry;
236    }
237
238    ensureEventCurrency(ecommerce);
239    cleanItemCurrencies(ecommerce.items);
240
241    if (Array.isArray(ecommerce.items) && 1 === ecommerce.items.length) {
242      const item = ecommerce.items[0];
243
244      if (item && 'object' === typeof item && !Array.isArray(item)) {
245        if (!isNumericValue(item.quantity) || Number(item.quantity) < 1) {
246          item.quantity = 1;
247        }
248
249        if (!isNumericValue(ecommerce.value) && isNumericValue(item.price)) {
250          ecommerce.value = Math.round(
251            Number(item.price) * Number(item.quantity) * 100
252          ) / 100;
253        }
254      }
255    }
256
257    return normalizedEntry;
258  }
259
260  function cleanupPendingRemovals(now = Date.now()) {
261    pendingRemovals = pendingRemovals.filter(removal => (
262      now - removal.timestamp >= 0 &&
263      now - removal.timestamp <= REMOVE_FROM_CART_MAX_AGE
264    ));
265  }
266
267  function pendingRemovalMatchesItem(removal, item) {
268    const itemName = normalizeComparableText(item?.item_name);
269    const itemVariant = normalizeComparableText(item?.item_variant);
270
271    if (!itemName || itemName !== removal.itemName) {
272      return false;
273    }
274
275    return !removal.itemVariant || !itemVariant || itemVariant === removal.itemVariant;
276  }
277
278  function consumePendingRemoval(item) {
279    cleanupPendingRemovals();
280
281    for (let index = pendingRemovals.length - 1; index >= 0; index--) {
282      if (pendingRemovalMatchesItem(pendingRemovals[index], item)) {
283        return pendingRemovals.splice(index, 1)[0];
284      }
285    }
286
287    return null;
288  }
289
290  function normalizeRemoveFromCartEntry(entry) {
291    const normalizedEntry = cloneDataLayerEntry(entry);
292    const ecommerce = normalizedEntry?.ecommerce;
293
294    if (!ecommerce) {
295      return entry;
296    }
297
298    ensureEventCurrency(ecommerce);
299    cleanItemCurrencies(ecommerce.items);
300
301    if (!Array.isArray(ecommerce.items) || !ecommerce.items.length) {
302      return normalizedEntry;
303    }
304
305    let value = 0;
306    let hasCompleteValue = true;
307
308    ecommerce.items.forEach(item => {
309      if (!item || 'object' !== typeof item || Array.isArray(item)) {
310        hasCompleteValue = false;
311        return;
312      }
313
314      const pendingRemoval = consumePendingRemoval(item);
315
316      if (!isNumericValue(item.quantity) || Number(item.quantity) < 1) {
317        if (pendingRemoval) {
318          item.quantity = pendingRemoval.quantity;
319        }
320      }
321
322      if (
323        !Number.isInteger(Number(item.quantity)) ||
324        Number(item.quantity) < 1 ||
325        !isNumericValue(item.price)
326      ) {
327        hasCompleteValue = false;
328        return;
329      }
330
331      value += Number(item.price) * Number(item.quantity);
332    });
333
334    if (hasCompleteValue) {
335      ecommerce.value = Math.round(value * 100) / 100;
336    }
337
338    return normalizedEntry;
339  }
340
341  function normalizePurchaseEntry(entry) {
342    const normalizedEntry = cloneDataLayerEntry(entry);
343    const transactionId = normalizedEntry?.ecommerce?.transaction_id;
344
345    if (!normalizedEntry?.ecommerce || null === transactionId || undefined === transactionId) {
346      return normalizedEntry || entry;
347    }
348
349    normalizedEntry.ecommerce.transaction_id = String(transactionId);
350    return normalizedEntry;
351  }
352
353  function normalizeDataLayerEntry(entry) {
354    if (!entry || 'object' !== typeof entry || Array.isArray(entry)) {
355      return entry;
356    }
357
358    switch (entry.event) {
359      case 'begin_checkout':
360        if (isValidBeginCheckoutEcommerce(entry.ecommerce)) {
361          setCheckoutMarker();
362        }
363
364        return entry;
365      case 'view_cart':
366        return normalizeViewCartEntry(entry);
367      case 'view_item':
368        return normalizeViewItemEntry(entry);
369      case 'remove_from_cart':
370        return normalizeRemoveFromCartEntry(entry);
371      case 'purchase':
372        return normalizePurchaseEntry(entry);
373      default:
374        return entry;
375    }
376  }
377
378  function installDataLayerNormalizer() {
379    const dataLayer = getDataLayer();
380    const originalPush = dataLayer?.push;
381
382    if (!dataLayer || 'function' !== typeof originalPush || originalPush[DATA_LAYER_WRAPPER_MARKER]) {
383      return false;
384    }
385
386    function normalizedPush(...entries) {
387      if (pluginPushDepth > 0) {
388        return originalPush.apply(this, entries);
389      }
390
391      try {
392        const normalizedEntries = entries
393          .map(entry => {
394            try {
395              return normalizeDataLayerEntry(entry);
396            } catch (error) {
397              return entry;
398            }
399          })
400          .filter(entry => suppressedDataLayerEntry !== entry);
401
402        return originalPush.apply(this, normalizedEntries);
403      } catch (error) {
404        return originalPush.apply(this, entries);
405      }
406    }
407
408    try {
409      Object.defineProperty(normalizedPush, DATA_LAYER_WRAPPER_MARKER, {
410        configurable: false,
411        enumerable: false,
412        value: true,
413        writable: false
414      });
415      dataLayer.push = normalizedPush;
416      return dataLayer.push === normalizedPush;
417    } catch (error) {
418      return false;
419    }
420  }
421
422  function registerRemoveFromCartCapture() {
423    if (removeListenerRegistered) {
424      return;
425    }
426
427    removeListenerRegistered = true;
428
429    document.addEventListener('click', event => {
430      const target = event.target instanceof Element ? event.target : null;
431      const removeButton = target?.closest('.c7-order-item button.c7-link');
432
433      if (
434        !removeButton ||
435        'remove' !== normalizeComparableText(removeButton.textContent) ||
436        removeButton.matches('[disabled], [aria-disabled="true"]')
437      ) {
438        return;
439      }
440
441      const orderItem = removeButton.closest('.c7-order-item');
442      const quantityControl = orderItem?.querySelector(
443        'select[name="c7-quantityOther"], input[name="quantity"]'
444      );
445      const quantity = Number(quantityControl?.value);
446      const itemName = normalizeComparableText(
447        orderItem?.querySelector('.c7-order-item__title')?.textContent
448      );
449      const itemVariant = normalizeComparableText(
450        orderItem?.querySelector('.c7-order-item__description')?.textContent
451      );
452
453      if (!Number.isInteger(quantity) || quantity < 1 || !itemName) {
454        return;
455      }
456
457      cleanupPendingRemovals();
458      pendingRemovals.push({
459        itemName,
460        itemVariant,
461        quantity,
462        timestamp: Date.now()
463      });
464    }, true);
465  }
466
467  function getTenant() {
468    return String(
469      window.foleyC7?.tenantId ||
470      window.c7wp_settings?.tenant ||
471      document.getElementById('c7-javascript')?.getAttribute('data-tenant') ||
472      ''
473    ).trim();
474  }
475
476  function getStorageScope() {
477    const tenant = getTenant();
478
479    if (tenant) {
480      return tenant;
481    }
482
483    const siteId = String(settings.siteId || '').trim();
484    return siteId ? `site-${siteId}` : '';
485  }
486
487  function getStorageKey(eventName, identifier = '') {
488    const scope = getStorageScope();
489
490    if (!scope || !eventName) {
491      return '';
492    }
493
494    return [
495      STORAGE_NAMESPACE,
496      eventName,
497      encodeURIComponent(scope),
498      identifier ? encodeURIComponent(String(identifier)) : ''
499    ].filter(Boolean).join(':');
500  }
501
502  function storageGet(storage, key) {
503    if (!storage || !key) {
504      return { success: false, value: null };
505    }
506
507    try {
508      return { success: true, value: storage.getItem(key) };
509    } catch (error) {
510      return { success: false, value: null };
511    }
512  }
513
514  function getBrowserStorage(storageName) {
515    try {
516      return window[storageName] || null;
517    } catch (error) {
518      return null;
519    }
520  }
521
522  function storageSet(storage, key, value) {
523    if (!storage || !key) {
524      return false;
525    }
526
527    try {
528      storage.setItem(key, value);
529      return true;
530    } catch (error) {
531      return false;
532    }
533  }
534
535  function storageRemove(storage, key) {
536    if (!storage || !key) {
537      return false;
538    }
539
540    try {
541      storage.removeItem(key);
542      return true;
543    } catch (error) {
544      return false;
545    }
546  }
547
548  function getCheckoutMarkerKey() {
549    return getStorageKey('checkout-origin');
550  }
551
552  function setCheckoutMarker() {
553    return storageSet(
554      getBrowserStorage('sessionStorage'),
555      getCheckoutMarkerKey(),
556      JSON.stringify({ timestamp: Date.now() })
557    );
558  }
559
560  function clearCheckoutMarker() {
561    storageRemove(getBrowserStorage('sessionStorage'), getCheckoutMarkerKey());
562  }
563
564  function hasValidCheckoutMarker() {
565    const key = getCheckoutMarkerKey();
566    const stored = storageGet(getBrowserStorage('sessionStorage'), key);
567
568    if (!stored.success || !stored.value) {
569      return false;
570    }
571
572    try {
573      const marker = JSON.parse(stored.value);
574      const timestamp = Number(marker?.timestamp);
575      const age = Date.now() - timestamp;
576
577      if (!Number.isFinite(timestamp) || age < 0 || age > CHECKOUT_MARKER_MAX_AGE) {
578        storageRemove(getBrowserStorage('sessionStorage'), key);
579        return false;
580      }
581
582      return true;
583    } catch (error) {
584      storageRemove(getBrowserStorage('sessionStorage'), key);
585      return false;
586    }
587  }
588
589  function getMostRecentDataLayerEvent(eventName) {
590    const dataLayer = getDataLayer();
591
592    if (!dataLayer || !eventName) {
593      return null;
594    }
595
596    for (let index = dataLayer.length - 1; index >= 0; index--) {
597      if (dataLayer[index]?.event === eventName) {
598        return dataLayer[index];
599      }
600    }
601
602    return null;
603  }
604
605  function isValidViewCartEcommerce(ecommerce) {
606    return Boolean(
607      ecommerce &&
608      'object' === typeof ecommerce &&
609      !Array.isArray(ecommerce) &&
610      'string' === typeof ecommerce.currency &&
611      ecommerce.currency.trim() &&
612      isNumericValue(ecommerce.value) &&
613      isNumericValue(ecommerce.tax) &&
614      isNumericValue(ecommerce.shipping) &&
615      'string' === typeof ecommerce.payment_type &&
616      ecommerce.payment_type.trim() &&
617      Array.isArray(ecommerce.items) &&
618      ecommerce.items.length
619    );
620  }
621
622  function isValidBeginCheckoutEcommerce(ecommerce) {
623    return Boolean(
624      ecommerce &&
625      'object' === typeof ecommerce &&
626      !Array.isArray(ecommerce) &&
627      isValidCurrency(ecommerce.currency) &&
628      isNumericValue(ecommerce.value) &&
629      Array.isArray(ecommerce.items) &&
630      ecommerce.items.length &&
631      ecommerce.items.every(item => (
632        item &&
633        'object' === typeof item &&
634        !Array.isArray(item) &&
635        (
636          String(item.item_id || '').trim() ||
637          String(item.item_name || '').trim()
638        )
639      ))
640    );
641  }
642
643  function registerBeginCheckout() {
644    if (checkoutListenerRegistered) {
645      return;
646    }
647
648    checkoutListenerRegistered = true;
649
650    document.addEventListener('click', function (event) {
651      if (!event.isTrusted || (Number.isFinite(event.button) && 0 !== event.button)) {
652        return;
653      }
654
655      const target = event.target instanceof Element ? event.target : null;
656      const checkoutLink = target?.closest(CHECKOUT_LINK_SELECTOR);
657
658      if (
659        !checkoutLink ||
660        checkoutLink.matches('[disabled], [aria-disabled="true"]')
661      ) {
662        return;
663      }
664
665      const now = Date.now();
666
667      if (now - lastCheckoutActivation < 1000) {
668        return;
669      }
670
671      const viewCart = getMostRecentDataLayerEvent('view_cart');
672
673      if (!isValidViewCartEcommerce(viewCart?.ecommerce)) {
674        return;
675      }
676
677      const ecommerce = cloneEcommerce(viewCart.ecommerce);
678
679      if (!ecommerce) {
680        return;
681      }
682
683      if (!pushEcommerceEvent('begin_checkout', ecommerce)) {
684        return;
685      }
686
687      lastCheckoutActivation = now;
688    });
689  }
690
691  function hasMatchingAddToCartEvent(startIndex, sku) {
692    const dataLayer = getDataLayer();
693
694    if (!dataLayer) {
695      return false;
696    }
697
698    for (let index = Math.max(0, startIndex); index < dataLayer.length; index++) {
699      const entry = dataLayer[index];
700
701      if (
702        entry?.event === 'add_to_cart' &&
703        Array.isArray(entry.ecommerce?.items) &&
704        entry.ecommerce.items.some(item => String(item?.item_id || '') === sku)
705      ) {
706        return true;
707      }
708    }
709
710    return false;
711  }
712
713  function mapAddedItem(item, requestedQuantity) {
714    const sku = String(item?.sku || '').trim();
715    const productTitle = String(item?.productTitle || '').trim();
716    const price = centsToCurrency(item?.price);
717    const quantity = Number(requestedQuantity);
718
719    if (
720      !sku ||
721      !productTitle ||
722      null === price ||
723      !Number.isInteger(quantity) ||
724      quantity < 1
725    ) {
726      return null;
727    }
728
729    const mappedItem = {
730      item_id: sku,
731      item_name: productTitle,
732      price,
733      quantity
734    };
735    const variant = String(item?.productVariantTitle || '').trim();
736
737    if (variant) {
738      mappedItem.item_variant = variant;
739    }
740
741    return mappedItem;
742  }
743
744  function emitAddToCart(cart, submittedSku, requestedQuantity, dataLayerStartIndex = 0) {
745    try {
746      const sku = String(submittedSku || '').trim();
747      const matchingItems = Array.isArray(cart?.items)
748        ? cart.items.filter(item => String(item?.sku || '').trim() === sku)
749        : [];
750
751      if (!sku || 1 !== matchingItems.length) {
752        return false;
753      }
754
755      const item = mapAddedItem(matchingItems[0], requestedQuantity);
756      const priceCents = parseCents(matchingItems[0]?.price);
757      const value = null === priceCents
758        ? null
759        : centsToCurrency(priceCents * Number(requestedQuantity));
760
761      if (!item || null === value || hasMatchingAddToCartEvent(dataLayerStartIndex, item.item_id)) {
762        return false;
763      }
764
765      return pushEcommerceEvent('add_to_cart', {
766        currency: getCurrency(),
767        value,
768        items: [item]
769      });
770    } catch (error) {
771      return false;
772    }
773  }
774
775  function getDatasetPrice(element) {
776    const rawPrice = String(element?.dataset?.ga4ItemPrice || '').trim();
777
778    if (!rawPrice || !isNumericValue(rawPrice) || Number(rawPrice) < 0) {
779      return null;
780    }
781
782    return Number(rawPrice);
783  }
784
785  function mapAnalyticsElement(element, index = null, includeCurrency = false) {
786    const itemId = String(element?.dataset?.ga4ItemId || '').trim();
787    const itemName = String(element?.dataset?.ga4ItemName || '').trim();
788
789    if (!itemId || !itemName) {
790      return null;
791    }
792
793    const item = {
794      item_id: itemId,
795      item_name: itemName
796    };
797    const currency = getCurrency();
798    const price = getDatasetPrice(element);
799    const variant = String(element.dataset.ga4ItemVariant || '').trim();
800
801    if (includeCurrency && currency) {
802      item.currency = currency;
803    }
804
805    if (null !== price) {
806      item.price = price;
807    }
808
809    if (variant) {
810      item.item_variant = variant;
811    }
812
813    if (Number.isInteger(index) && index >= 0) {
814      item.index = index;
815    }
816
817    return item;
818  }
819
820  function getListImpressionState(listElement) {
821    if (!listImpressionStates.has(listElement)) {
822      listImpressionStates.set(listElement, {
823        currentFingerprint: '',
824        seenItemIds: new Set()
825      });
826    }
827
828    return listImpressionStates.get(listElement);
829  }
830
831  function emitViewItemList(listElement, options = {}) {
832    try {
833      if (!(listElement instanceof Element)) {
834        return false;
835      }
836
837      const listId = String(listElement.dataset.ga4ItemListId || '').trim();
838      const listName = String(listElement.dataset.ga4ItemListName || '').trim();
839      const currency = getCurrency();
840      const productElements = Array.from(listElement.querySelectorAll(LIST_ITEM_SELECTOR));
841      const requestedStartIndex = Number(options.startIndex);
842      const startIndex = Number.isInteger(requestedStartIndex) && requestedStartIndex >= 0
843        ? requestedStartIndex
844        : 0;
845      const reset = true === options.reset || 0 === startIndex;
846      const state = getListImpressionState(listElement);
847
848      if (!listId || !listName || !currency || !productElements.length) {
849        return false;
850      }
851
852      const allItems = productElements
853        .map((element, index) => mapAnalyticsElement(element, index, true))
854        .filter(Boolean);
855      const currentFingerprint = JSON.stringify({ listId, listName, items: allItems });
856      let items = allItems.filter(item => item.index >= startIndex);
857      let nextSeenItemIds;
858
859      if (reset) {
860        if (!items.length || currentFingerprint === state.currentFingerprint) {
861          return false;
862        }
863
864        nextSeenItemIds = new Set(items.map(item => item.item_id));
865      } else {
866        items = items.filter(item => !state.seenItemIds.has(item.item_id));
867
868        if (!items.length) {
869          return false;
870        }
871
872        nextSeenItemIds = new Set(state.seenItemIds);
873        items.forEach(item => nextSeenItemIds.add(item.item_id));
874      }
875
876      if (!pushEcommerceEvent('view_item_list', {
877        item_list_id: listId,
878        item_list_name: listName,
879        items
880      })) {
881        return false;
882      }
883
884      state.currentFingerprint = currentFingerprint;
885      state.seenItemIds = nextSeenItemIds;
886      return true;
887    } catch (error) {
888      return false;
889    }
890  }
891
892  function emitCustomPdpViewItem() {
893    try {
894      const productElement = document.querySelector(PDP_SELECTOR);
895      const currency = getCurrency();
896      const item = mapAnalyticsElement(productElement);
897
898      if (!productElement || !currency || !item) {
899        return false;
900      }
901
902      item.quantity = 1;
903
904      const fingerprint = JSON.stringify({
905        path: location.pathname,
906        item
907      });
908
909      if (pdpViewFingerprints.has(fingerprint)) {
910        return false;
911      }
912
913      const ecommerce = {
914        currency,
915        items: [item]
916      };
917
918      if (isNumericValue(item.price)) {
919        ecommerce.value = Number(item.price);
920      }
921
922      if (!pushEcommerceEvent('view_item', ecommerce)) {
923        return false;
924      }
925
926      pdpViewFingerprints.add(fingerprint);
927      return true;
928    } catch (error) {
929      return false;
930    }
931  }
932
933  function sumMonetaryLines(lines) {
934    if (!Array.isArray(lines)) {
935      return 0;
936    }
937
938    let total = 0;
939
940    for (const line of lines) {
941      const price = parseCents(line?.price);
942
943      if (null === price) {
944        return null;
945      }
946
947      total += price;
948    }
949
950    return centsToCurrency(total);
951  }
952
953  function mapOrderItem(item) {
954    const sku = String(item?.sku || '').trim();
955    const productTitle = String(item?.productTitle || '').trim();
956    const price = centsToCurrency(item?.price);
957    const quantity = Number(item?.quantity);
958
959    if (
960      !sku ||
961      !productTitle ||
962      null === price ||
963      !Number.isInteger(quantity) ||
964      quantity < 1
965    ) {
966      return null;
967    }
968
969    const mappedItem = {
970      item_id: sku,
971      item_name: productTitle,
972      price,
973      quantity
974    };
975    const brand = String(item?.vendor || '').trim();
976    const variant = String(item?.productVariantTitle || '').trim();
977
978    if (brand) {
979      mappedItem.item_brand = brand;
980    }
981
982    if (variant) {
983      mappedItem.item_variant = variant;
984    }
985
986    return mappedItem;
987  }
988
989  function hasDataLayerPurchase(transactionId) {
990    const dataLayer = getDataLayer();
991
992    return Boolean(dataLayer?.some(entry => (
993      entry?.event === 'purchase' &&
994      String(entry.ecommerce?.transaction_id || '') === transactionId
995    )));
996  }
997
998  function emitPurchase(order) {
999    try {
1000      if (!hasValidCheckoutMarker()) {
1001        return false;
1002      }
1003
1004      const transactionId = String(order?.orderNumber ?? '').trim();
1005      const value = centsToCurrency(order?.total);
1006      const tax = sumMonetaryLines(order?.taxes);
1007      const shipping = sumMonetaryLines(order?.shipping);
1008      const sourceItems = Array.isArray(order?.items) ? order.items : [];
1009      const items = sourceItems.map(mapOrderItem);
1010
1011      if (
1012        !transactionId ||
1013        null === value ||
1014        null === tax ||
1015        null === shipping ||
1016        !sourceItems.length ||
1017        items.some(item => null === item)
1018      ) {
1019        return false;
1020      }
1021
1022      const purchaseKey = getStorageKey('purchase', transactionId);
1023      const localStorage = getBrowserStorage('localStorage');
1024      const purchaseMarker = storageGet(localStorage, purchaseKey);
1025
1026      if (!purchaseKey || !purchaseMarker.success) {
1027        return false;
1028      }
1029
1030      if (null !== purchaseMarker.value) {
1031        return false;
1032      }
1033
1034      if (hasDataLayerPurchase(transactionId)) {
1035        storageSet(localStorage, purchaseKey, JSON.stringify({ timestamp: Date.now() }));
1036        clearCheckoutMarker();
1037        return false;
1038      }
1039
1040      if (!pushEcommerceEvent('purchase', {
1041        transaction_id: transactionId,
1042        currency: getCurrency(),
1043        value,
1044        tax,
1045        shipping,
1046        items
1047      })) {
1048        return false;
1049      }
1050
1051      storageSet(localStorage, purchaseKey, JSON.stringify({ timestamp: Date.now() }));
1052      clearCheckoutMarker();
1053      return true;
1054    } catch (error) {
1055      return false;
1056    }
1057  }
1058
1059  function getReceiptOrderId() {
1060    const pathSegments = location.pathname.split('/').filter(Boolean);
1061    const receiptIndex = pathSegments.lastIndexOf(RECEIPT_SEGMENT);
1062
1063    if (-1 === receiptIndex || !pathSegments[receiptIndex + 1]) {
1064      return '';
1065    }
1066
1067    try {
1068      return decodeURIComponent(pathSegments[receiptIndex + 1]);
1069    } catch (error) {
1070      return '';
1071    }
1072  }
1073
1074  function isMatchingLimitedOrderRequest(method, requestUrl, receiptOrderId) {
1075    if ('GET' !== String(method || 'GET').toUpperCase()) {
1076      return false;
1077    }
1078
1079    try {
1080      const url = new URL(String(requestUrl), location.href);
1081      const match = url.pathname.match(/^\/v2\/order\/([^/]+)\/limited\/?$/);
1082
1083      return Boolean(
1084        match &&
1085        'api.commerce7.com' === url.hostname &&
1086        decodeURIComponent(match[1]) === receiptOrderId
1087      );
1088    } catch (error) {
1089      return false;
1090    }
1091  }
1092
1093  function parseXhrJson(xhr) {
1094    if (xhr.response && 'object' === typeof xhr.response) {
1095      return xhr.response;
1096    }
1097
1098    const responseText = 'string' === typeof xhr.responseText
1099      ? xhr.responseText
1100      : xhr.response;
1101
1102    if ('string' !== typeof responseText || !responseText) {
1103      return null;
1104    }
1105
1106    try {
1107      return JSON.parse(responseText);
1108    } catch (error) {
1109      return null;
1110    }
1111  }
1112
1113  function installLimitedOrderObserver() {
1114    const receiptOrderId = getReceiptOrderId();
1115
1116    if (!receiptOrderId || !document.getElementById('c7-content') || !window.XMLHttpRequest) {
1117      return;
1118    }
1119
1120    const requestMatches = Symbol('foleyC7LimitedOrderRequest');
1121    const xhrPrototype = window.XMLHttpRequest.prototype;
1122    const originalOpen = xhrPrototype.open;
1123    const originalSend = xhrPrototype.send;
1124    let restored = false;
1125
1126    function restore() {
1127      if (restored) {
1128        return;
1129      }
1130
1131      restored = true;
1132
1133      if (xhrPrototype.open === interceptedOpen) {
1134        xhrPrototype.open = originalOpen;
1135      }
1136
1137      if (xhrPrototype.send === interceptedSend) {
1138        xhrPrototype.send = originalSend;
1139      }
1140    }
1141
1142    function interceptedOpen(method, url) {
1143      if (isMatchingLimitedOrderRequest(method, url, receiptOrderId)) {
1144        this[requestMatches] = true;
1145      } else if (this[requestMatches]) {
1146        delete this[requestMatches];
1147      }
1148
1149      return originalOpen.apply(this, arguments);
1150    }
1151
1152    function interceptedSend() {
1153      if (this[requestMatches]) {
1154        this.addEventListener('load', () => {
1155          if (this.status < 200 || this.status >= 300) {
1156            return;
1157          }
1158
1159          const order = parseXhrJson(this);
1160          restore();
1161
1162          if (order) {
1163            emitPurchase(order);
1164          }
1165        }, { once: true });
1166      }
1167
1168      return originalSend.apply(this, arguments);
1169    }
1170
1171    xhrPrototype.open = interceptedOpen;
1172    xhrPrototype.send = interceptedSend;
1173    window.setTimeout(restore, 120000);
1174  }
1175
1176  installDataLayerNormalizer();
1177  registerRemoveFromCartCapture();
1178  installLimitedOrderObserver();
1179
1180  return {
1181    emitAddToCart,
1182    emitCustomPdpViewItem,
1183    emitViewItemList,
1184    getDataLayerLength,
1185    getTenant,
1186    registerBeginCheckout
1187  };
1188})();
1189
1190window.foleyC7UiGa4Analytics = foleyC7UiGa4Analytics;
1191
1192
1193/* hide cents in C7 price if == ".00" */
1194document.querySelectorAll('.c7-buy-product').forEach(item => {
1195  new MutationObserver((mutationsList, observer) => {
1196    let priceWrapper = item.querySelector('.c7-product__add-to-cart__price');
1197    if (priceWrapper) {
1198      observer.disconnect();
1199      let priceEls = Array.from(priceWrapper.children).filter(el => !el.matches('.c7-sr-only,.c7-product__add-to-cart__price__variant'));
1200      priceEls.forEach(el => {
1201        let centsEl = el.querySelector('span:last-child');
1202        if (centsEl && centsEl.innerText == '.00') {
1203          centsEl.style.display = "none";
1204        }
1205      });
1206    }
1207  }).observe(item, { childList: true, subtree: true });
1208});
1209
1210
1211
1212
1213
1214
1215document.addEventListener("DOMContentLoaded", () => {
1216  /*
1217	  email:"[email protected]"
1218	  firstName:"Ron"
1219	  isClubMember:true
1220	  lastName:"Marcelle"
1221	*/
1222  let jwt = null;
1223  const API_BASE = 'https://api.commerce7.com/v2';
1224
1225  foleyC7UiGa4Analytics.registerBeginCheckout();
1226  foleyC7UiGa4Analytics.emitCustomPdpViewItem();
1227
1228  const getCookie = async (name) => {
1229    if ('cookieStore' in window) {
1230      return (await cookieStore.get(name))?.value;
1231    }
1232
1233    const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]+)`));
1234    return match ? match[1] : null;
1235  };
1236
1237  const setCookie = async (name, value, days = 365) => {
1238    if ('cookieStore' in window) {
1239      await cookieStore.set({
1240        name,
1241        value,
1242        expires: Date.now() + days * 24 * 60 * 60 * 1000,
1243        path: '/',
1244        sameSite: 'lax',
1245        secure: location.protocol === 'https:'
1246      });
1247      return;
1248    }
1249
1250    document.cookie = [
1251      `${name}=${encodeURIComponent(value)}`,
1252      `expires=${new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString()}`,
1253      'path=/',
1254      'SameSite=Lax',
1255      location.protocol === 'https:' ? 'Secure' : ''
1256    ].filter(Boolean).join('; ');
1257  };
1258
1259  async function getC7JWT(force = false) {
1260    if (jwt && !force) {
1261      return jwt;
1262    }
1263
1264    const token = await getCookie("customerToken");
1265    jwt = parseC7JWT(token);
1266    return jwt;
1267  }
1268
1269  function parseC7JWT(token) {
1270    if (!token) return;
1271    const base64Url = token.split('.')[1];
1272    const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
1273    const jsonPayload = decodeURIComponent(
1274      window.atob(base64)
1275        .split('')
1276        .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
1277        .join('')
1278    );
1279    return JSON.parse(jsonPayload);
1280  }
1281
1282  async function updateC7JWT() {
1283    jwt = await getC7JWT(true);
1284    return jwt;
1285  }
1286
1287  if ('cookieStore' in window) {
1288    cookieStore.addEventListener('change', (e) => {
1289      if (e.changed.length && e.changed[0].name === 'customerToken') {
1290        updateC7JWT().then(() => {
1291          document.querySelectorAll('c7-user-menu').forEach(el => el.buildMenu());
1292        });
1293      }
1294    });
1295  }
1296
1297  function getTenant() {
1298    return foleyC7UiGa4Analytics.getTenant();
1299  }
1300
1301  function getHeaders() {
1302    const tenant = getTenant();
1303
1304    if (!tenant) {
1305      throw new Error('Could not find Commerce7 tenant.');
1306    }
1307
1308    return {
1309      'Content-Type': 'application/json',
1310      'Accept': 'application/json',
1311      'Pragma': 'no-cache',
1312      'tenant': tenant,
1313      'tenantId': tenant
1314    };
1315  }
1316
1317  async function createCart() {
1318    const response = await fetch(`${API_BASE}/cart`, {
1319      method: 'POST',
1320      credentials: 'omit',
1321      mode: 'cors',
1322      headers: getHeaders(),
1323      body: JSON.stringify({
1324        channel: 'Web',
1325        connectionInformation: {
1326          userAgent: navigator.userAgent
1327        }
1328      })
1329    });
1330
1331    if (!response.ok) {
1332      const text = await response.text().catch(() => '');
1333      throw new Error(`Create cart failed: ${response.status} ${text}`);
1334    }
1335
1336    const cart = await response.json();
1337
1338    if (!cart?.id) {
1339      throw new Error('Create cart failed: missing cart id');
1340    }
1341
1342    await setCookie('cartId', cart.id);
1343    return cart.id;
1344  }
1345
1346  async function ensureCartId() {
1347    return await getCookie('cartId') || await createCart();
1348  }
1349
1350  async function addToCart({ cartId, sku, quantity = 1 }) {
1351    const response = await fetch(`${API_BASE}/cart/${encodeURIComponent(cartId)}/item`, {
1352      method: 'POST',
1353      credentials: 'omit',
1354      mode: 'cors',
1355      headers: getHeaders(),
1356      body: JSON.stringify({ sku, quantity })
1357    });
1358
1359    if (!response.ok) {
1360      const text = await response.text().catch(() => '');
1361      throw new Error(`Add to cart failed: ${response.status} ${text}`);
1362    }
1363
1364    return response.json();
1365  }
1366
1367
1368
1369
1370
1371  /* CUSTOM ELEMENTS */
1372	customElements.define('c7-user-menu', class C7UserMenu extends HTMLElement {
1373		constructor() {
1374			super();
1375
1376			this.logo = this.innerHTML;
1377			this.innerHTML = '';
1378			this._scaffoldMenu();
1379
1380			/*cookieStore.addEventListener('change', (e) => {
1381				if (e.changed.length && e.changed[0].name === 'customerToken') {
1382					this._updateToken();
1383				}
1384			});*/
1385		}
1386
1387		connectedCallback() {
1388      getC7JWT().then(x => {
1389        this.jwt = x;
1390        this.buildMenu();
1391      });
1392		}
1393
1394		buildMenu() {
1395			if (this.jwt) {
1396				this.namePlate.textContent = `Hi ${this.jwt.firstName}`;
1397				this.menuWrapper.innerHTML = this._menuLoggedInContent();
1398			} else {
1399				this.namePlate.textContent = '';
1400				this.menuWrapper.innerHTML = this._menuLoggedOutContent();
1401			}
1402		}
1403
1404		_scaffoldMenu() {
1405			let wrapper = document.createElement('div');
1406			let closeButton = document.createElement('button');
1407			let logo = document.createElement('span');
1408			this.menuWrapper = document.createElement('div');
1409			this.dialog = document.createElement('dialog');
1410			this.namePlate = document.createElement('span');
1411
1412			this.dialog.id = 'foley-c7-account-dialog';
1413			this.dialog.classList.add('slide-in');
1414      
1415      this.dialog.addEventListener("click", ({target}) => {
1416        if (target === this.dialog) {
1417          this.dialog.close();
1418        }
1419      });
1420			
1421			wrapper.classList.add('wrapper');
1422			
1423			closeButton.setAttribute('commandfor', 'foley-c7-account-dialog');
1424			closeButton.setAttribute('command', 'close');
1425			closeButton.textContent = 'Close';
1426
1427			this.namePlate.classList.add('name-plate');
1428			
1429			logo.classList.add('logo');
1430			logo.innerHTML = this.logo;
1431			
1432			this.menuWrapper.classList.add('menu-wrapper','dialog-main-menu');
1433			
1434			this.dialog.append(wrapper);
1435			wrapper.append(closeButton);
1436			wrapper.append(this.namePlate);
1437			wrapper.append(logo);
1438			wrapper.append(this.menuWrapper);
1439			this.append(this.dialog);
1440		}
1441
1442		_menuLoggedInContent() {
1443			return `<ul>
1444      	<li><a href="/profile/">Dashboard</a></li>
1445      	<li><a href="/profile/club-membership">Club Memberships</a></li>
1446      	<li><a href="/profile/order-history">Order History</a></li>
1447      	<li><a href="/profile/reservation">Reservations</a></li>
1448      	<li><a href="/profile/account">Account Details</a></li>
1449      	<li><a href="/profile/logout">Log out</a></li>
1450    	</ul>`;
1451		}
1452
1453		_menuLoggedOutContent() {
1454			return '<ul><li><a href="/profile/">Login</a></li></ul>'
1455		}
1456
1457		/*_updateToken() {
1458			getC7JWT().then(x => {
1459        this.jwt = parseC7JWT(x);
1460        this.buildMenu();
1461      });
1462		}*/
1463
1464		/*async _getJwt() {
1465			let x = await cookieStore.get("customerToken");
1466			return x?.value;
1467		}
1468
1469		_parseJwt(token) {
1470			if (!token) return;
1471			var base64Url = token.split('.')[1];
1472  		var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
1473  		var jsonPayload = decodeURIComponent(window.atob(base64).split('').map((c) =>
1473 '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join(''));
1474  		return JSON.parse(jsonPayload);
1475		}*/
1476
1477	});
1478
1479  document.addEventListener('click', async function (event) {
1480    const button = event.target.closest('.js-c7-add-to-cart');
1481    if (!button) return;
1482
1483    event.preventDefault();
1484
1485    const sku = button.dataset.sku;
1486    const quantity = Math.max(1, Number(button.form?.elements?.qty?.value) || Number(button.dataset.quantity) || 1);
1487
1488    if (!sku) {
1489      alert('Missing SKU.');
1490      return;
1491    }
1492
1493    button.disabled = true;
1494
1495    try {
1496      const dataLayerStartIndex = foleyC7UiGa4Analytics.getDataLayerLength();
1497      const cartId = await ensureCartId();
1498      const cart = await addToCart({ cartId, sku, quantity });
1499
1500      foleyC7UiGa4Analytics.emitAddToCart(cart, sku, quantity, dataLayerStartIndex);
1501
1502      window.c7action?.reloadCart?.();
1503      window.c7action?.showSideCart?.();
1504    } catch (err) {
1505      console.error(err);
1506      alert(err.message || 'Could not add item to cart.');
1507    } finally {
1508      button.disabled = false;
1509    }
1510  });
1511
1512
1513
1514  let membershipLink = document.querySelector('article.full.type-wine .membership-link');
1515  if (membershipLink) {
1516    getC7JWT().then(data => {
1517      if (!data || data.isClubMember === false) {
1518        membershipLink.style.display = "initial";
1519      }
1520    });
1521  }
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531  customElements.define('accordion-tabs', class AccordionTabs extends HTMLElement {
1532		#allowMultiple = false;
1533		#accordionID = null;
1534		
1535		constructor() {
1536			super();
1537			this.#allowMultiple = this.allowMultiple();
1538			this.#accordionID = crypto.randomUUID();
1539      this.breakpoint = this.hasAttribute('breakpoint') ? this.getAttribute('breakpoint') : 700;
1540			let originalItems = Array.from(this.children).filter(item => item.matches('[title]'));
1541      if (this.breakpoint == 0) {
1542        this.breakpoint = Infinity;
1543      }
1544
1545			this.labels = originalItems.map((item,i) => {
1546				let button = document.createElement('button');
1547				button.innerHTML = item.title;
1548				button.addEventListener("click", () => {
1549					this.items[i].open = true;
1550					this.labels.filter(el =>
1550 el.classList.contains("active")).forEach(el => el.classList.remove("active"));
1551					button.parentNode.querySelector('.active')?.classList.remove("active");
1552					button.classList.add("active");
1553				});
1554				if (i === 0) {
1555					button.classList.add("active");
1556				}
1557				return button;
1558			});
1559			this.items = originalItems.map(item => {
1560				let details = document.createElement('details');
1561				if (!this.#allowMultiple) {
1562					details.name = this.#accordionID;
1563				}
1564				
1565				details.innerHTML = `<summary>${item.title}</summary>${item.innerHTML}`;
1566				return details;
1567			});
1568			let labelWrap = document.createElement('div');
1569			labelWrap.className = "label-wrap";
1570			labelWrap.append(...this.labels);
1571			
1572			let accordionWrap = document.createElement('div');
1573			accordionWrap.className = "accordion-wrap";
1574			accordionWrap.append(...this.items);
1575			
1576			this.innerHTML = '';
1577			this.append(labelWrap, accordionWrap);
1578		}
1579		
1580		connectedCallback() {
1581			//this.getBoundingClientRect().width
1582			new ResizeObserver((e) => {
1583				if (e[0].borderBoxSize[0].inlineSize > this.breakpoint) {
1584          this.classList.add("element-large");
1585          this.classList.remove("element-small");
1586					if (!this.querySelector('details[open]')) {
1587						this.items[0].open = true;
1588					}
1589				} else {
1590          this.classList.add("element-small");
1591          this.classList.remove("element-large");
1592        }
1593			}).observe(this);
1594		}
1595		
1596		static get observedAttributes() {
1597			return ['allow-multiple'];
1598		}
1599		
1600		attributeChangedCallback(name, oldValue, newValue) {
1601			if (name === "allow-multiple") {
1602				this.#allowMultiple = this.allowMultiple();
1603				
1604				if (this.#allowMultiple) {
1605					this.items.forEach(item => item.removeAttribute("name"));				
1606				} else {
1607					this.items.forEach(item => item.name = this.#accordionID);
1608				}
1609			}
1610		}
1611		
1612		allowMultiple() {
1613			return this.hasAttribute("allow-multiple")
1614		}
1615	});
1616
1617
1618  /* header */
1619  document.querySelector('#foley-c7-account-icon')?.addEventListener('click', (evt) => {
1620    evt.preventDefault();
1621    /*getC7JWT().then(jwt => {
1622      if (jwt) {
1623        let drawer = document.querySelector(`#${evt.target.getAttribute('commandfor')}`);
1624        drawer.showModal();
1625      } else {
1626        window.open("/profile/", "_self");
1627      }
1628    });*/
1629    window.open("/profile/", "_self");
1630  });
1631
1632
1633});
1634
1635
1636
1637
1638/************
1639**** PLP ****
1640************/
1641addEventListener("DOMContentLoaded", () => {
1642	/*document.querySelectorAll('.foley-c7-ui-wine-listing__control:is([data-control-type="checkbox"], [data-control-type="radio"]').forEach(elem => {*/
1643  document.querySelectorAll('.foley-c7-ui-wine-listing__control').forEach(elem => {
1644    let label = elem.querySelector('label');
1645    if (label.children.length===0) {
1646      elem.querySelector('label').addEventListener("click", () => elem.classList.toggle("active"));
1647
1648      elem.addEventListener("click", (e) => {
1649        if (e.target.matches('input[type="radio"]')) {
1650          elem.classList.remove("active");
1651        }
1652      });
1653    }
1654	});
1655  
1656  let wineListingControls = document.querySelector('.foley-c7-ui-wine-listing__controls');
1657  document.querySelector('#foley-c7-ui-wine-listing__controls-toggle')?.addEventListener("click", () => {
1658    if (matchMedia('max-width:1200px')) {
1659      wineListingControls?.classList.toggle('active');
1660    }
1661  });
1662  
1663  document.querySelectorAll('.foley-c7-ui-wine-listing__controls-close').forEach(button => {
1664    let toggle = button.closest('.foley-c7-ui-wine-listing__controls');
1665    button.addEventListener("click", () => {
1666      toggle.classList.remove('active');
1667    });
1668  });
1669});
1670
1671/************
1672**** PLP ****
1673************/
1674addEventListener("DOMContentLoaded", () => {
1675  document.querySelector('#back-top-shop')?.addEventListener("click", e => {
1676    if (document.referrer.indexOf('shop')>-1)  {
1677      e.preventDefault();
1678      history.back();
1679    }
1680  });
1681});
1682
1683
1684/************************
1685**** MEMBERSHIP PAGE ****
1686************************/
1687addEventListener("DOMContentLoaded", () => {
1688  /*document.querySelectorAll('.club-membership-type-picker').forEach(el => {
1689    let parent = el.closest('.kb-row-layout-wrap');
1690    let buttons = Array.from(parent.querySelectorAll('.c7-club-join-button'));
1691    let toggleButtons = () => {
1692      console.log(el.value);
1693      buttons.forEach(button => button.style.display = button.getAttribute('data-club-slug') === el.value ? "block" : "none");
1694    }	
1695    el.addEventListener("change", () => toggleButtons());
1696    toggleButtons();
1697  });*/
1698  
1699  document.querySelectorAll('.club-picker').forEach(el => {
1700    let buttons = Array.from(el.querySelectorAll('.c7-club-join-button'));
1701    let picker = el.querySelector('select');
1702    let flexType = el.classList.contains('inline') ? "inline-flex" : "flex";
1703    let toggleButtons = () => {
1704      if (picker.value) {
1705        buttons.forEach(button => button.style.display = button.getAttribute('data-club-slug') === picker.value ? flexType : "none");
1706        el.classList.remove('disabled');
1707      } else {
1708        el.classList.add('disabled');
1709        buttons.forEach((button,i) => button.style.display = i===0 ? flexType : "none");
1710      }
1711    }
1712    picker.addEventListener("change", () => toggleButtons());
1713    toggleButtons();
1714  });
1715});
1716
1717
1718
1719
1720
1721/************************
1722**** Checkout Teaser ****
1723************************/
1724
1725/*addEventListener("DOMContentLoaded", () => {
1726  const c7Content = document.querySelector('#c7-content');
1727  const checkoutTeaser = document.querySelector('.foley-c7-ui-checkout-teaser');
1728  
1729  function debounce(func, delay = 100) {
1730    let timer;
1731    return (...args) => {
1732      clearTimeout(timer);
1733      timer = setTimeout(() => func(...args), delay);
1734    };
1735  }
1736  
1737  if (c7Content && checkoutTeaser) {
1738    setTimeout(() => {
1739      new ResizeObserver((entries) => {
1740        c7Content.style.paddingTop = `${entries[0].borderBoxSize[0].blockSize}px`;
1741        checkoutTeaser.classList.add("loaded");
1742      }).observe(checkoutTeaser);
1743    }, 500);
1744
1745  }
1746});*/
1747;
1748!function(){var t={831:function(){const t=document.querySelectorAll(".js-accordion-block:not(.js-accordion-disable-auto-open)");function e(t){const e=t.closest(".js-accordion-block").querySelectorAll(".js-accordion-item"),n=t.getAttribute("aria-expanded"),r=t.nextElementSibling;"false"===n?(Array.from(e).forEach((t=>{const e=t.querySelector(".js-accordion-toggle");e.setAttribute("aria-expanded","false"),e.nextElementSibling.setAttribute("aria-hidden","true")})),t.setAttribute("aria-expanded","true"),r.setAttribute("aria-hidden","false")):(t.setAttribute("aria-expanded","false"),r.setAttribute("aria-hidden","true"))}function n(t){let n=t.target;for(;n;){if("BUTTON"===n.nodeName&&/js-accordion-toggle/.test(n.className)){e(n);break}n=n.parentNode}}Array.from(t).forEach((t=>{const e=t.querySelector(".js-accordion-toggle");e.setAttribute("aria-expanded","true"),e.nextElementSibling.setAttribute("aria-hidden","false")})),document.addEventListener?document.addEventListener("click",n,!1):document.attachEvent&&document.attachEvent("onclick",n)},417:function(){"use strict";class t{constructor(t){this.buttonEl=t,this.parentEl=this.buttonEl.parentElement,this.contentEl=this.buttonEl.nextElementSibling,this.open="true"===this.buttonEl.getAttribute("aria-expanded"),this.buttonEl.addEventListener("click",this.onButtonClick.bind(this))}onButtonClick(){this.toggle(!this.open)}toggle(t){t!==this.open&&(this.open=t,this.buttonEl.setAttribute("aria-expanded",`${t}`),t?(this.contentEl.removeAttribute("hidden"),this.parentEl.classList.add("open")):(this.contentEl.setAttribute("hidden",""),this.parentEl.classList.remove("open")))}open(){this.toggle(!0)}close(){this.toggle(!1)}}function e(){document.querySelectorAll(".js-event-accordion-trigger").forEach((e=>{window.innerWidth<782?new t(e):(e.parentNode.classList.add("open"),e.setAttribute("aria-expanded","true"),e.nextElementSibling.removeAttribute("hidden"))}))}document.addEventListener("DOMContentLoaded",e),window.addEventListener("resize",e)},769:function(){function t(t){const e=function(t){const e={classes:{slide:"js-carousel__slide"},config:{type:"carousel",gap:0}};switch(t){case"carousel-block":return{...e,classes:{...e.classes},config:{...e.config,animationDuration:0,touchRatio:0}};case"hero-img-carousel":return{...e,classes:{...e.classes},config:{...e.config}};case"footer-gallery":return{...e,classes:{...e.classes},config:{...e.config,perView:5,perTouch:1,autoplay:3e3,animationTimingFunc:"ease",animationDuration:1e3,gap:10,breakpoints:{1024:{perView:4},768:{perView:3},600:{perView:2}}}};case"logo-carousel":return{...e,classes:{...e.classes},config:{...e.config,perView:6,perTouch:1,autoplay:3e3,animationTimingFunc:"ease",animationDuration:1e3,gap:40,breakpoints:{1024:{perView:4},768:{perView:2},600:{perView:1}}}};default:return{}}}(t.dataset.carousel_config);new Glide(t,e.config).mount()}function e(){const e=document.querySelectorAll(".js-glide-carousel");if(e.length)for(let n=0,r=e.length;n<r;n++)t(e[n])}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e()},432:function(){const t=document.querySelectorAll([".menu-item-has-children a",".menu-item-has-children svg"]),e=document.querySelectorAll([".mega-menu-content a",".mega-menu-content svg"]),n=document.querySelectorAll('.menu-item a[href="#"]');
1748n&&Array.from(n).forEach((t=>{t.addEventListener("click",(t=>{t.preventDefault()}))})),t&&t.forEach((t=>{t.addEventListener("click",(function(){if(window.innerWidth>"1200")return;const t=this.parentNode;t.classList.contains("open")?(t.classList.remove("open"),t.setAttribute("aria-expanded","false")):(t.classList.add("open"),t.setAttribute("aria-expanded","true"))}),!1)})),e&&e.forEach((t=>{t.addEventListener("click",(function(){const t=this.parentNode,e=document.querySelector(".menu-item.open");t.classList.contains("open")?(t.classList.remove("open"),t.setAttribute("aria-expanded","false")):(t.classList.add("open"),t.setAttribute("aria-expanded","true"),e&&window.innerWidth>"1200"&&(e.classList.remove("open"),e.setAttribute("aria-expanded","false")))}),!1)}))},473:function(){!function(){const t=function(t){const e=document.body,n=document.getElementById(t+"-open-menu"),r=document.getElementById(t+"-close-menu"),i=document.querySelectorAll(".menu-item-has-children");let o=!1;function a(){i&&i.forEach((t=>{t.setAttribute("aria-expanded","false"),t.classList.remove("open")}))}function s(){e.classList.remove(t+"-navigation-open"),e.classList.remove("lock-scrolling"),a(),o=!1}n&&r&&(n.onclick=function(){e.classList.add(t+"-navigation-open"),e.classList.add("lock-scrolling"),o=!0,r.focus()},r.onclick=function(){s(),n.focus()}),window.onresize=function(){"1199"<window.innerWidth&&!0===o&&(s(),a())},document.addEventListener("keydown",(function(r){if(!e.classList.contains(t+"-navigation-open"))return;let i=document.getElementById("masthead").querySelectorAll("a");i=Array.prototype.slice.call(i);const o=9===r.keyCode,c=r.shiftKey,u=27===r.keyCode,l=document.activeElement,d=i[i.length-1],f=i[0];u&&(r.preventDefault(),e.classList.remove(t+"-navigation-open","lock-scrolling"),n.focus(),s(),a()),!c&&o&&d===l&&(r.preventDefault(),f.focus()),c&&o&&f===l&&(r.preventDefault(),d.focus()),o&&f===d&&r.preventDefault()}))};window.addEventListener("load",(function(){new t("primary")}))}()}},e={};function n(r){var i=e[r];if(void 0!==i)return i.exports;var o=e[r]={exports:{}};return t[r](o,o.exports,n),o.exports}n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),function(){"use strict";function t(){return(t=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t}).apply(this,arguments)}function e(t){var e={exports:{}};return t(e,e.exports),e.exports}n(831),n(417),"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:"undefined"!=typeof self&&self;var r=e((function(t,e){t.exports=function(){var t="millisecond",e="second",n="minute",r="hour",i="day",o="week",a="month",s="quarter",c="year",u="date",l=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,d=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,f={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_")},h=function(t,e,n){var r=String(t);return!r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},p={s:h,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?"+":"-")+h(r,2,"0")+":"+h(i,2,"0")},m:function t(e,n){if(e.date()<n.date())return-t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),i=e.clone().add(r,a),o=n-i<0,s=e.clone().add(r+(o?-1:1),a);return+(-(r+(n-i)/(o?i-s:s-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(l){return{M:a,y:c,w:o,d:i,D:u,h:r,m:n,s:e,ms:t,Q:s}[l]||String(l||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},m="en",g={};g[m]=f;var y=function(t){return t instanceof w},$=function(t,e,n){var r;if(!t)return m;if("string"==typeof t)g[t]&&(r=t),e&&(g[t]=e,r=t);else{var i=t.name;g[i]=t,r=i}return!n&&r&&(m=r),r||!n&&m},v=function(t,e){if(y(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new w(n)},b=p;b.l=$,b.i=y,b.w=function(t,e){return v(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var w=function(){function f(t){this.$L=$(t.locale,null,!0),this.parse(t)}var h=f.prototype;return h.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match(l);if(r){var i=r[2]-1||0,o=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,o)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,o)}}return new Date(e)}(t),this.$x=t.x||{},this.init()},h.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},h.$utils=function(){return b},h.isValid=function(){return!("Invalid Date"===this.$d.toString())},h.isSame=function(t,e){var n=v(t);return this.startOf(e)<=n&&n<=this.endOf(e)},h.isAfter=function(t,e){return v(t)<this.startOf(e)},h.isBefore=function(t,e){return this.endOf(e)<v(t)},h.$g=function(t,e,n){return b.u(t)?this[e]:this.set(n,t)},h.unix=function(){return Math.floor(this.valueOf()/1e3)},h.valueOf=function(){return this.$d.getTime()},h.startOf=function(t,s){var l=this,d=!!b.u(s)||s,f=b.p(t),h=function(t,e){var n=b.w(l.$u?Date.UTC(l.$y,e,t):new Date(l.$y,e,t),l);return d?n:n.endOf(i)},p=function(t,e){return b.w(l.toDate()[t].apply(l.toDate("s"),(d?[0,0,0,0]:[23,59,59,999]).slice(e)),l)},m=this.$W,g=this.$M,y=this.$D,$="set"+(this.$u?"UTC":"");switch(f){case c:return d?h(1,0):h(31,11);case a:return d?h(1,g):h(0,g+1);case o:var v=this.$locale().weekStart||0,w=(m<v?m+7:m)-v;return h(d?y-w:y+(6-w),g);case i:case u:return p($+"Hours",0);case r:return p($+"Minutes",1);case n:return p($+"Seconds",2);case e:return p($+"Milliseconds",3);default:return this.clone()}},h.endOf=function(t){return this.startOf(t,!1)},h.$set=function(o,s){var l,d=b.p(o),f="set"+(this.$u?"UTC":""),h=(l={},l[i]=f+"Date",l[u]=f+"Date",l[a]=f+"Month",l[c]=f+"FullYear",l[r]=f+"Hours",l[n]=f+"Minutes",l[e]=f+"Seconds",l[t]=f+"Milliseconds",l)[d],p=d===i?this.$D+(s-this.$W):s;if(d===a||d===c){var m=this.clone().set(u,1);
1748m.$d[h](p),m.init(),this.$d=m.set(u,Math.min(this.$D,m.daysInMonth())).$d}else h&&this.$d[h](p);return this.init(),this},h.set=function(t,e){return this.clone().$set(t,e)},h.get=function(t){return this[b.p(t)]()},h.add=function(t,s){var u,l=this;t=Number(t);var d=b.p(s),f=function(e){var n=v(l);return b.w(n.date(n.date()+Math.round(e*t)),l)};if(d===a)return this.set(a,this.$M+t);if(d===c)return this.set(c,this.$y+t);if(d===i)return f(1);if(d===o)return f(7);var h=(u={},u[n]=6e4,u[r]=36e5,u[e]=1e3,u)[d]||1,p=this.$d.getTime()+t*h;return b.w(p,this)},h.subtract=function(t,e){return this.add(-1*t,e)},h.format=function(t){var e=this;if(!this.isValid())return"Invalid Date";var n=t||"YYYY-MM-DDTHH:mm:ssZ",r=b.z(this),i=this.$locale(),o=this.$H,a=this.$m,s=this.$M,c=i.weekdays,u=i.months,l=function(t,r,i,o){return t&&(t[r]||t(e,n))||i[r].substr(0,o)},f=function(t){return b.s(o%12||12,t,"0")},h=i.meridiem||function(t,e,n){var r=t<12?"AM":"PM";return n?r.toLowerCase():r},p={YY:String(this.$y).slice(-2),YYYY:this.$y,M:s+1,MM:b.s(s+1,2,"0"),MMM:l(i.monthsShort,s,u,3),MMMM:l(u,s),D:this.$D,DD:b.s(this.$D,2,"0"),d:String(this.$W),dd:l(i.weekdaysMin,this.$W,c,2),ddd:l(i.weekdaysShort,this.$W,c,3),dddd:c[this.$W],H:String(o),HH:b.s(o,2,"0"),h:f(1),hh:f(2),a:h(o,a,!0),A:h(o,a,!1),m:String(a),mm:b.s(a,2,"0"),s:String(this.$s),ss:b.s(this.$s,2,"0"),SSS:b.s(this.$ms,3,"0"),Z:r};return n.replace(d,(function(t,e){return e||p[t]||r.replace(":","")}))},h.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},h.diff=function(t,u,l){var d,f=b.p(u),h=v(t),p=6e4*(h.utcOffset()-this.utcOffset()),m=this-h,g=b.m(this,h);return g=(d={},d[c]=g/12,d[a]=g,d[s]=g/3,d[o]=(m-p)/6048e5,d[i]=(m-p)/864e5,d[r]=m/36e5,d[n]=m/6e4,d[e]=m/1e3,d)[f]||m,l?g:b.a(g)},h.daysInMonth=function(){return this.endOf(a).$D},h.$locale=function(){return g[this.$L]},h.locale=function(t,e){if(!t)return this.$L;var n=this.clone(),r=$(t,e,!0);return r&&(n.$L=r),n},h.clone=function(){return b.w(this.$d,this)},h.toDate=function(){return new Date(this.valueOf())},h.toJSON=function(){return this.isValid()?this.toISOString():null},h.toISOString=function(){return this.$d.toISOString()},h.toString=function(){return this.$d.toUTCString()},f}(),D=w.prototype;return v.prototype=D,[["$ms",t],["$s",e],["$m",n],["$H",r],["$W",i],["$M",a],["$y",c],["$D",u]].forEach((function(t){D[t[1]]=function(e){return this.$g(e,t[0],t[1])}})),v.extend=function(t,e){return t.$i||(t(e,w,v),t.$i=!0),v},v.locale=$,v.isDayjs=y,v.unix=function(t){return v(1e3*t)},v.en=g[m],v.Ls=g,v.p={},v}()})),i=e((function(t,e){t.exports=function(t,e,n){var r=e.prototype;n.utc=function(t){return new e({date:t,utc:!0,args:arguments})},r.utc=function(t){var e=n(this.toDate(),{locale:this.$L,utc:!0});return t?e.add(this.utcOffset(),"minute"):e},r.local=function(){return n(this.toDate(),{locale:this.$L,utc:!1})};var i=r.parse;r.parse=function(t){t.utc&&(this.$u=!0),this.$utils().u(t.$offset)||(this.$offset=t.$offset),i.call(this,t)};var o=r.init;r.init=function(){if(this.$u){var t=this.$d;this.$y=t.getUTCFullYear(),this.$M=t.getUTCMonth(),this.$D=t.getUTCDate(),this.$W=t.getUTCDay(),this.$H=t.getUTCHours(),this.$m=t.getUTCMinutes(),this.$s=t.getUTCSeconds(),this.$ms=t.getUTCMilliseconds()}else o.call(this)};var a=r.utcOffset;r.utcOffset=function(t,e){var n=this.$utils().u;if(n(t))return this.$u?0:n(this.$offset)?a.call(this):this.$offset;var r=Math.abs(t)<=16?60*t:t,i=this;if(e)return i.$offset=r,i.$u=0===t,i;if(0!==t){var o=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();(i=this.local().add(r+o,"minute")).$offset=r,i.$x.$localOffset=o}else i=this.utc();return i};var s=r.format;r.format=function(t){return s.call(this,t||(this.$u?"YYYY-MM-DDTHH:mm:ss[Z]":""))},r.valueOf=function(){var t=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||(new Date).getTimezoneOffset());return this.$d.valueOf()-6e4*t},r.isUTC=function(){return!!this.$u},r.toISOString=function(){return this.toDate().toISOString()},r.toString=function(){return this.toDate().toUTCString()};var c=r.toDate;r.toDate=function(t){return"s"===t&&this.$offset?n(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():c.call(this)};var u=r.diff;r.diff=function(t,e,r){if(t&&this.$u===t.$u)return u.call(this,t,e,r);var i=this.local(),o=n(t).local();return u.call(i,o,e,r)}}})),o=new RegExp("%[a-f0-9]{2}","gi"),a=new RegExp("(%[a-f0-9]{2})+","gi");function s(t,e){try{return decodeURIComponent(t.join(""))}catch(t){}if(1===t.length)return t;var n=t.slice(0,e=e||1),r=t.slice(e);return Array.prototype.concat.call([],s(n),s(r))}function c(t){try{return decodeURIComponent(t)}catch(r){for(var e=t.match(o),n=1;n<e.length;n++)e=(t=s(e,n).join("")).match(o);return t}}var u=function(t){if("string"!=typeof t)throw new TypeError("Expected `encodedURI` to be of type `string`, got `"+typeof t+"`");try{return t=t.replace(/\+/g," "),decodeURIComponent(t)}catch(e){return function(t){for(var e={"%FE%FF":"��","%FF%FE":"��"},n=a.exec(t);n;){try{e[n[0]]=decodeURIComponent(n[0])}catch(t){var r=c(n[0]);r!==n[0]&&(e[n[0]]=r)}n=a.exec(t)}e["%C2"]="�";for(var i=Object.keys(e),o=0;o<i.length;o++){var s=i[o];t=t.replace(new RegExp(s,"g"),e[s])}return t}(t)}},l=(t,e)=>{if("string"!=typeof t||"string"!=typeof e)throw new TypeError("Expected the arguments to be of type `string`");if(""===e)return[t];const n=t.indexOf(e);return-1===n?[t]:[t.slice(0,n),t.slice(n+e.length)]},d=function(t,e){for(var n={},r=Object.keys(t),i=Array.isArray(e),o=0;o<r.length;o++){var a=r[o],s=t[a];(i?-1!==e.indexOf(a):e(a,s,t))&&(n[a]=s)}return n},f=e((function(t,e){function n(t){if("string"!=typeof t||1!==t.length)throw new TypeError("arrayFormatSeparator must be single character string")}function r(t,e){return e.encode?e.strict?encodeURIComponent(t).replace(/[!'()*]/g,(t=>`%${t.charCodeAt(0).toString(16).toUpperCase()}`)):encodeURIComponent(t):t}function i(t,e){return e.decode?u(t):t}function o(t){return Array.isArray(t)?t.sort():"object"==typeof t?o(Object.keys(t)).sort(((t,e)=>Number(t)-Number(e))).map((e=>t[e])):t}function a(t){const e=t.indexOf("#");return-1!==e&&(t=t.slice(0,e)),t}function s(t){const e=(t=a(t)).indexOf("?");return-1===e?"":t.slice(e+1)}function c(t,e){return e.parseNumbers&&!Number.isNaN(Number(t))&&"string"==typeof t&&""!==t.trim()?t=Number(t):!e.parseBooleans||null===t||"true"!==t.toLowerCase()&&"false"!==t.toLowerCase()||(t="true"===t.toLowerCase()),t}function f(t,e){n((e=Object.assign({decode:!0,sort:!0,arrayFormat:"none",arrayFormatSeparator:",",parseNumbers:!1,parseBooleans:!1},e)).arrayFormatSeparator);const r=function(t){let e;switch(t.arrayFormat){case"index":return(t,n,r)=>{e=/\[(\d*)\]$/.exec(t),t=t.replace(/\[\d*\]$/,""),e?(void 0===r[t]&&(r[t]={}),r[t][e[1]]=n):r[t]=n};case"bracket":return(t,n,r)=>{e=/(\[\])$/.exec(t),r[t=t.replace(/\[\]$/,"")]=e?void 0!==r[t]?[].concat(r[t],n):[n]:n};case"comma":case"separator":return(e,n,r)=>{const o="string"==typeof n&&n.includes(t.arrayFormatSeparator),a="string"==typeof n&&!o&&i(n,t).includes(t.arrayFormatSeparator);n=a?i(n,t):n;const s=o||a?n.split(t.arrayFormatSeparator).map((e=>i(e,t))):null===n?n:i(n,t);r[e]=s};default:return(t,e,n)=>{n[t]=void 0!==n[t]?[].concat(n[t],e):e}}}(e),a=Object.create(null);if("string"!=typeof t)return a;
1748if(!(t=t.trim().replace(/^[?#&]/,"")))return a;for(const n of t.split("&")){if(""===n)continue;let[t,o]=l(e.decode?n.replace(/\+/g," "):n,"=");o=void 0===o?null:["comma","separator"].includes(e.arrayFormat)?o:i(o,e),r(i(t,e),o,a)}for(const t of Object.keys(a)){const n=a[t];if("object"==typeof n&&null!==n)for(const t of Object.keys(n))n[t]=c(n[t],e);else a[t]=c(n,e)}return!1===e.sort?a:(!0===e.sort?Object.keys(a).sort():Object.keys(a).sort(e.sort)).reduce(((t,e)=>{const n=a[e];return t[e]=Boolean(n)&&"object"==typeof n&&!Array.isArray(n)?o(n):n,t}),Object.create(null))}e.extract=s,e.parse=f,e.stringify=(t,e)=>{if(!t)return"";n((e=Object.assign({encode:!0,strict:!0,arrayFormat:"none",arrayFormatSeparator:","},e)).arrayFormatSeparator);const i=n=>e.skipNull&&null==t[n]||e.skipEmptyString&&""===t[n],o=function(t){switch(t.arrayFormat){case"index":return e=>(n,i)=>{const o=n.length;return void 0===i||t.skipNull&&null===i||t.skipEmptyString&&""===i?n:null===i?[...n,[r(e,t),"[",o,"]"].join("")]:[...n,[r(e,t),"[",r(o,t),"]=",r(i,t)].join("")]};case"bracket":return e=>(n,i)=>void 0===i||t.skipNull&&null===i||t.skipEmptyString&&""===i?n:null===i?[...n,[r(e,t),"[]"].join("")]:[...n,[r(e,t),"[]=",r(i,t)].join("")];case"comma":case"separator":return e=>(n,i)=>null==i||0===i.length?n:0===n.length?[[r(e,t),"=",r(i,t)].join("")]:[[n,r(i,t)].join(t.arrayFormatSeparator)];default:return e=>(n,i)=>void 0===i||t.skipNull&&null===i||t.skipEmptyString&&""===i?n:null===i?[...n,r(e,t)]:[...n,[r(e,t),"=",r(i,t)].join("")]}}(e),a={};for(const e of Object.keys(t))i(e)||(a[e]=t[e]);const s=Object.keys(a);return!1!==e.sort&&s.sort(e.sort),s.map((n=>{const i=t[n];return void 0===i?"":null===i?r(n,e):Array.isArray(i)?i.reduce(o(n),[]).join("&"):r(n,e)+"="+r(i,e)})).filter((t=>t.length>0)).join("&")},e.parseUrl=(t,e)=>{e=Object.assign({decode:!0},e);const[n,r]=l(t,"#");return Object.assign({url:n.split("?")[0]||"",query:f(s(t),e)},e&&e.parseFragmentIdentifier&&r?{fragmentIdentifier:i(r,e)}:{})},e.stringifyUrl=(t,n)=>{n=Object.assign({encode:!0,strict:!0},n);const i=a(t.url).split("?")[0]||"",o=e.extract(t.url),s=e.parse(o,{sort:!1}),c=Object.assign(s,t.query);let u=e.stringify(c,n);u&&(u=`?${u}`);let l=function(t){let e="";const n=t.indexOf("#");return-1!==n&&(e=t.slice(n)),e}(t.url);return t.fragmentIdentifier&&(l=`#${r(t.fragmentIdentifier,n)}`),`${i}${u}${l}`},e.pick=(t,n,r)=>{r=Object.assign({parseFragmentIdentifier:!0},r);const{url:i,query:o,fragmentIdentifier:a}=e.parseUrl(t,r);return e.stringifyUrl({url:i,query:d(o,n),fragmentIdentifier:a},r)},e.exclude=(t,n,r)=>{const i=Array.isArray(n)?t=>!n.includes(t):(t,e)=>!n(t,e);return e.pick(t,i,r)}}));const h={dateTimeLocal:"YYYY-MM-DD[T]HH:mm:ss",dateTimeUTC:"YYYYMMDD[T]HHmmss[Z]",allDay:"YYYYMMDD"};function p({startTime:t,endTime:e},n){const r=h[n];return{start:t.format(r),end:e.format(r)}}r.extend(i);const m=(e,n=!0)=>{const{start:i,end:o,duration:a}=e,s=function(t,e){if(null==t)return{};var n,r,i={},o=Object.keys(t);for(r=0;r<o.length;r++)e.indexOf(n=o[r])>=0||(i[n]=t[n]);return i}(e,["start","end","duration"]),c=n?r(i).utc():r(i),u=o?n?r(o).utc():r(o):(()=>{if(e.allDay)return c.add(1,"day");if(a&&2==a.length){const t=Number(a[0]);return c.add(t,a[1])}return n?r().utc():r()})();return t({},s,{startTime:c,endTime:u})},g=document.querySelector(".js-calendar-links"),y=document.querySelector(".js-calendar-link-google"),$=document.querySelector(".js-calendar-link-outlook"),v=document.querySelector(".js-calendar-link-ics");if(g){const t={title:g.getAttribute("data-title"),description:g.getAttribute("data-excerpt"),start:new Date(1e3*Number(g.getAttribute("data-start"))),end:new Date(1e3*Number(g.getAttribute("data-end"))),location:g.getAttribute("data-location")};y.addEventListener("click",(()=>{window.open((t=>{const e=m(t),{start:n,end:r}=p(e,e.allDay?"allDay":"dateTimeUTC"),i={action:"TEMPLATE",text:e.title,details:e.description,location:e.location,trp:e.busy,dates:n+"/"+r,recur:e.rRule?"RRULE:"+e.rRule:void 0};return e.guests&&e.guests.length&&(i.add=e.guests.join()),`https://calendar.google.com/calendar/render?${f.stringify(i)}`})(t))})),$.addEventListener("click",(()=>{window.open((t=>{const e=m(t,!1),{start:n,end:r}=p(e,"dateTimeLocal");return`https://outlook.live.com/calendar/0/deeplink/compose?${f.stringify({path:"/calendar/action/compose",rru:"addevent",startdt:n,enddt:r,subject:e.title,body:e.description,location:e.location,allday:e.allDay||!1})}`})(t))})),v.addEventListener("click",(()=>{window.open("data:text/calendar;charset=utf8;"+(t=>{const e=m(t),n=(e.description||"").replace(/,/gm,",").replace(/;/gm,";").replace(/\r\n/gm,"\n").replace(/\n/gm,"\\n").replace(/(\\n)[\s\t]+/gm,"\\n"),r=(e.location||"").replace(/,/gm,",").replace(/;/gm,";").replace(/\r\n/gm,"\n").replace(/\n/gm,"\\n").replace(/(\\n)[\s\t]+/gm,"\\n"),{start:i,end:o}=p(e,e.allDay?"allDay":"dateTimeUTC");let a="";return[{key:"BEGIN",value:"VCALENDAR"},{key:"VERSION",value:"2.0"},{key:"BEGIN",value:"VEVENT"},{key:"URL",value:e.url},{key:"DTSTART",value:i},{key:"DTEND",value:o},{key:"RRULE",value:e.rRule},{key:"SUMMARY",value:e.title},{key:"DESCRIPTION",value:n},{key:"LOCATION",value:r},{key:"ORGANIZER",value:e.organizer},{key:"END",value:"VEVENT"},{key:"END",value:"VCALENDAR"}
1748].forEach((t=>{if(t.value)if("ORGANIZER"==t.key){const e=t.value;a+=`${t.key};${encodeURIComponent(`CN=${e.name}:MAILTO:${e.email}\n`)}`}else a+=`${t.key}:${encodeURIComponent(`${t.value}\n`)}`})),`data:text/calendar;charset=utf8,${a}`})(t))}))}n(769),n(432),n(473)}()}();;

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.