').append($.parseHTML(html));\n\n var body = $html.find('.bonus-acordion-container');\n var selectedProducts = $html.find('.selected-products-container');\n var footer = $html.find('.modal-footer');\n\n return {\n body,\n footer,\n selectedProducts\n };\n}\n\n/**\n * Function to update GWP elements on swatch or size change\n */\nfunction updateGwpElements() {\n $('.choice-of-bonus-product').on('bonus:afterAttributeSelect', function () {\n const productDialog = queryFirst('.choose-bonus-product-dialog');\n const accordionContainer = this.closest('.bonus-acordion-container', productDialog);\n const bonusAccordionElements = queryAll('.bonus-acordion-container', productDialog);\n const addToCart = queryFirst('.add-bonus-products', productDialog);\n const sizeEl = queryFirst('.select-size', this);\n const isSizeSelected = sizeEl ? !!sizeEl.selectedIndex : true;\n const selectedSwatch = queryFirst('.color-attribute .swatch-circle.selected', this);\n const isSelectedSizeUnavailable = sizeEl && hasClass($(sizeEl).children('option:selected')[0], notAvailable);\n\n if (sizeEl) {\n const firstOption = queryFirst('option', sizeEl);\n\n // Force this option's resetUrl to remove the size\n firstOption.value = firstOption.value.replace(/(_size=)[^&]+/, '$1');\n }\n\n if (isSelectedSizeUnavailable) {\n addClass(sizeEl, notAvailable);\n } else {\n removeClass(sizeEl, notAvailable);\n }\n\n let isEnabled = true;\n const maxItems = parseInt(accordionContainer.dataset.maxItems, 10);\n const selectedItemsCount = queryAll('.select-bonus-product:checked', accordionContainer).length;\n\n if (selectedItemsCount < maxItems) {\n isEnabled = false;\n }\n\n if (isEnabled && isSizeSelected && !!selectedSwatch && !isSelectedSizeUnavailable) {\n addClass(accordionContainer, readyClass);\n } else {\n isEnabled = false;\n removeClass(accordionContainer, readyClass);\n }\n\n const validProducts = queryAll('.bonus-acordion-container.ready-to-add', productDialog);\n\n addToCart.disabled = !isEnabled || hasClass(addToCart, notAvailable) || bonusAccordionElements.length !== validProducts.length;\n });\n}\n\n/**\n * Retrieves url to use when adding a product to the cart\n *\n * @param {Object} data - data object used to fill in dynamic portions of the html\n */\nfunction chooseBonusProducts(data) {\n $('.modal-body')\n .spinner()\n .start();\n\n var bonusUrl;\n if (data.bonusChoiceRuleBased) {\n bonusUrl = data.showProductsUrlRuleBased;\n } else {\n bonusUrl = data.showProductsUrlListBased;\n }\n\n const { maxBonusItems, addToCartUrl, uuid, pliUUID, pageSize, showProductsUrlRuleBased, bonusChoiceRuleBased, bonusDiscountLineItems } = data;\n $('.choose-bonus-product-dialog').attr({\n 'data-total-qty': maxBonusItems,\n 'data-addToCartUrl': addToCartUrl,\n 'data-UUID': uuid,\n 'data-pliUUID': pliUUID,\n 'data-pageStart': 0,\n 'data-pageSize': pageSize,\n 'data-moreURL': showProductsUrlRuleBased,\n 'data-bonusChoiceRuleBased': bonusChoiceRuleBased,\n 'data-bonus-items': JSON.stringify(bonusDiscountLineItems)\n });\n\n $.ajax({\n url: bonusUrl,\n method: 'GET',\n dataType: 'json',\n success: function (response) {\n var parsedHtml = parseHtml(response.renderedTemplate);\n $gwpDialog.find('.enter-message').text(response.enterDialogMessage);\n $gwpDialog.find('.modal-body').html(parsedHtml.body);\n $gwpDialog\n .find('.modal-footer, .selected-products-container')\n .remove();\n $gwpDialog.find('.modal-content').append(parsedHtml.footer);\n $(parsedHtml.selectedProducts).insertAfter($gwpDialog.find('.modal-header'));\n // LP custom changes start\n const { selectedBonusProducts } = response;\n if ((selectedBonusProducts || []).length) {\n const modalDialog = queryFirst('.choose-bonus-product-dialog');\n let selectedProductsCount = 0;\n selectedBonusProducts.forEach(eachProductList => {\n if (eachProductList.length) {\n const bonusAccordionContainer = queryFirst(`.bonus-acordion-container[data-uuid=\"${eachProductList[0].uuid}\"]`, modalDialog);\n const maxCount = parseInt(bonusAccordionContainer.dataset.maxItems, 10);\n const productListLength = eachProductList.length;\n if (maxCount === productListLength) {\n addClass(bonusAccordionContainer, 'selected');\n addClass(bonusAccordionContainer, readyClass);\n }\n const bonusItemCount = queryFirst('.bonus-item-count span', bonusAccordionContainer);\n bonusItemCount.textContent = productListLength;\n selectedProductsCount += productListLength;\n eachProductList.forEach(eachProduct => {\n const selectedProduct = queryFirst(`.choice-of-bonus-product[data-pid=\"${eachProduct.pid}\"][data-uuid=\"${eachProduct.uuid}\"]`);\n const selectBonusCheckbox = queryFirst('.select-bonus-product', selectedProduct);\n\n if (selectBonusCheckbox) {\n selectBonusCheckbox.checked = true;\n }\n\n addClass(selectedProduct, selectedProductClass);\n setControlsEnabled(selectedProduct, true);\n });\n }\n });\n const addToCart = queryFirst('.add-bonus-products', modalDialog);\n addToCart.disabled = maxBonusItems !== selectedProductsCount;\n }\n\n // Default all size dropdowns that aren't selected products\n $('.bonus-product-item:not(.selected-product) .select-size').each(function () {\n this.selectedIndex = 0;\n });\n\n updateGwpElements();\n // LP custom changes end\n $gwpDialog.modal('show');\n $.spinner().stop();\n },\n error: function () {\n $.spinner().stop();\n }\n });\n}\n\n/**\n * Updates the Mini-Cart quantity value after the customer has pressed the \"Add to Cart\" button\n * @param {string} response - ajax response from clicking the add to cart button\n */\nfunction handlePostCartAdd(response) {\n $('.minicart').trigger('count:update', response);\n if (!response.error) {\n return;\n }\n\n if (response.displayModal) {\n let addToCartWarningDialog = queryFirst('#add-to-cart-warning-dialog');\n\n if (!addToCartWarningDialog) {\n const isOnCartPage = (window.location.pathname === '/cart/');\n const fragment = renderFragment(dialogTemplate({\n buttons: isOnCartPage ? [{ text: 'OK', primary: true }] : [{ text: 'Close' }, { text: 'Review Tote', primary: true, link: response.redirectLink }],\n modalContentHeading: response.messageHeading,\n modalContentBody: isOnCartPage ? response.messageBodyOnCart : response.messageBodyOffCart,\n id: 'add-to-cart-warning-dialog'\n }));\n\n document.body.appendChild(fragment);\n addToCartWarningDialog = queryFirst('#add-to-cart-warning-dialog');\n }\n\n $(addToCartWarningDialog).modal('show');\n } else {\n var messageType = response.error ? 'alert-danger' : 'alert-success';\n // show add to cart toast\n $('.add-to-cart-messages').remove();\n if ($('.add-to-cart-messages').length === 0) {\n $body.append('
');\n }\n\n $('.add-to-cart-messages').append('
' + response.message + '
');\n\n setTimeout(function () {\n $('.add-to-basket-alert').remove();\n }, 5000);\n }\n}\n\n/**\n * Retrieves the bundle product item ID's for the Controller to replace bundle master product\n * items with their selected variants\n *\n * @return {string[]} - List of selected bundle product item ID's\n */\nfunction getChildProducts() {\n var childProducts = [];\n $('.bundle-item').each(function () {\n childProducts.push({\n pid: $(this)\n .find('.product-id')\n .text(),\n quantity: parseInt(\n $(this)\n .find('label.quantity')\n .data('quantity'),\n 10\n )\n });\n });\n\n return childProducts.length ? JSON.stringify(childProducts) : [];\n}\n\n/**\n * Retrieve product options\n *\n * @param {jQuery} $productContainer - DOM element for current product\n * @return {string} - Product options and their selected values\n */\nfunction getOptions($productContainer) {\n var options = $productContainer\n .find('.product-option')\n .map(function () {\n var $elOption = $(this).find('.options-select');\n var urlValue = $elOption.val();\n var selectedValueId = $elOption.find('option[value=\"' + urlValue + '\"]').data('value-id');\n return {\n optionId: $(this).data('option-id'),\n selectedValueId: selectedValueId\n };\n })\n .toArray();\n\n return JSON.stringify(options);\n}\n\n/**\n * Enables or disables the color/size controls in a container\n * @param {HTMLElement} container - The container element\n * @param {boolean} enable - Whether to enable the controls (false to disable)\n */\nfunction setControlsEnabled(container, enable) {\n const controls = queryAll('button, select', container);\n\n controls.forEach(control => {\n control.disabled = !enable;\n });\n}\n\nexport default {\n methods: {\n editBonusProducts: function (data) {\n chooseBonusProducts(data);\n }\n },\n attributeSelect,\n updateProductDetails,\n updateImageDetails,\n focusChooseBonusProductModal: function () {\n $gwpDialog.on('shown.bs.modal', () => {\n $gwpDialog.siblings().attr('aria-hidden', 'true');\n $gwpDialog.find('.close').trigger('focus');\n });\n },\n\n onClosingChooseBonusProductModal: function () {\n $gwpDialog.on('hidden.bs.modal', () => {\n $gwpDialog.siblings().attr('aria-hidden', 'false');\n removeClass(queryFirst('.choose-bonus-product-dialog'), 'selected');\n });\n },\n\n trapChooseBonusProductModalFocus: function () {\n $body.on('keydown', '#chooseBonusProductModal', function (e) {\n var focusParams = {\n event: e,\n containerSelector: '#chooseBonusProductModal',\n firstElementSelector: '.close',\n lastElementSelector: '.add-bonus-products'\n };\n focusHelper.setTabNextFocus(focusParams);\n });\n },\n\n colorAttribute: function () {\n $(document).on('click', '[data-attr=\"color\"] button.color-attribute, [data-attr=\"fitSize\"] button.non-color-attribute', function (e) {\n e.preventDefault();\n if (($('.size-container').length > 0) && !($('.size-container .size-list .size-btn.selected').length > 0)) {\n $('.pdp-details .notify-me-desc').addClass('d-none')\n }\n const productDetailContainer = this.closest(PRODUCT_DETAIL_CONTAINER_SELECTOR);\n if ($(this).hasClass('fit-product-type') || $(this).hasClass('color-attribute')) {\n const selectedSizeBtn = queryFirst('.size-btn.selected', productDetailContainer);\n const notifyMeCTA = queryFirst('.notify-me-btn', productDetailContainer);\n const addToCartSection = queryFirst('.prices-add-to-cart-actions', productDetailContainer);\n const addToCartCTA = queryFirst('.prices-add-to-cart-actions .add-to-cart', productDetailContainer);\n removeClass(selectedSizeBtn, 'selected');\n addClass(notifyMeCTA, 'd-none');\n removeClass(addToCartSection, 'd-none');\n $(addToCartCTA).attr('disabled', false);\n selectedSizeCTA = selectedSizeBtn;\n }\n\n if ($(this).attr('disabled') || hasClass(queryFirst('.swatch-circle', this), 'selected')) {\n return;\n }\n var $productContainer = $(this).closest('.pdp-container.product-detail, .set-items .product-detail, .choose-bonus-product-modal .product-detail, .gift-card-main, .product-quickview');\n if ($productContainer.hasClass('cached-quick-view')) {\n updateQuickViewDetails(this, $productContainer);\n } else if ($productContainer.length) {\n selectColorAttribute($(this).attr('data-url'), $productContainer, $(this));\n }\n $body.trigger('swatchChangeEvent', this);\n $body.trigger('search:updateProducts');\n updateVisibilityOfLowInventoryMsg(productDetailContainer);\n });\n },\n\n renderSizeElements: function () {\n const swatchEl = queryFirst('.pdp-container:not(.gift-card-main) button.color-attribute .swatch-circle.selected');\n\n if (swatchEl) {\n const productContainer = queryFirst('.pdp-container');\n const selectedSizeEl = queryFirst('.size-btn.selected', productContainer);\n\n if (!selectedSizeEl) {\n const selectedSwtachBtn = swatchEl.parentElement;\n const variantGroupId = selectedSwtachBtn.dataset.attrValue;\n const masterId = productContainer.dataset.masterid;\n const productInfo = window.productInfo[masterId];\n const { sizes, variantsList, isDirectlyPurchasable } = productInfo.variants[variantGroupId];\n if (!isDirectlyPurchasable) {\n const sizeElements = queryAll('.size-btn', productContainer);\n addClass(sizeElements, notAvailable);\n }\n }\n\n $body.trigger('product:updateStoreInventory', {\n productContainer: productContainer\n });\n }\n updatedimageSlideArrowPDP();\n },\n\n selectAttribute: function () {\n $(document).on('change', 'select[class*=\"select-\"], .options-select', function (e) {\n if (!e.target.closest('.fp-root')) {\n e.preventDefault();\n var $productContainer = $(this).closest('.set-item');\n if (!$productContainer.length) {\n $productContainer = $(this).closest('.product-detail');\n }\n attributeSelect(e.currentTarget.value, $productContainer);\n }\n });\n },\n\n availability: function () {\n $(document).on('change', '.quantity-select', function (e) {\n e.preventDefault();\n\n var $productContainer = $(this).closest('.product-detail');\n if (!$productContainer.length) {\n $productContainer = $(this)\n .closest('.modal-content')\n .find('.product-quickview');\n }\n\n if ($('.bundle-items', $productContainer).length === 0) {\n attributeSelect(\n $(e.currentTarget)\n .find('option:selected')\n .data('url'),\n $productContainer\n );\n }\n });\n },\n\n addToCart: function () {\n $(document).on('click', '.prices-add-to-cart-actions button.add-to-cart, .prices-add-to-cart-actions button.add-to-cart-global, button.quick-buy-add-to-cart', function () {\n var addToCartUrl;\n var pid;\n var pidsObj;\n var setPids;\n var setMasterPid;\n const storeLocatoreContainer = queryFirst('.store-locator-container');\n const ispuAddToCart = storeLocatoreContainer && queryFirst('.add-to-cart', storeLocatoreContainer);\n const ispuModalContainer = $(this)\n .closest('.product-detail')\n .find('.lp-slideout-modal[id*=\"pick-up-in-store\"]');\n if (ispuAddToCart) {\n ispuAddToCart.disabled = true;\n }\n let isSet = false;\n let triggerSSAddToCart = true;\n var $productContainer = $(this).closest('.product-detail');\n const isAddAllToCart = hasClass(this, 'add-to-cart-global');\n if (isAddAllToCart) {\n const setModal = this.closest('.custom-set-detail-modal');\n const setProducts = queryAll('.custom-set-items.set-items .product-detail', setModal).filter(item => !hasClass(item.closest('.product-detail'), 'hidden-set'));\n const fillteredProducts = setProducts.filter(eachProduct => {\n toggleSelectSizeInfo(eachProduct);\n return !!queryFirst('.size-btn.selected', eachProduct);\n });\n if (fillteredProducts.length !== setProducts.length) {\n return;\n }\n } else {\n toggleSelectSizeInfo($productContainer[0]);\n if (!queryFirst('.size-btn.selected', $productContainer[0])) {\n return;\n }\n }\n\n $body.trigger('product:beforeAddToCart', this);\n if ($('.set-items').length && $(this).hasClass('add-to-cart-global')) {\n isSet = true;\n triggerSSAddToCart = false;\n setMasterPid = $('.product-detail.product-set-detail').data('pid');\n setPids = [];\n\n // DRP-180 updated class from \".product-detail\" to \".custom-set-items .custom-set-product\" to only check products within set modal for add all to tote\n $('.custom-set-items .custom-set-product').each(function () {\n if (!$(this).hasClass('product-set-detail')) {\n setPids.push({\n pid: $(this)\n .find('.product-id')\n .text(),\n qty: $(this)\n .find('.quantity-select')\n .val(),\n options: getOptions($(this))\n });\n }\n });\n pidsObj = JSON.stringify(setPids);\n }\n\n if ($(this).next('ul.size-container').find('li button.size-btn').hasClass('selected')) {\n pid = $(this).next('ul.size-container').find('li button.size-btn.selected').data('variation-id');\n } else {\n pid = getPidValue($(this));\n }\n\n if (!$productContainer.length) {\n $productContainer = $(this)\n .closest('.quick-view-dialog')\n .find('.product-detail');\n }\n\n addToCartUrl = getAddToCartUrl();\n\n var form = {\n pid: pid,\n pidsObj: pidsObj,\n childProducts: getChildProducts(),\n quantity: getQuantitySelected($(this)),\n setMasterPid: setMasterPid\n };\n\n if (!$('.bundle-item').length) {\n form.options = getOptions($productContainer);\n }\n\n $(this).trigger('updateAddToCartFormData', form);\n\n if (addToCartUrl) {\n $.ajax({\n url: addToCartUrl,\n method: 'POST',\n data: form,\n success: function (data) {\n if (isSet) {\n $('#productSetModal').modal('hide');\n }\n\n if (ispuAddToCart) {\n ispuAddToCart.disabled = false;\n ispuModalContainer.modal('hide');\n }\n\n handlePostCartAdd(data);\n\n if (triggerSSAddToCart && isFitPredictorEnabled) {\n ssAddToCart($productContainer[0]);\n }\n\n $.spinner().stop();\n $body.trigger('product:afterAddToCart', data);\n const productContainerPrice = queryFirst('.price-section .sales .value', $productContainer[0]);\n if (productContainerPrice) {\n // note, that this event will not function on PLP, because of DOM structure (price section in different place)\n $body.trigger('stylitics:main:addItem', {\n pid: pid,\n price: productContainerPrice.getAttribute('content')\n });\n }\n },\n error: function () {\n $.spinner().stop();\n if (ispuAddToCart) {\n ispuAddToCart.disabled = false;\n }\n }\n });\n }\n });\n },\n selectBonusProduct: function () {\n $(document).on('click', '.select-bonus-product', function () {\n var $choiceOfBonusProduct = $(this).parents('.choice-of-bonus-product');\n var pid = $choiceOfBonusProduct.data('pid');\n var uuid = $choiceOfBonusProduct.data('uuid');\n var maxPids = $('.choose-bonus-product-dialog').data('total-qty');\n var submittedQty = 1;\n var totalQty = 0;\n $.each($('#chooseBonusProductModal .selected-bonus-products .selected-pid'), function () {\n totalQty += $(this).data('qty');\n });\n\n // LP customization changes start\n const { checked } = this;\n const productDialog = queryFirst('.choose-bonus-product-dialog');\n const choiceOfBonusProduct = $choiceOfBonusProduct[0];\n const addToCart = queryFirst('.add-bonus-products', productDialog);\n const selectedProductElement = queryFirst(`.selected-pid[data-pid=\"${pid}\"][data-uuid=\"${uuid}\"]`, productDialog);\n let bonusAccordionElements = queryAll('.bonus-acordion-container', productDialog);\n let accordionContainer = this.closest('.bonus-acordion-container', productDialog);\n const bonusCountElement = queryFirst('.bonus-item-count span', accordionContainer);\n const selectedCount = queryAll('.select-bonus-product:checked', accordionContainer).length;\n const maxCount = parseInt(accordionContainer.dataset.maxItems, 10);\n let sizeEl = queryFirst('.select-size', choiceOfBonusProduct);\n let selectedSwatch = queryFirst('.color-attribute .swatch-circle.selected', choiceOfBonusProduct);\n let isSizeSelected = sizeEl ? !!sizeEl.selectedIndex : true;\n\n if (selectedCount < maxCount) {\n removeClass(accordionContainer, 'selected');\n } else {\n addClass(accordionContainer, 'selected');\n }\n bonusCountElement.textContent = selectedCount;\n\n let enableAddTocart = true;\n const maxItems = parseInt(accordionContainer.dataset.maxItems, 10);\n const selectedItemsCount = queryAll('.select-bonus-product:checked', accordionContainer).length;\n if (selectedItemsCount < maxItems) {\n enableAddTocart = false;\n }\n enableAddTocart = isSizeSelected && !!selectedSwatch && enableAddTocart;\n\n if (enableAddTocart) {\n addClass(accordionContainer, readyClass);\n } else {\n removeClass(accordionContainer, readyClass);\n }\n\n let validProducts = queryAll('.bonus-acordion-container.ready-to-add', productDialog);\n\n if (!hasClass(addToCart, notAvailable)) {\n addToCart.disabled = bonusAccordionElements.length !== validProducts.length;\n }\n\n if (checked) {\n addClass(choiceOfBonusProduct, selectedProductClass);\n } else {\n removeClass(choiceOfBonusProduct, selectedProductClass);\n if (selectedProductElement) {\n selectedProductElement.click();\n }\n }\n if (selectedCount < maxCount) {\n $(accordionContainer)\n .find('.choice-of-bonus-product')\n .find('.select-bonus-product, .color-attribute, select')\n .removeAttr('tabindex').prop('disabled', false);\n } else {\n $(accordionContainer)\n .find('.choice-of-bonus-product:not(.selected-product)')\n .find('.select-bonus-product, .color-attribute, select')\n .attr('tabindex', -1).prop('disabled', true);\n }\n if (!checked) {\n return;\n }\n // LP customization changes end\n\n totalQty += submittedQty;\n var optionID = $choiceOfBonusProduct.find('.product-option').data('option-id');\n var valueId = $choiceOfBonusProduct.find('.options-select option:selected').data('valueId');\n if (totalQty <= maxPids) {\n var selectedBonusProductHtml =\n '' +\n '
' +\n '
' +\n $choiceOfBonusProduct.find('.product-name').html() +\n '
' +\n '
' +\n '
';\n $('#chooseBonusProductModal .selected-bonus-products').append(selectedBonusProductHtml);\n $('.pre-cart-products').html(totalQty);\n $('.selected-bonus-products .bonus-summary').removeClass('alert-danger');\n } else {\n $('.selected-bonus-products .bonus-summary').addClass('alert-danger');\n }\n });\n },\n removeBonusProduct: function () {\n $(document).on('click', '.selected-pid', function () {\n $(this).remove();\n var $selected = $('#chooseBonusProductModal .selected-bonus-products .selected-pid');\n var count = 0;\n if ($selected.length) {\n $selected.each(function () {\n count += parseInt($(this).data('qty'), 10);\n });\n }\n\n $('.pre-cart-products').html(count);\n $('.selected-bonus-products .bonus-summary').removeClass('alert-danger');\n });\n },\n enableBonusProductSelection: function () {\n $body.on('bonusproduct:updateSelectButton', function (e, response) {\n $('button.select-bonus-product', response.$productContainer).attr('disabled', !response.product.readyToOrder || !response.product.available);\n var pid = response.product.id;\n $('button.select-bonus-product', response.$productContainer).data('pid', pid);\n });\n\n const bonusProductDialog = queryFirst('.choose-bonus-product-dialog');\n\n if (bonusProductDialog) {\n bonusProductDialog.addEventListener('click', e => {\n const target = e.target.closest('.select-bonus-product');\n\n if (!target) return;\n\n setControlsEnabled(target.closest('.row'), target.checked);\n });\n }\n },\n showMoreBonusProducts: function () {\n $(document).on('click', '.show-more-bonus-products', function () {\n var url = $(this).data('url');\n $('.modal-content')\n .spinner()\n .start();\n $.ajax({\n url: url,\n method: 'GET',\n success: function (html) {\n var parsedHtml = parseHtml(html);\n $('.modal-body').append(parsedHtml.body);\n $('.show-more-bonus-products:first').remove();\n $('.modal-content')\n .spinner()\n .stop();\n },\n error: function () {\n $('.modal-content')\n .spinner()\n .stop();\n }\n });\n });\n },\n addBonusProductsToCart: function () {\n $(document).on('click', '.add-bonus-products', function () {\n var $readyToOrderBonusProducts = $('.choose-bonus-product-dialog .selected-pid');\n var queryString = '?pids=';\n var url = $('.choose-bonus-product-dialog').data('addtocarturl');\n var pidsObject = {\n bonusProducts: []\n };\n\n $.each($readyToOrderBonusProducts, function () {\n var qtyOption = parseInt($(this).data('qty'), 10);\n const pid = $(this).data('pid');\n const uuid = $(this).data('uuid');\n const productId = $(`.choice-of-bonus-product.selected-product[data-pid=\"${pid}\"][data-uuid=\"${uuid}\"] .product-detail`).attr('data-pid');\n var option = null;\n if (qtyOption > 0) {\n if ($(this).data('optionid') && $(this).data('option-selected-value')) {\n option = {};\n option.optionId = $(this).data('optionid');\n option.productId = productId;\n option.selectedValueId = $(this).data('option-selected-value');\n }\n pidsObject.bonusProducts.push({\n uuid: uuid,\n pid: productId,\n qty: qtyOption,\n options: option ? [option] : []\n });\n pidsObject.totalQty = parseInt($('.pre-cart-products').html(), 10);\n }\n });\n queryString += JSON.stringify(pidsObject);\n queryString = queryString + '&bonusItems=' + JSON.stringify($('.choose-bonus-product-dialog').data('bonusItems'));\n $.spinner().start();\n $.ajax({\n url: url + queryString,\n method: 'POST',\n success: function (data) {\n $.spinner().stop();\n if (data.error) {\n $('#chooseBonusProductModal').modal('hide');\n if ($('.add-to-cart-messages').length === 0) {\n $body.append('
');\n }\n $('.add-to-cart-messages').append('
' + data.errorMessage + '
');\n setTimeout(function () {\n $('.add-to-basket-alert').remove();\n }, 3000);\n } else {\n $('.configure-bonus-product-attributes').html(data);\n $('.bonus-products-step2').removeClass('hidden-xl-down');\n $('#chooseBonusProductModal').modal('hide');\n $('.minicart-quantity').html(data.totalQty);\n if ($('.cart-page').length) {\n location.reload();\n }\n }\n },\n error: function () {\n $.spinner().stop();\n }\n });\n });\n },\n revealRecommendations: function () {\n const { initSpecificCarousel } = require('../components/carousel');\n queryAll('.recommendations:not(.product-listing-header)').forEach(eachRecommendation => {\n const titleEl = queryFirst('.title', eachRecommendation);\n const productEl = queryFirst('.grid-tile', eachRecommendation);\n const scrollableContent = queryFirst('.scrollable-content', eachRecommendation);\n\n if (titleEl && !productEl) {\n eachRecommendation.outerHTML = '';\n } else if (titleEl && productEl) {\n eachRecommendation.style.display = 'block';\n if (scrollableContent) initSpecificCarousel(scrollableContent);\n }\n });\n },\n handleEarlyAccessPLPLockIcon: function () {\n const earlyAccessPLPContainer = queryAll('.early-access-plp-container');\n if (earlyAccessPLPContainer.length) {\n earlyAccessPLPContainer.forEach(earlyAccessPlpIcon => {\n const lockIconContainer = queryFirst('.loyalty-early-access-lock-container', earlyAccessPlpIcon);\n const earlyAccessWishlistIcon = queryFirst('.product-tile .add-to-wish-list-container', earlyAccessPlpIcon);\n const earlyAccessPLPBadge = queryFirst('.loyalty-product-tile-badge', earlyAccessPlpIcon);\n const { earlyAccessDate } = lockIconContainer.dataset;\n const isEarlyAccessItem = isEarlyAccessElement(earlyAccessDate);\n if (isLoyaltyProgramMember || !isEarlyAccessItem) {\n removeClass(earlyAccessWishlistIcon, HIDDEN_CLASS);\n addClass(lockIconContainer, HIDDEN_CLASS);\n if (!isEarlyAccessItem) {\n addClass(earlyAccessPLPBadge, HIDDEN_CLASS);\n }\n } else {\n addClass(earlyAccessWishlistIcon, HIDDEN_CLASS);\n removeClass([lockIconContainer, earlyAccessPLPBadge], HIDDEN_CLASS);\n }\n });\n }\n },\n\n getPidValue: getPidValue,\n getQuantitySelected: getQuantitySelected,\n handleEarlyAccessCta: handleEarlyAccessCta,\n updatedimageSlideArrowPDP: updatedimageSlideArrowPDP,\n};\nwindow.onload = () => {\n updatedimageSlideArrowPDP();\n replaceVideoThumbnailImage(queryFirst('.pdp-container'));\n};\n","'use strict';\n\nimport { queryFirst, addClass, removeClass, hasClass, queryAll, scrollTo, setAttribute, throttle } from '../domUtil';\nimport base from './base';\nimport { updateProductData, handleColor, handleSize } from 'fitpredictor/product/secretsauce';\nconst { isShippingPreferencesViewEnabled, isEarlyAccessElement, handleNotifyMe } = require('./helper');\nconst { availabilityMessageTmpl, restrictedMessageTmpl, availabilityMessageOOS, availabilityMessagePreorder, ispuAvailabilityMessageTmpl, ispuLowStockMessageTmpl } = require('../templates').productDetail;\nconst $body = $('body');\nconst sizeChartClasses = 'no-scroll size-chart-visible';\nvar Hammer = require('hammerjs');\nconst KEYCODE_TAB = 9;\nconst TabKey = 'Tab';\nconst ACTIVE_CLASS = 'active';\nconst { IN_STOCK_STATUS: IN_STOCK, NOT_AVAILABLE_STATUS: NOT_AVAILABLE, PREORDER_STATUS: PREORDER, HIDDEN_CLASS } = require('../constants');\nconst { SHIP_TO_LOW_INVENTORY_CLASS } = require('../components/shippingPreference/constants');\n/**\n * Handling zoomin effect on product image slider\n */\nfunction handleProductImageZoom() {\n const pdpPageCarousels = queryFirst('.product-detail');\n const carousel = $('.primary-images .carousel:not(.tile-carousel)');\n const imageZoomUrl = carousel.data('image');\n const imagePresetUrl = carousel.data('preset');\n\n const imageObserver = new MutationObserver(function (mutationList) {\n for (let mutation of mutationList) {\n if (mutation.type === 'childList') {\n const { target, addedNodes } = mutation;\n const baseImg = queryFirst('.img-fluid', target);\n const zoomAlt = baseImg.getAttribute('alt') + ' Zoomed';\n setAttribute(addedNodes, 'alt', zoomAlt);\n }\n }\n });\n\n if (pdpPageCarousels && pdpPageCarousels.length > 0) {\n const pdpImages = queryAll('.primary-images .carousel-item');\n const pdpIndicators = queryAll('.primary-images .carousel-indicators li');\n\n pdpImages.forEach((img, index) => {\n const imageEl = queryFirst('img', img);\n if (!imageEl) {\n return;\n }\n imageEl.setAttribute('data-src-hires', imageEl.getAttribute('data-src').replace(imagePresetUrl, imageZoomUrl));\n let scale = 0.35;\n let zoomed = false;\n let mobileZoomed = false;\n /**\n * Handling zoomin effect logic\n * @param {jQuery} elm - DOM element for current image\n * @param {boolean} zoomed - boolean value if zoomed or not\n */\n function createTouchZoom(elm) {\n var thisHammer = new Hammer(elm, {});\n thisHammer.domEvents = true;\n thisHammer.get('pinch').set({ enable: true });\n\n let transform = '';\n let el = elm;\n let panSpeed = 1.1;\n let xPos = { current: 0, last: 0, max: 0 };\n let yPos = { current: 0, last: 0, max: 0 };\n let scale = { current: 2, last: 2, max: 4 };\n\n el.style.transform = `translate(${xPos.current}px,${yPos.current}px) scale(${scale.current},${scale.current})`;\n\n thisHammer.on('tap pan pinch panend pinchend', function (e) {\n // Prevent tap events from interfering\n e.srcEvent.stopPropagation();\n e.srcEvent.preventDefault();\n // If zoomed in, pan the image\n if (scale.current !== 1) {\n xPos.current = xPos.last + e.deltaX * panSpeed;\n yPos.current = yPos.last + e.deltaY * panSpeed;\n xPos.max = Math.ceil(((scale.current - 1) * el.clientWidth) / 2);\n yPos.max = Math.ceil(((scale.current - 1) * el.clientHeight) / 2);\n // Keep coordinates within image bounds\n if (xPos.current > xPos.max) {\n xPos.current = xPos.max;\n }\n if (xPos.current < -xPos.max) {\n xPos.current = -xPos.max;\n }\n if (yPos.current > yPos.max) {\n yPos.current = yPos.max;\n }\n if (yPos.current < -yPos.max) {\n yPos.current = -yPos.max;\n }\n }\n\n if (e.type === 'tap') {\n e.preventDefault();\n scale.current++;\n scale.last = scale.current;\n\n if (scale.current > scale.max) {\n scale.current = 1;\n xPos.current = 0;\n yPos.current = 0;\n xPos.last = xPos.current;\n yPos.last = yPos.current;\n scale.last = scale.current;\n transform = `translate(${xPos.current}px,${yPos.current}px) scale(${scale.current},${scale.current})`;\n mobileZoomed = true;\n } else mobileZoomed = false;\n }\n // Scale image with pinch\n if (e.type === 'pinch') {\n scale.current = Math.max(0.99, Math.min(scale.last * e.scale, scale.max));\n }\n // Finish scaling\n if (e.type === 'pinchend') {\n scale.last = scale.current;\n }\n // Finish panning\n if (e.type === 'panend') {\n xPos.last = xPos.current;\n yPos.last = yPos.current;\n }\n\n // Create scale/pan changes if zoomed in\n if (scale.current !== 1) {\n transform = `translate(${xPos.current}px,${yPos.current}px) scale(${scale.current},${scale.current})`;\n }\n // Apply transformation\n if (transform) {\n el.style.transform = transform;\n }\n });\n\n $(el).on('zoom:imageChange', () => {\n thisHammer.off('tap pan pinch panend pinchend');\n scale.current = 1;\n xPos.current = 0;\n yPos.current = 0;\n xPos.last = xPos.current;\n yPos.last = yPos.current;\n scale.last = scale.current;\n el.style.transform = `translate(${xPos.current}px,${yPos.current}px) scale(${scale.current},${scale.current})`;\n el.style['touch-action'] = 'initial';\n mobileZoomed = false;\n zoomed = false;\n });\n }\n\n /** function to create zoom effect on hover\n * @param {jQuery} el - DOM element for current product image\n * @param {number} scale - scale value for the zoom\n */\n function createHoverZoom(el, scale) {\n let hiresUrl = $(el).find('img').attr('data-src-hires');\n if (hiresUrl && hiresUrl !== 'null' && hiresUrl.indexOf('noimagelarge') === -1) {\n $(el).zoom({\n on: 'click',\n url: hiresUrl,\n touch: false,\n magnify: scale\n });\n }\n }\n\n const setZoomOffset = function () {\n if (!zoomed) {\n scale *= 1.5;\n if (scale === 1.18125) {\n zoomed = true;\n }\n createHoverZoom(img, scale);\n } else {\n $(img).trigger('zoom-destroy');\n $(img).find('.zoomImg').remove();\n zoomed = false;\n scale = 0.35;\n createHoverZoom(img, scale);\n }\n };\n\n const allMobileZoom = function (event) {\n const img = event.target;\n if (!zoomed) {\n img.src = img.getAttribute('data-src-hires');\n createTouchZoom(img);\n }\n zoomed = true;\n if (!mobileZoomed) {\n addClass(img.parentNode, 'touch-zoom');\n $('.primary-images .carousel').carousel('dispose');\n img.style['touch-action'] = 'none';\n }\n\n if (mobileZoomed) {\n removeClass(img.parentNode, 'touch-zoom');\n $('.primary-images .carousel.image-slider').carousel();\n $('.primary-images .carousel').on('slide.bs.carousel', () => {\n $('.primary-images .carousel-item img').trigger('zoom:imageChange');\n });\n img.style['touch-action'] = 'initial';\n }\n };\n\n if (window.matchMedia('(max-width: 1024px)').matches) {\n if (window.matchMedia('(max-width: 768px)').matches) {\n if (pdpIndicators) {\n $(pdpIndicators).on('click', () => {\n const touchZoom = queryFirst('.primary-images .carousel-item.touch-zoom');\n zoomed = false;\n mobileZoomed = false;\n if (touchZoom) {\n $('.primary-images .carousel-item.touch-zoom img').trigger('zoom:imageChange');\n removeClass(queryFirst('.primary-images .carousel-item.touch-zoom'), 'touch-zoom');\n }\n $('.primary-images .carousel.image-slider').carousel();\n $('.primary-images .carousel').on('slide.bs.carousel', () => {\n $('.primary-images .carousel-item img').trigger('zoom:imageChange');\n });\n });\n if (index === 0) {\n $('.primary-images .carousel').on('slide.bs.carousel', () => {\n $('.primary-images .carousel-item img').trigger('zoom:imageChange');\n });\n }\n }\n }\n img.addEventListener('click', allMobileZoom);\n } else {\n $(img).one('mouseenter', function () {\n createHoverZoom(img, scale);\n });\n img.addEventListener('click', () => {\n $(pdpImages).not($(img)).each(function () {\n if ($(this).find('.zoomImg').length > 1) {\n $(this).find('.zoomImg').remove();\n scale = 0.35;\n createHoverZoom($(this), scale);\n }\n });\n setZoomOffset();\n });\n\n imageObserver.observe(img, { childList: true });\n }\n });\n }\n}\n\n/**\n * updates the product view when a product attribute is selected or deselected or when\n * changing quantity\n * @param {Array} variationAttributes - the Url for the selected variation value\n * @param {jQuery} $productContainer - DOM element for current product\n */\nfunction updateSelectedSwatchProductName(variationAttributes, $productContainer) {\n if (Array.isArray(variationAttributes) && variationAttributes.length) {\n const colorVariationObject = variationAttributes.find(attribute => attribute.attributeId === 'color');\n\n if (colorVariationObject && Array.isArray(colorVariationObject.values) && colorVariationObject.values.length) {\n const selectedSwatchObject = colorVariationObject.values.find(eachValue => eachValue.selected);\n let $swatchSection = $productContainer.find('.selected-swatch');\n $swatchSection.find('.selected-swatch-name').text(selectedSwatchObject && $swatchSection.data('color-label') ? $swatchSection.data('color-label').toUpperCase() + selectedSwatchObject.displayValue : '');\n }\n }\n}\n\n/**\n * handles size change\n * @param {Object} productContainer - product container html element\n * @param {string} selectedSizeValue - Selected size value\n */\nfunction onSizeChangeHandler(productContainer, selectedSizeValue) {\n const sizeDetailsContainer = queryFirst('.details-text:not(.d-none)', productContainer);\n const selectedSize = queryFirst('.selected-size', sizeDetailsContainer);\n const selectedSizeErrMsg = queryFirst('.select-size-message', productContainer);\n\n removeClass(queryAll('.size-btn', productContainer), 'selected');\n addClass(this, 'selected');\n addClass(selectedSizeErrMsg, 'd-none');\n const sizeContainer = this.closest('.size-container');\n const assistiveElements = queryAll('.selected-assistive-text', sizeContainer);\n assistiveElements.forEach(eachElement => {\n if (eachElement.textContent.includes(eachElement.dataset.outOfStock)) {\n eachElement.textContent = eachElement.dataset.outOfStock;\n } else {\n eachElement.textContent = '';\n }\n });\n const assistiveElementOfSelected = queryFirst('.selected-assistive-text', this.closest('.size-list'));\n const { selectedText, outOfStock } = assistiveElementOfSelected.dataset;\n assistiveElementOfSelected.textContent = selectedText;\n if (hasClass(this, 'not-available')) {\n assistiveElementOfSelected.textContent += ' ' + outOfStock;\n }\n removeClass(queryFirst('.size-seperator', sizeDetailsContainer), 'd-none');\n selectedSize.textContent = selectedSizeValue;\n removeClass(selectedSize, 'd-none');\n}\n\n/**\n * update quickview product info on product variation change\n * @param {string} selectedSizeValue - Selected size value\n * @param {int} selectedColorId - selected color id\n * @param {Object} productContainer - product container html element\n * @param {Object} currentSizeElement - current active size element\n */\nfunction updateQuickViewProductInfo(selectedSizeValue, selectedColorId, productContainer, currentSizeElement) {\n const quickViewInfo = window.quickviewProductInfo;\n const { productInfo } = quickViewInfo;\n const variantGroupData = productInfo.variants[selectedColorId];\n const { sizes, images, formattedPrice, standardPrice, price, vgProductDetailsUrl, isDirectlyPurchasable } = variantGroupData;\n const ispu = base.updateImageDetails(images.ispu);\n const selectedSizeData = sizes[selectedSizeValue];\n const addToCartButton = queryFirst('.add-to-cart', productContainer);\n const hiddenClass = 'd-none';\n const notifyMeButton = queryFirst('.notify-me-btn', productContainer);\n const notifyMeDesc = queryFirst('.notify-me-desc', productContainer);\n const addToCartSection = queryFirst('.prices-add-to-cart-actions', productContainer);\n const availabilityMsgEl = queryFirst('.availability-msg', productContainer);\n let availabilityValue = '';\n let productDetailsUrl = vgProductDetailsUrl;\n const fullPDPLink = queryFirst('.full-pdp-link', productContainer);\n const wishlistButton = queryFirst('.add-to-wish-list', productContainer);\n\n if (wishlistButton && hasClass(wishlistButton, 'added-to-wish-list')) {\n removeClass(wishlistButton, 'added-to-wish-list');\n wishlistButton.disabled = false;\n }\n\n if (!selectedSizeData || !currentSizeElement) {\n removeClass(addToCartSection, hiddenClass);\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n fullPDPLink.href = productDetailsUrl;\n if (!isDirectlyPurchasable) {\n addToCartButton.disabled = true;\n availabilityValue = availabilityMessageTmpl(availabilityMsgEl.dataset.notPurchasable);\n availabilityMsgEl.innerHTML = availabilityValue;\n } else {\n addToCartButton.disabled = false;\n }\n return;\n }\n\n const { isNotifyMeEnabled, ID, forceOutOfStock, variantProductDetailsUrl } = selectedSizeData;\n productDetailsUrl = variantProductDetailsUrl;\n const { productInventory } = quickViewInfo;\n const { variants } = productInventory;\n const inventoryData = variants[ID];\n const { message, availabilityStatus, isLowInventory } = inventoryData;\n const selectedColorName = queryFirst('.selected-swatch-name').textContent;\n\n if (!isDirectlyPurchasable) {\n availabilityValue = availabilityMessageTmpl(availabilityMsgEl.dataset.notPurchasable);\n } else if (availabilityStatus !== IN_STOCK || isLowInventory) {\n availabilityValue = availabilityMessageTmpl(message);\n }\n fullPDPLink.href = productDetailsUrl;\n\n if (!isDirectlyPurchasable) {\n addToCartButton.disabled = true;\n removeClass(addToCartSection, hiddenClass);\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n } else if (availabilityStatus !== NOT_AVAILABLE && !forceOutOfStock) {\n addToCartButton.disabled = false;\n removeClass(currentSizeElement, 'not-available');\n } else {\n addClass(currentSizeElement, 'not-available');\n addToCartButton.disabled = true;\n if (isNotifyMeEnabled) {\n addClass(addToCartSection, hiddenClass);\n removeClass([notifyMeDesc, notifyMeButton], hiddenClass);\n } else {\n removeClass(addToCartSection, hiddenClass);\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n }\n }\n\n availabilityMsgEl.innerHTML = availabilityValue;\n productContainer.dataset.pid = ID;\n productContainer.dataset.wishlistId = ID;\n const productData = {\n available: !hasClass(currentSizeElement, 'not-available'),\n isNotifyMeEnabled,\n id: ID,\n formattedPrice,\n forceOutOfStock,\n imageData: ispu\n };\n handleNotifyMe(productData, productContainer);\n\n // secret sauce integration to update product data\n updateProductData(selectedColorName, selectedSizeValue, standardPrice, price, productContainer);\n handleSize(productContainer);\n $('body').trigger('product:afterQuickViewSizeChange', {\n ID,\n productContainer,\n monetateData: {\n pdpBreadCrumbs: variantGroupData.pdpBreadCrumbs\n }\n });\n}\n\n/**\n * Update Scarcity Message on product variation change\n * @param {string} message - Scarcity Message\n * @param {Object} productContainer - product container html element\n */\nfunction updateScarcityMessage(message, productContainer) {\n const fitSizeScarcityLabel = queryFirst('.js-size-scarcity-message', productContainer);\n const ctaScarcityLabel = queryFirst('.js-cta-scarcity-message', productContainer);\n\n if (fitSizeScarcityLabel) {\n fitSizeScarcityLabel.innerHTML = message\n ? `
- ${message}`\n : '';\n\n if (message === fitSizeScarcityLabel.dataset.oosMsg) {\n addClass(fitSizeScarcityLabel, 'accent');\n } else {\n removeClass(fitSizeScarcityLabel, 'accent');\n }\n }\n\n if (ctaScarcityLabel) {\n if (message && message !== ctaScarcityLabel.dataset.oosMsg) {\n ctaScarcityLabel.innerHTML = `
- ${message}`;\n } else {\n ctaScarcityLabel.innerHTML = '';\n }\n }\n}\n\n/**\n * update product info on product variation change\n * @param {string} selectedSizeValue - Selected size value\n * @param {int} selectedColorId - selected color id\n * @param {Object} productContainer - product container html element\n * @param {Object} currentSizeElement - current active size element\n * @param {boolean} isPDPSetPage - is PDP set page\n */\nfunction updateProductInfo(selectedSizeValue, selectedColorId, productContainer, currentSizeElement, isPDPSetPage) {\n const masterId = productContainer.dataset.masterid;\n const productInfo = window.productInfo[masterId];\n const variantGroupData = productInfo.variants[selectedColorId];\n const { sizes, images, formattedPrice, formattedStandardPrice, totalPrice, monogramProductPrice, standardPrice, price, mgFlag, mgLocs, isDirectlyPurchasable } = variantGroupData;\n const ispu = base.updateImageDetails(images.ispu);\n const selectedSizeData = sizes[selectedSizeValue];\n let addToCartButton = '';\n if (hasClass(productContainer, 'custom-set-product')) {\n addToCartButton = queryFirst('.add-to-cart-global');\n } else {\n addToCartButton = queryFirst('.add-to-cart', productContainer);\n }\n const ispuButton = queryFirst('.btn-in-store-pickup', productContainer);\n const hiddenClass = 'd-none';\n const notifyMeButton = queryFirst('.notify-me-btn', productContainer);\n const notifyMeDesc = queryFirst('.notify-me-desc', productContainer);\n const addToCartSection = queryFirst('.prices-add-to-cart-actions', productContainer);\n const availabilityMsgEl = queryFirst('.availability-msg', productContainer);\n const ispuLowStockMsgEl = queryFirst('.ispu-low-stock-msg', productContainer);\n const restrictedMsg = availabilityMsgEl.dataset.restrictedItem;\n const isGlobaleSession = availabilityMsgEl.dataset.isGlobaleSession;\n let availabilityValue = '';\n\n if (!selectedSizeData || !currentSizeElement) {\n if (ispuButton) {\n ispuButton.disabled = true;\n }\n removeClass(addToCartSection, hiddenClass);\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n if (!isDirectlyPurchasable) {\n addToCartButton.disabled = true;\n availabilityValue = availabilityMessageTmpl(availabilityMsgEl.dataset.notPurchasable);\n availabilityMsgEl.innerHTML = availabilityValue;\n if (ispuButton) {\n ispuButton.disabled = true;\n }\n } else {\n addToCartButton.disabled = false;\n }\n return;\n }\n\n const { isNotifyMeEnabled, ID, forceOutOfStock, manufacturerSKU, availableForInStorePickup } = selectedSizeData;\n const { variants } = isPDPSetPage ? window.productInventory[masterId] : window.productInventory;\n const inventoryData = variants[ID];\n const {\n message, availabilityStatus, isLowInventory, scarcityMessage\n } = inventoryData;\n\n updateScarcityMessage(scarcityMessage, productContainer);\n\n // Shipping preference view\n const shippingPreferencesEnabled = isShippingPreferencesViewEnabled();\n let ispuAvailabilityValue = '';\n let ispuLowStockValue = '';\n let ispuVariants;\n let ispuInventoryData;\n let ispuMessage;\n let ispuLowStockMessage;\n let ispuAvailabilityStatus;\n let isISPULowInventory;\n let isNotEligibleForISPU;\n if (shippingPreferencesEnabled && window.ispuProductInventory) {\n const { variants } = isPDPSetPage ? window.ispuProductInventory[masterId] : window.ispuProductInventory;\n if (variants) {\n ispuInventoryData = variants[ID];\n }\n if (ispuInventoryData) {\n ispuMessage = ispuInventoryData.message;\n ispuLowStockMessage = ispuInventoryData.lowStockAvailabilityMessage;\n ispuAvailabilityStatus = ispuInventoryData.availabilityStatus;\n isISPULowInventory = ispuInventoryData.isLowInventory;\n }\n }\n\n const selectedColorName = queryFirst('.selected-swatch-name', productContainer).textContent;\n if (!isDirectlyPurchasable) {\n availabilityValue = availabilityMessageTmpl(availabilityMsgEl.dataset.notPurchasable);\n } else {\n if (availabilityStatus !== IN_STOCK || isLowInventory) {\n const breadcrumbItems = queryAll('.breadcrumb-item');\n const categoryUrl = breadcrumbItems && breadcrumbItems.length > 1 && breadcrumbItems.pop().lastElementChild && breadcrumbItems.pop().lastElementChild.href;\n if (availabilityStatus === NOT_AVAILABLE && categoryUrl) {\n availabilityValue = availabilityMessageOOS(message, categoryUrl);\n } else if (availabilityStatus === PREORDER && categoryUrl) {\n availabilityValue = availabilityMessagePreorder(message, categoryUrl);\n }\n else {\n availabilityValue = availabilityMessageTmpl(message);\n }\n if (isLowInventory) addClass(currentSizeElement, SHIP_TO_LOW_INVENTORY_CLASS);\n }\n\n // Shipping preference view\n if (ispuAvailabilityStatus && (ispuAvailabilityStatus !== IN_STOCK || isISPULowInventory)) {\n ispuAvailabilityValue = ispuAvailabilityMessageTmpl(ispuMessage);\n ispuLowStockValue = ispuLowStockMessage ? ispuLowStockMessageTmpl(ispuLowStockMessage) : '';\n }\n }\n\n if (!isDirectlyPurchasable) {\n addToCartButton.disabled = true;\n removeClass(addToCartSection, hiddenClass);\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n } else if (((availabilityStatus !== NOT_AVAILABLE || (ispuAvailabilityStatus && ispuAvailabilityStatus !== NOT_AVAILABLE)) &&\n !forceOutOfStock) && !(isGlobaleSession === 'true' && availabilityStatus === PREORDER)) {\n addToCartButton.disabled = false;\n removeClass(currentSizeElement, 'not-available');\n } else {\n addClass(currentSizeElement, 'not-available');\n addToCartButton.disabled = true;\n if (isNotifyMeEnabled) {\n addClass(addToCartSection, hiddenClass);\n removeClass([notifyMeDesc, notifyMeButton], hiddenClass);\n } else {\n removeClass(addToCartSection, hiddenClass);\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n }\n }\n availabilityMsgEl.innerHTML = availabilityValue;\n\n if (availabilityStatus === PREORDER) {\n addClass(currentSizeElement, 'pre-order');\n if (restrictedMsg !== '' && isGlobaleSession === 'true') {\n availabilityValue = restrictedMessageTmpl(restrictedMsg);\n availabilityMsgEl.innerHTML += availabilityValue;\n }\n addClass(queryFirst('.afterpay-paragraph', productContainer), hiddenClass)\n } else {\n removeClass(queryFirst('.afterpay-paragraph', productContainer), hiddenClass)\n }\n\n if (shippingPreferencesEnabled) {\n $body.trigger('product:inventoryStatus', {\n shipToAddressAvailabilityStatus: availabilityStatus,\n inStorePickUpAvailabilityStatus: ispuAvailabilityStatus || NOT_AVAILABLE,\n isStorePickUpLowInventory: isISPULowInventory,\n inStorePickUpAvailabilityMessage: ispuAvailabilityValue,\n inStorePickUpLowStockMessage: ispuLowStockValue,\n availableForInStorePickup: availableForInStorePickup,\n productContainer\n });\n }\n productContainer.dataset.pid = ID;\n queryFirst('.product-id', productContainer).textContent = ID;\n const manufacturerID = queryFirst('.product-manufacturer-id', productContainer);\n if (null != manufacturerID) {\n manufacturerID.textContent = manufacturerSKU;\n }\n productContainer.dataset.wishlistId = ID;\n const productData = {\n available: !hasClass(currentSizeElement, 'not-available'),\n isNotifyMeEnabled,\n id: ID,\n formattedPrice,\n forceOutOfStock,\n imageData: ispu\n };\n handleNotifyMe(productData, productContainer);\n if (!isDirectlyPurchasable) {\n if (ispuButton) {\n ispuButton.disabled = true;\n }\n } else if (ispuButton) {\n ispuButton.disabled = false;\n ispuButton.dataset.pid = ID;\n const pickupImageElement = queryFirst('.pickup-product-img img', productContainer);\n if (pickupImageElement && ispu) {\n const { alt, url, srcset } = ispu[0];\n const imageHasLoaded = hasClass(pickupImageElement, 'lz-loaded');\n\n pickupImageElement.setAttribute(imageHasLoaded ? 'src' : 'data-src', url);\n pickupImageElement.setAttribute(imageHasLoaded ? 'srcset' : 'data-srcset', srcset);\n pickupImageElement.setAttribute('alt', alt);\n }\n const pickupSalesPrice = queryFirst('.pickup-price .sale-price', productContainer);\n pickupSalesPrice.textContent = formattedPrice;\n const pickupStandardPrice = queryFirst('.pickup-price .standard-price', productContainer);\n if (formattedStandardPrice !== formattedPrice) {\n pickupStandardPrice.classList.add('mr-2');\n pickupStandardPrice.textContent = formattedStandardPrice;\n pickupSalesPrice.classList.add('has-marked-price');\n }\n queryFirst('.pickup-color .selected-color', productContainer).textContent = selectedColorName.split(':')[1];\n const pickupSize = queryFirst('.pickup-size', productContainer);\n queryFirst('.size-label', pickupSize).textContent = queryFirst('.size-display-name', productContainer).value;\n const sizeSelected = queryFirst('.size-card .size-btn.selected', productContainer);\n if (sizeSelected) {\n queryFirst('.selected-size', pickupSize).textContent = sizeSelected.dataset.attrValue;\n }\n }\n const ispuCheckBoxChecked = queryFirst('.shipping-preferences .preference-ispu', productContainer);\n const availabilityElement = queryFirst('.product-availability .availability-message-text', productContainer);\n if (ispuCheckBoxChecked && ispuCheckBoxChecked.checked) {\n addClass(availabilityElement, HIDDEN_CLASS);\n }\n const product = {};\n if (mgFlag && mgLocs && mgLocs.length > 0) {\n const monogramImages = images.monogram || [];\n let url = '';\n let srcset = '';\n if (monogramImages.length) {\n const updatedImageData = base.updateImageDetails(monogramImages)[0];\n url = updatedImageData.url;\n srcset = updatedImageData.srcset;\n }\n const monogramObject = {\n monogramProductID: ID,\n monogramImageURL: url,\n monogramImageSrcSetURL: srcset,\n monogramLocations: mgLocs,\n monogramSelectedColor: selectedColorName,\n monogramSelectedSize: selectedSizeValue,\n productPrice: formattedPrice,\n monogramProductPrice,\n totalPrice: totalPrice\n };\n product.monogramObject = monogramObject;\n }\n\n // secret sauce integration to update product data\n updateProductData(selectedColorName, selectedSizeValue, standardPrice, price, productContainer);\n handleSize(productContainer);\n}\n\nconst init = () => {\n $('body').on('product:handleImageZoom', handleProductImageZoom);\n $('.carousel.image-slider').carousel();\n $('.primary-images').on('click', '.carousel-indicators-images li,.carousel-indicators li ', function (e) {\n const clickedContainerEle = this.closest('.primary-images');\n const carouselIndicatorsActivedImages = queryFirst('.carousel-indicators-images li.active', clickedContainerEle);\n const carouselIndicatorsActivedPips = queryFirst('.carousel-indicators li.active', clickedContainerEle);\n removeClass(carouselIndicatorsActivedImages, ACTIVE_CLASS);\n removeClass(carouselIndicatorsActivedPips, ACTIVE_CLASS);\n let idx = $(this).index() + 1;\n const carouselIndicatorsToBeActivedImages = queryFirst('.carousel-indicators-images li:nth-child(' + idx + ')', clickedContainerEle);\n const carouselIndicatorsToBeActivedPips = queryFirst('.carousel-indicators li:nth-child(' + idx + ')', clickedContainerEle);\n addClass(carouselIndicatorsToBeActivedImages, ACTIVE_CLASS);\n addClass(carouselIndicatorsToBeActivedPips, ACTIVE_CLASS);\n const carouselMzThumbSelected = queryFirst('.carousel-indicators-images li:nth-child(' + idx + ') a.mz-thumb-selected', clickedContainerEle);\n const carouselInnerItem = queryFirst('.carousel-inner .carousel-item:nth-child(' + idx + ') a', clickedContainerEle);\n const carouselItemImage = queryAll('.carousel-inner .carousel-item:nth-child(' + idx + ') a img', clickedContainerEle);\n const carouselMzZoomWindow = queryAll('.mz-zoom-window img');\n const newImgSrc = carouselInnerItem?.getAttribute('href') ?? '';\n const newImgAlt = carouselItemImage.length > 0 ? carouselItemImage[0].getAttribute('alt') : '';\n $(carouselMzThumbSelected).triggerHandler('click');\n carouselItemImage.forEach((imgEle) => {\n imgEle.setAttribute('src', newImgSrc);\n });\n carouselMzZoomWindow.forEach((mzZoomImg) => {\n if (mzZoomImg.alt === newImgAlt) {\n mzZoomImg.setAttribute('src', newImgSrc);\n mzZoomImg.setAttribute('alt', newImgAlt);\n }\n });\n });\n\n setTimeout(() => {\n setDynamicHeight();\n }, 3000); // Adjust the debounce delay as needed\n updateFitSizeTab();\n const productName = queryFirst('.product-name-row .product-name');\n if (productName) {\n productName.innerHTML = productName.innerHTML.replace(/-/g, '‑');\n }\n let carouselIns = $('.product-detail .primary-images .carousel');\n carouselIns.carousel(0);\n};\n\n/**\n * Show the Fit Size Tab if fit size selectable count is greater than one\n */\nfunction updateFitSizeTab() {\n const fitSizeSelectableCountEle = queryAll('.selectableCount');\n fitSizeSelectableCountEle.forEach(fitSizeSelectableCount => {\n const fitSizeSelectableConatiner = fitSizeSelectableCount.closest('.fit-size-tab');\n const sizeAccordionEle = fitSizeSelectableCount.closest('.size-card');\n const fitSizeText = queryFirst('.fitsize-detail-text', sizeAccordionEle);\n const sizeText = queryFirst('.size-detail-text', sizeAccordionEle);\n if (fitSizeSelectableCount) {\n const fitSizeCount = fitSizeSelectableCount.dataset.selectableCount;\n const fitSizes = queryAll('.non-color-attribute.fit-product-type', fitSizeSelectableConatiner);\n if (fitSizes && fitSizes.length > 0) {\n let selectedFit = queryFirst('.non-color-attribute.fit-product-type.selected', fitSizeSelectableConatiner);\n if (!selectedFit) {\n let firstAvailableFit = fitSizes[0];\n $(firstAvailableFit).trigger('click');\n }\n }\n if (fitSizeCount > 1) {\n removeClass(fitSizeSelectableConatiner, 'fit-size-tab');\n addClass(sizeText, 'd-none');\n removeClass(fitSizeText, 'd-none');\n } else {\n removeClass(sizeText, 'd-none');\n addClass(fitSizeText, 'd-none');\n }\n }\n });\n\n updateScarcityMessage('', queryFirst('.product-detail'));\n}\nconst handleLastLinkTab = e => {\n const sizeChartCatBtn = queryFirst('#sizechart-menu-toggle');\n const isTabPressed = e.key === TabKey || e.keyCode === KEYCODE_TAB;\n if (!isTabPressed) {\n return;\n }\n\n if (!e.shiftKey) {\n sizeChartCatBtn.focus();\n }\n};\n\nexport default {\n init: init,\n\n availability: base.availability,\n\n addToCart: base.addToCart,\n\n scrollFitRatingToReviews: function () {\n $(document).on('click', 'button.fit-review, button.no-fit-review', function (e) {\n e.preventDefault();\n const bvReviews = document.getElementById('bazaarvoiceReviews');\n if (bvReviews) {\n scrollTo(window.scrollY + bvReviews.getBoundingClientRect().top, 0);\n }\n });\n },\n\n handleProductImageZoom: handleProductImageZoom,\n\n updateAttribute: function () {\n $('body').on('product:afterAttributeSelect', function (e, response) {\n const { container } = response;\n const {\n id,\n variationAttributes,\n gtmData,\n gtmGA4Data\n } = response.data.product;\n if ($('.product-detail>.bundle-items').length) {\n container.data('pid', id);\n container.find('.product-id').text(id);\n } else if ($('.product-set-detail').eq(0)) {\n container.data('pid', id);\n container.find('.product-id').text(id);\n } else {\n $('.product-id').text(id);\n $('.product-detail:not(\".bundle-item\")').data('pid', id);\n }\n\n const $addToCart = $('.add-to-cart');\n\n if (gtmData) {\n $addToCart.data('gtmdata', gtmData);\n }\n\n if (gtmGA4Data) {\n $addToCart.data('gtmga4data', gtmGA4Data);\n }\n\n updateSelectedSwatchProductName(variationAttributes, container);\n $('body').trigger('product:handleImageZoom');\n updateFitSizeTab();\n });\n },\n\n selectSizeAttribute: function () {\n $('body').off('click').on('click', '.set-items .size-btn, .product-quickview .size-btn, .quick-buy .size-btn', function (e) {\n e.preventDefault();\n const buttonElement = e.target;\n const $productContainer = $(this).closest('.product-detail');\n if ($productContainer.hasClass('quick-buy')) {\n const $body = $('body');\n const productTileItem = $(this).closest('.product-tile-container')[0];\n const productName = queryFirst('.product-name a', productTileItem).textContent;\n const selectedColor = $(this).closest('.product-tile-container').find('.product-tile-swatch.selected').data('swatch-name');\n const plpItemImage = queryFirst('.tile-image', productTileItem);\n const notifyImageElementMarkup = `
`;\n const size = $(this).data('attr-value');\n if ($(this).hasClass('not-available')) {\n if ($(this).data('stock-notification')) {\n $('.quick-buy-modal').modal('hide')\n const notifyContainer = queryFirst('.notify-me-container');\n const notifyImageElement = queryFirst('.notify-product-img', notifyContainer);\n notifyImageElement.innerHTML = notifyImageElementMarkup;\n queryFirst('.notify-product-name', notifyContainer).textContent = productName;\n const productPrice = queryFirst('.price-section .sales .value', productTileItem).innerText;\n queryFirst('.notify-price', notifyContainer).textContent = productPrice;\n const pid = $(this).data('variation-id');\n const sizeLabel = $('.size-display-name').val();\n const notifySize = queryFirst('.notify-size', notifyContainer);\n const notifySizeSeperator = queryFirst('.size-seperator', notifyContainer);\n const notifySelectedSize = queryFirst('.selected-size', notifyContainer);\n queryFirst('.size-label', notifySize).textContent = sizeLabel;\n queryFirst('.selected-size', notifySize).textContent = size;\n removeClass(notifySizeSeperator, 'd-none');\n removeClass(notifySelectedSize, 'd-none');\n if (pid) {\n document.getElementById('notifySku').value = pid;\n }\n const custEmail = (document.getElementById('notifyEmail') || {}).value;\n if (custEmail) {\n queryFirst('.notify-email', notifyContainer).value = custEmail;\n }\n const notifyForm = queryFirst('.notify-form.enable-form-validate', notifyContainer);\n removeClass(notifyForm, 'd-none');\n const notifyConfirm = queryFirst('.notify-me-confirm', notifyContainer);\n addClass(notifyConfirm, 'd-none');\n $('div.quick-buy-notifyme').find('#notifyMe').modal('show');\n }\n } else {\n $('.quick-buy-modal').modal('hide');\n $body.removeClass('modal-open');\n $('.quick-buy-add-toast .sizeVal').text(size);\n $('.quick-buy-add-toast .colorVal').text(selectedColor);\n $('.quick-buy-add-toast .title').text(productName);\n $('.quick-buy-add-toast .image-container').html(notifyImageElementMarkup);\n $('.quick-buy-add-toast').attr('is-quick-buy', true);\n $('.quick-buy .size-btn').removeClass('selected');\n $(this).addClass('selected');\n if ($('.pdp-container').length === 0) {\n queryFirst('.quick-buy-add-to-cart', $productContainer[0]).click();\n }\n }\n } else {\n const isPDPSetPage = this.closest('.product-set-item');\n if ($productContainer.hasClass('cached-quick-view') && !hasClass(buttonElement, 'selected')) {\n const productContainer = this.closest('.product-detail');\n const selectedColorElement = queryFirst('.color-attribute .swatch-circle.selected', productContainer);\n const selectedColorId = selectedColorElement.dataset.attrValue;\n const selectedSizeValue = this.dataset.attrValue;\n onSizeChangeHandler.apply(this, productContainer, selectedSizeValue);\n updateQuickViewProductInfo(selectedSizeValue, selectedColorId, productContainer, this);\n } else if (isPDPSetPage) {\n const productContainerEle = isPDPSetPage;\n if (!hasClass(productContainerEle, 'scrollable-product-item')) {\n const url = buttonElement.dataset.attrUrl;\n base.attributeSelect(url, $productContainer, buttonElement);\n } else {\n const selectedColorElement = queryFirst('.color-attribute .swatch-circle.selected', productContainerEle);\n const selectedColorIdValue = selectedColorElement.dataset.attrValue;\n const selectedSizeEleValue = this.dataset.attrValue;\n onSizeChangeHandler.apply(this, [productContainerEle, selectedSizeEleValue]);\n $body.trigger('product:pdpSizeSelected', {\n selectedColorElement,\n selectedSizeElement: buttonElement,\n productContainer: productContainerEle\n });\n updateProductInfo(selectedSizeEleValue, selectedColorIdValue, productContainerEle, this, isPDPSetPage);\n }\n //Code echange to Fix the Scrolling issue on PDP Set page on click on Add all to Cart CTA\n const availabilityEle = queryFirst('.product-availability', productContainerEle);\n if (availabilityEle) {\n $(availabilityEle).attr('data-ready-to-order', true);\n }\n }\n }\n });\n $('body').on('product:quickViewAttributeChange', (e, response) => {\n const selectedSizeElement = queryFirst('.product-quickview.cached-quick-view .size-btn.selected');\n const selectedValue = selectedSizeElement ? selectedSizeElement.dataset.attrValue : '';\n updateQuickViewProductInfo(selectedValue, response.variantGroupId, response.container[0], selectedSizeElement);\n });\n window.addEventListener('resize', throttle(() => {\n const quickViewCarouselEl = queryFirst('.product-quickview.cached-quick-view .carousel');\n if (quickViewCarouselEl) {\n quickViewCarouselEl.style.minHeight = '';\n }\n }, 16));\n },\n afterAttributeSelect: function () {\n $('body').on('product:afterAttributeSelect', (event, response) => {\n const { selectedSizeElement } = response;\n const { product } = response.data;\n const { id, readyToOrder, available, formattedPrice, formattedStandardPrice, forceOutOfStock, price, wishListID, images, isDirectlyPurchasable } = product;\n const { ispu } = images;\n const responseContainer = response.container[0];\n const addToCartButton = queryFirst('.add-to-cart', responseContainer);\n responseContainer.dataset.pid = id;\n responseContainer.dataset.wishlistId = wishListID;\n\n let ssSize = 'unknown';\n const hiddenClass = 'd-none';\n if (hasClass(responseContainer, 'product-quickview') && addToCartButton) {\n addToCartButton.disabled = false;\n }\n if (selectedSizeElement) {\n ssSize = selectedSizeElement.dataset.attrValue;\n removeClass(queryAll('.size-btn', responseContainer), 'selected');\n addClass(selectedSizeElement, 'selected');\n const sizeCard = selectedSizeElement.closest('.size-card');\n const selectedSize = queryFirst('.selected-size', sizeCard);\n if (selectedSize) {\n const sizeSeparator = queryFirst('.size-seperator', sizeCard);\n selectedSize.textContent = selectedSizeElement.dataset.attrValue;\n removeClass([sizeSeparator, selectedSize], hiddenClass);\n }\n const sizeContainer = selectedSizeElement.closest('.size-container');\n const assistiveElements = queryAll('.selected-assistive-text', sizeContainer);\n assistiveElements.forEach(eachElement => {\n if (eachElement.textContent.includes(eachElement.dataset.outOfStock)) {\n eachElement.textContent = eachElement.dataset.outOfStock;\n } else {\n eachElement.textContent = '';\n }\n });\n const assistiveElementOfSelected = queryFirst('.selected-assistive-text', selectedSizeElement.closest('.size-list'));\n const { selectedText, outOfStock } = assistiveElementOfSelected.dataset;\n assistiveElementOfSelected.textContent = selectedText;\n if (hasClass(selectedSizeElement, 'not-available')) {\n assistiveElementOfSelected.textContent += ' ' + outOfStock;\n }\n if (addToCartButton) {\n addToCartButton.disabled = !readyToOrder || !available || forceOutOfStock;\n }\n\n const quickviewContainer = selectedSizeElement.closest('.product-quickview');\n if (quickviewContainer) {\n const addToCartSection = queryFirst('.prices-add-to-cart-actions', responseContainer);\n const notifyMeButton = queryFirst('.notify-me-btn', responseContainer);\n const notifyMeDesc = queryFirst('.notify-me-desc', responseContainer);\n const availabilityMessageEl = queryFirst('.product-availability', responseContainer);\n const { isNotifyMeEnabled, isDirectlyPurchasable } = product;\n const salesPrice = price.type === 'range' ? price.min.sales : price.sales;\n const productData = {\n available,\n isNotifyMeEnabled,\n id,\n formattedPrice: salesPrice.formatted,\n forceOutOfStock,\n imageData: ispu\n };\n handleNotifyMe(productData, quickviewContainer);\n const updateCartButton = queryFirst('.update-cart-product-global', quickviewContainer);\n if (updateCartButton) {\n const { giftWrapAvailableFlag } = product;\n updateCartButton.dataset.giftWrapAvailable = giftWrapAvailableFlag;\n }\n if (isDirectlyPurchasable === false) {\n removeClass(addToCartSection, hiddenClass);\n if (availabilityMessageEl) {\n removeClass(availabilityMessageEl, hiddenClass);\n }\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n }\n }\n\n const ispuButton = queryFirst('.btn-in-store-pickup', responseContainer);\n if (ispuButton) {\n ispuButton.dataset.pid = id;\n ispuButton.disabled = false;\n const pickupImageElement = queryFirst('.pickup-product-img img', responseContainer);\n if (pickupImageElement && ispu) {\n const { alt, url, srcset } = ispu[0];\n pickupImageElement.setAttribute('src', url);\n pickupImageElement.setAttribute('srcset', srcset);\n pickupImageElement.setAttribute('alt', alt);\n }\n queryFirst('.pickup-product-name', responseContainer).textContent = product.productName;\n const pickupSalesPrice = queryFirst('.pickup-price .sale-price');\n if (pickupSalesPrice) {\n pickupSalesPrice.textContent = (product.price && product.price.sales) ? product.price.sales.formatted : '';\n }\n const pickupStandardPrice = queryFirst('.pickup-price .standard-price');\n if (formattedStandardPrice !== formattedPrice && pickupStandardPrice) {\n pickupStandardPrice.classList.add('mr-2');\n pickupStandardPrice.textContent = formattedStandardPrice;\n pickupSalesPrice.classList.add('has-marked-price');\n }\n const selectedSwatchName = queryFirst('.selected-swatch-name', responseContainer);\n if (selectedSwatchName) {\n queryFirst('.pickup-color .selected-color', responseContainer).textContent = selectedSwatchName.textContent;\n }\n const pickupSize = queryFirst('.pickup-size', responseContainer);\n queryFirst('.size-label', pickupSize).textContent = queryFirst('.size-display-name', responseContainer).value;\n const sizeSelected = queryFirst('.size-card .size-btn.selected', responseContainer);\n if (sizeSelected) {\n queryFirst('.selected-size', pickupSize).textContent = sizeSelected.dataset.attrValue;\n }\n }\n }\n if (hasClass(responseContainer, 'product-quickview') && isDirectlyPurchasable === false) {\n const addToCartSection = queryFirst('.prices-add-to-cart-actions', responseContainer);\n const notifyMeButton = queryFirst('.notify-me-btn', responseContainer);\n const notifyMeDesc = queryFirst('.notify-me-desc', responseContainer);\n const availabilityMessageEl = queryFirst('.product-availability', responseContainer);\n removeClass(addToCartSection, hiddenClass);\n if (addToCartButton) {\n addToCartButton.disabled = true;\n }\n if (availabilityMessageEl) {\n removeClass(availabilityMessageEl, hiddenClass);\n }\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n }\n const wishlistButton = queryFirst('.add-to-wish-list', responseContainer);\n if (wishlistButton && hasClass(wishlistButton, 'added-to-wish-list')) {\n removeClass(wishlistButton, 'added-to-wish-list');\n wishlistButton.disabled = false;\n const assistiveText = wishlistButton.getAttribute('data-assistive-text');\n wishlistButton.setAttribute('aria-label', assistiveText);\n }\n if (!hasClass(responseContainer, 'gift-card-main') && !document.getElementById('chooseBonusProductModal')) {\n const ssColorElement = queryFirst('.color-container .color-attribute.selected', responseContainer);\n const ssColor = (ssColorElement && ssColorElement.dataset.attrDisplayvalue) || 'unknown';\n const { type } = price;\n const pricesObject = type === 'range' ? price.min : price;\n const { sales, list } = pricesObject;\n const ssSalesPrice = ((sales && sales.value) ? sales.value.toString() : 'unknown') || 'unknown';\n const ssPrice = ((list && list.value) ? list.value.toString() : ssSalesPrice) || ssSalesPrice;\n updateProductData(ssColor, ssSize, ssPrice, ssSalesPrice, responseContainer);\n if (ssSize === 'unknown') {\n handleColor(responseContainer);\n } else {\n handleSize(responseContainer);\n }\n }\n if (selectedSizeElement) {\n const productSetModal = selectedSizeElement.closest('#productSetModal');\n if (productSetModal) {\n const addAllToToteButton = queryFirst('.add-to-cart-global', productSetModal);\n if (addAllToToteButton) {\n const productsAvailability = queryAll('.product-availability', productSetModal).filter(item => !hasClass(item.closest('.product-detail'), 'hidden-set'));\n const numberOfProducts = productsAvailability.length;\n\n // Check to enable add to tote button, if atleast one product exists\n let enable = true;\n if (!numberOfProducts) {\n enable = false;\n }\n addAllToToteButton.disabled = !enable;\n }\n }\n }\n setTimeout(() => {\n setDynamicHeight();\n }, 200);\n updateFitSizeTab();\n $.spinner().stop();\n });\n },\n selectPdpSizeAttribute: function () {\n $(document).on('click', '.pdp-container .size-btn', function (e) {\n e.preventDefault();\n\n const productContainer = this.closest('.product-detail');\n const selectedColorElement = queryFirst('.color-attribute .swatch-circle.selected', productContainer);\n const selectedColorId = selectedColorElement.dataset.attrValue;\n const selectedSizeValue = this.dataset.attrValue;\n onSizeChangeHandler.apply(this, [productContainer, selectedSizeValue]);\n $body.trigger('product:pdpSizeSelected', {\n selectedColorElement,\n selectedSizeElement: this,\n productContainer\n });\n $('.sku-section').removeClass('d-none');\n updateProductInfo(selectedSizeValue, selectedColorId, productContainer, this);\n });\n $('body').on('product:afterAttributeChange', (e, response) => {\n const selectedSizeElement = queryFirst('.pdp-container .size-btn.selected');\n const selectedValue = selectedSizeElement ? selectedSizeElement.dataset.attrValue : '';\n updateProductInfo(selectedValue, response.variantGroupId, response.container[0], selectedSizeElement);\n });\n\n const swatchEl = queryFirst('.pdp-container button.color-attribute .swatch-circle.selected');\n\n if (swatchEl) {\n const sizeElements = queryAll('.pdp-container .size-btn');\n\n if (sizeElements.length) {\n if (sizeElements.length === 1) {\n queryFirst('.pdp-container .size-btn').click();\n } else {\n const selectedSizeEl = queryFirst('.pdp-container .size-btn.selected');\n\n if (selectedSizeEl) {\n selectedSizeEl.click();\n }\n }\n\n if (!queryFirst('.pdp-container .size-btn.not-purchasable')) {\n const allSizesSoldOut = sizeElements.every((sizeElement) => hasClass(sizeElement, 'not-available'));\n\n if (allSizesSoldOut) {\n removeClass(swatchEl, 'selectable');\n\n const allSelectableSwatches = queryAll('.pdp-container button.color-attribute .swatch-circle.selectable');\n const notifyMeDesc = queryFirst('.notify-me-desc.d-none');\n\n if (allSelectableSwatches.length && notifyMeDesc.length) {\n // Hide the selected swatch because it's out of stock\n addClass(swatchEl.closest('li'), 'd-none');\n allSelectableSwatches[0].click();\n }\n }\n }\n }\n }\n },\n\n updateAttributesAndDetails: function () {\n $('body').on('product:statusUpdate', function (e, data) {\n var $productContainer = $('.product-detail[data-pid=\"' + data.id + '\"]');\n\n $productContainer\n .find('.description-and-detail .product-attributes')\n .empty()\n .html(data.attributesHtml);\n\n if (data.shortDescription) {\n $productContainer.find('.description-and-detail .description').removeClass('hidden-xl-down');\n $productContainer\n .find('.description-and-detail .description .content')\n .empty()\n .html(data.shortDescription);\n } else {\n $productContainer.find('.description-and-detail .description').addClass('hidden-xl-down');\n }\n\n if (data.longDescription) {\n $productContainer.find('.description-and-detail .details').removeClass('hidden-xl-down');\n $productContainer\n .find('.description-and-detail .details .content')\n .empty()\n .html(data.longDescription);\n } else {\n $productContainer.find('.description-and-detail .details').addClass('hidden-xl-down');\n }\n });\n },\n\n showSpinner: function () {\n $('body').on('product:beforeAddToCart product:beforeAttributeSelect', function () {\n const productSetModal = document.getElementById('productSetModal');\n const quickViewModal = document.getElementById('quickViewModal');\n if (productSetModal && hasClass(productSetModal, 'show')) {\n $(productSetModal)\n .spinner()\n .start();\n } else if (quickViewModal && hasClass(quickViewModal, 'show')) {\n $(quickViewModal)\n .spinner()\n .start();\n } else {\n $.spinner().start();\n }\n });\n },\n updateAvailability: function () {\n $('body').on('product:updateAvailability', function (e, response) {\n $('div.availability', response.$productContainer)\n .attr('data-ready-to-order', response.product.readyToOrder)\n .attr('data-available', response.product.available);\n\n var availabilityValue = '';\n var availabilityMessages = response.product.availability.messages;\n if (response.product.readyToOrder) {\n availabilityMessages.forEach(message => {\n availabilityValue += availabilityMessageTmpl(message);\n });\n }\n\n $('.availability-msg', response.$productContainer)\n .empty()\n .html(availabilityValue);\n\n if ($('.global-availability').length) {\n var allAvailable = $('.product-availability')\n .toArray()\n .every(function (item) {\n return $(item).data('available');\n });\n\n var allReady = $('.product-availability')\n .toArray()\n .every(function (item) {\n return $(item).data('ready-to-order');\n });\n\n $('.global-availability')\n .data('ready-to-order', allReady)\n .data('available', allAvailable);\n\n $('.global-availability .availability-msg')\n .empty()\n .html(allReady ? response.message : response.resources.info_selectforstock);\n }\n });\n },\n sizeChart: function () {\n var $prodSizeChart = $('.size-chart-collapsible');\n $('body').on('click', '.size-chart .size-chart-link', function (e) {\n e.preventDefault();\n var url = $(this).data('href');\n var $lpSlideout = $('.lp-sizechart');\n var activeCategoryVal = $(this).data('sizefamily');\n var defaultText = $(this).data('defaulttext');\n const setStickyNav = queryFirst('.custom-set-detail-sticky-nav');\n if ($prodSizeChart.is(':empty')) {\n $.ajax({\n url: url,\n type: 'get',\n dataType: 'json',\n success: function (data) {\n $prodSizeChart.append(data.content);\n },\n complete: function () {\n var $activeCategoryEl = $prodSizeChart.find(`a[href=\"#${activeCategoryVal}-size\"]`);\n var $lpSizechartTitle = $prodSizeChart.find('.lp-sizechart-category-btn');\n $lpSizechartTitle.focus();\n $activeCategoryEl.tab('show');\n $lpSizechartTitle.text($activeCategoryEl.text().length ? $activeCategoryEl.text() : defaultText);\n\n $prodSizeChart.animate(\n {\n right: '0'\n },\n 500\n );\n $prodSizeChart.addClass('active');\n $lpSlideout.toggleClass('lp-slideout-open');\n $body.toggleClass(sizeChartClasses);\n\n const lastLinkEl = queryFirst('.return-policy-link');\n // console.log(lastLinkEl);\n if (lastLinkEl) {\n lastLinkEl.addEventListener('keydown', handleLastLinkTab);\n }\n }\n });\n } else {\n $prodSizeChart.toggleClass('active');\n $lpSlideout.toggleClass('lp-slideout-open');\n $body.toggleClass(sizeChartClasses);\n }\n if (setStickyNav) {\n addClass(setStickyNav, 'd-none');\n }\n $lpSlideout.trigger('shown.lp.sizeguide');\n });\n\n $('body').on('click touchstart', function (e) {\n if (e.target.matches('#sizechart-close') || (e.target.matches('.size-chart-bg') && $prodSizeChart.hasClass('active'))) {\n $prodSizeChart.removeClass('active');\n $('.lp-slideout').removeClass('lp-slideout-open');\n $body.removeClass(sizeChartClasses);\n }\n });\n },\n\n focusChooseBonusProductModal: base.focusChooseBonusProductModal(),\n renderSizeElements: base.renderSizeElements,\n handleEarlyAccessPLPLockIcon: base.handleEarlyAccessPLPLockIcon(),\n handleEarlyAccessLockIcon: function () {\n const productContainer = queryFirst('.pdp-container');\n const productContainerEarlyAccessIcon = queryFirst('.loyalty-early-access-lock-container', productContainer);\n if (productContainerEarlyAccessIcon) {\n const { earlyAccessDate } = productContainerEarlyAccessIcon.dataset;\n const earlyAccessItem = isEarlyAccessElement(earlyAccessDate);\n base.handleEarlyAccessCta(productContainer, earlyAccessItem);\n }\n },\n handleOflineProduct: function () {\n const offlineContainerEl = queryFirst('.offline-product-detail');\n if (offlineContainerEl) {\n const pid = offlineContainerEl.dataset.pid;\n const inventoryData = window.productInventory;\n if (inventoryData && inventoryData.variants) {\n const data = inventoryData.variants[pid];\n if (data && data.availabilityStatus === IN_STOCK) {\n location.search = (location.search ? location.search + '&' : '') + 'timestamp=' + new Date().getTime();\n }\n }\n }\n },\n};\n\n/**\n * Set dynamic height for carousel indicators based on main image height.\n */\nfunction setDynamicHeight() {\n const pdpContainer = document.querySelector('.container-fluid.product-detail');\n if (!pdpContainer) return;\n\n const carousels = document.querySelectorAll('.container-fluid.product-detail .carousel');\n carousels.forEach((carousel) => {\n const imgContainer = document.querySelector('.primary-images');\n const carouselIndicators = carousel.querySelector('.carousel-indicators-images');\n const mainImageHeight = imgContainer ? imgContainer.clientHeight : 0;\n if (carouselIndicators) {\n carouselIndicators.style.maxHeight = `${mainImageHeight}px`;\n }\n })\n}\n\n/**\n * Debounce function to handle window resize event.\n */\nfunction handleResize() {\n clearTimeout(resizeTimeout);\n let resizeTimeout = setTimeout(() => {\n setDynamicHeight();\n base.updatedimageSlideArrowPDP();\n }, 200); // Adjust the debounce delay as needed\n}\n\n/**\n * Attach event listener for window resize using the debounce mechanism.\n */\nwindow.addEventListener('resize', handleResize);\n\n","'use strict';\n\nconst { queryFirst, addClass, removeClass, hasClass, matchesBreakpoint } = require('../domUtil');\nconst { getNestedValue } = require('../util');\nconst { selectStyleMessageTmpl, ispuSelectStyleMessageTmpl } = require('../templates').productDetail;\nconst { EMPTY_STRING } = require('../constants');\n\n/**\n * Function to check if shipping preferences view is enabled or not\n * @returns { boolean } - returns isEnabled flag value\n */\nfunction isShippingPreferencesViewEnabled() {\n return getNestedValue(window, 'johnnyWasUtils.shippingPreferencesConfig.isEnabled') || false;\n}\n\n\n/**\n * This method manages Notify me container content\n * @param {Object} productData - Product data\n * @param {Object} productContainer - Product Container DOM element\n */\nfunction handleNotifyMe(productData, productContainer) {\n const $body = $('body');\n const addToCartSection = queryFirst('.prices-add-to-cart-actions', productContainer);\n const notifyContainer = queryFirst('.notify-me-container', productContainer);\n const notifyMeButton = queryFirst('.notify-me-btn', productContainer);\n const notifyMeDesc = queryFirst('.notify-me-desc', productContainer);\n const availabilityMessageEl = queryFirst('.product-availability', productContainer);\n const isPDPPage = queryFirst('.product-detail');\n const mainImageEle = queryFirst('.primary-images .carousel-item.active img', productContainer);\n const hiddenClass = 'd-none';\n const { available, isNotifyMeEnabled, id, forceOutOfStock, imageData } = productData;\n if (!available && isNotifyMeEnabled && !forceOutOfStock) {\n addClass(addToCartSection, hiddenClass);\n if (availabilityMessageEl) {\n addClass(availabilityMessageEl, hiddenClass);\n }\n removeClass([notifyMeDesc, notifyMeButton], hiddenClass);\n const notifyImageElement = queryFirst('.notify-product-img img', notifyContainer);\n if (imageData && notifyImageElement) {\n const { alt, url, srcset, src } = isPDPPage ? mainImageEle : imageData[0];\n const imageHasLoaded = hasClass(notifyImageElement, 'lz-loaded');\n\n notifyImageElement.setAttribute(imageHasLoaded ? 'src' : 'data-src', isPDPPage ? src : url);\n notifyImageElement.setAttribute(imageHasLoaded ? 'srcset' : 'data-srcset', srcset);\n notifyImageElement.setAttribute('alt', alt);\n }\n const notifySize = queryFirst('.notify-size', notifyContainer);\n const notifySizeSeperator = queryFirst('.size-seperator', notifyContainer);\n const notifySelectedSize = queryFirst('.selected-size', notifyContainer);\n queryFirst('.size-label', notifySize).textContent = queryFirst('.size-display-name', productContainer).value;\n queryFirst('.selected-size', notifySize).textContent = queryFirst('.size-btn.selected', productContainer).dataset.attrValue;\n removeClass(notifySizeSeperator, 'd-none');\n removeClass(notifySelectedSize, 'd-none');\n if (id) {\n queryFirst('.notify-pid', notifyContainer).value = id;\n }\n const custEmail = (document.getElementById('notifyEmail') || {}).value;\n if (custEmail) {\n queryFirst('.notify-email', notifyContainer).value = custEmail;\n }\n removeClass(queryFirst('.notify-me-desc', notifyContainer), hiddenClass);\n removeClass(queryFirst('.notify-form', notifyContainer), hiddenClass);\n addClass(queryFirst('.notify-me-confirm', notifyContainer), hiddenClass);\n addClass(queryFirst('.footer-close-link', notifyContainer), hiddenClass);\n\n $body.trigger('product:notifyMeShown', productContainer);\n } else {\n removeClass(addToCartSection, hiddenClass);\n if (availabilityMessageEl) {\n removeClass(availabilityMessageEl, hiddenClass);\n }\n addClass([notifyMeDesc, notifyMeButton], hiddenClass);\n\n $body.trigger('product:notifyMeHidden', productContainer);\n }\n}\n\n/**\n * Function to toggle select color or size info\n * @param {HTMLElement} productContainer - current product element\n */\nfunction toggleSelectSizeInfo(productContainer) {\n const selectedSizeEl = queryFirst('.size-btn.selected', productContainer);\n const availabilityMessageEl = queryFirst('.select-size-message', productContainer);\n if (availabilityMessageEl) {\n if (!selectedSizeEl) {\n removeClass(availabilityMessageEl, 'd-none');\n availabilityMessageEl.innerHTML = selectStyleMessageTmpl(availabilityMessageEl.dataset.selectStylesMessage);\n }\n }\n\n if (isShippingPreferencesViewEnabled()) {\n const ispuAvailabilityMessageEl = queryFirst('.ispu-preference-container .select-size-info-msg', productContainer);\n if (ispuAvailabilityMessageEl) {\n const messages = getNestedValue(window, 'johnnyWasUtils.shippingPreferencesConfig.messages') || {};\n const { selectStylesMessage } = messages;\n if (!selectedSizeEl && selectStylesMessage) {\n ispuAvailabilityMessageEl.innerHTML = ispuSelectStyleMessageTmpl(selectStylesMessage);\n }\n }\n }\n}\n/**\n * Helper method to check if product is on early access or not\n * @param {Object|String} earlyAccess - product | early access date\n * @return {Boolean} true, if early access product or false for not\n */\nfunction isEarlyAccessElement(earlyAccess) {\n let isEarlyAccessItem = false;\n const earlyAccessDate = earlyAccess && earlyAccess.earlyAccessUntilDate || earlyAccess;\n if (earlyAccessDate && earlyAccessDate !== 'false') {\n if (new Date(earlyAccessDate).getTime() > new Date().getTime()) {\n isEarlyAccessItem = true;\n }\n }\n return isEarlyAccessItem;\n}\n\nconst updatePLPTileHeight = (element) => {\n let cards = $('.tile-img-link');\n let carouselImageHeight = cards;\n\n if (element) {\n carouselImageHeight = $('.carousel-inner');\n }\n\n // Find the maximum height among the cards\n let maxHeight = Math.max.apply(null, carouselImageHeight.map(function () {\n return $(this).height();\n }).get());\n\n // Set the same height for all cards\n cards.height(maxHeight);\n};\n\n\nmodule.exports = {\n toggleSelectSizeInfo: toggleSelectSizeInfo,\n isEarlyAccessElement: isEarlyAccessElement,\n isShippingPreferencesViewEnabled: isShippingPreferencesViewEnabled,\n handleNotifyMe: handleNotifyMe,\n updatePLPTileHeight: updatePLPTileHeight\n};\n\n","'use strict';\n\nconst base = require('./base').default;\nconst detail = require('./detail').default;\nconst { updateSelectedSwatchProductName, injectAfterpay, injectFitPredictor, injectLongDescription, updateFullProductLink } = require('../quickView/quickViewHelpers').default;\nconst focusHelper = require('base/components/focus');\nconst { getJSON } = require('../util');\nconst { getLastElementInRow, getStyles, hasClass, queryFirst, remove, scrollTo } = require('../domUtil');\nconst { quickView: quickViewTemplates } = require('../templates');\nconst $window = $(window);\nconst $body = $('body');\nconst { ajaxFormInvalid, ajaxFormSubmit } = require('../clientSideValidation');\nconst header = queryFirst('.main-header');\nconst { handleEarlyAccessLogin } = require('../loyalty/loyaltyDrawer');\n\n/**\n * OOTB function\n * Generates the modal window on the first call.\n * @param {HTMLElement} srcElement - quick view initiator element\n */\nfunction getModalHtmlElement(srcElement) {\n const quickViewModalEl = document.getElementById('quickViewModal');\n remove(quickViewModalEl);\n const quickview = $(quickViewTemplates.quickViewModal);\n quickview.data('srcElement', srcElement);\n $('body').append(quickview);\n}\n\n/**\n * OOTB function\n * Parse HTML code in Ajax response\n *\n * @param {string} html - Rendered HTML from quickview template\n * @return {QuickViewHtml} - QuickView content components\n */\nfunction parseHtml(html) {\n const $html = $('
').append($.parseHTML(html));\n const body = $html.find('.product-quickview');\n return { body };\n}\n\n/**\n * Modifies a quickview template to include elements specific to this implementation\n * @param {string} template - The rendered template\n * @returns {string} Modified template\n */\nfunction modifyTemplate(template) {\n const openTagIndex = template.indexOf('>') + 1;\n\n return template.substr(0, openTagIndex) + template.substr(openTagIndex);\n}\n\n/**\n * Returns the additional offset that should be scrolled depending on whether the navigation menu is sticky\n * @returns {number} Main navigation offset\n */\nfunction getNavOffset() {\n return hasClass(header, 'sticky') ? header.offsetHeight : 0;\n}\n\n/**\n * Function to attach form validation events\n */\nfunction attachFormEvents() {\n const quickViewFormSelector = '.product-quickview form';\n ajaxFormInvalid(quickViewFormSelector);\n ajaxFormSubmit(quickViewFormSelector);\n}\n\n/**\n * OOTB function with changes\n * replaces the content in the modal window on for the selected product variation.\n * @param {string} selectedValueUrl - url to be used to retrieve a new product model\n * @param {jQuery.event} event - Event object which trigger the action\n */\nfunction fillModalElement(selectedValueUrl, event) {\n const quickViewModal = $('#quickViewModal');\n\n $.spinner().start();\n\n getJSON(selectedValueUrl, 'GET', null,\n data => {\n const { quickviewProductInfo } = data;\n var parsedHtml = parseHtml(data.renderedTemplate);\n\n if (quickViewModal) {\n quickViewModal.find('.modal-body').html(parsedHtml.body);\n quickViewModal.find('.size-chart').attr('href', data.productUrl);\n quickViewModal.find('.enter-message').text(data.enterDialogMessage);\n\n updateFullProductLink(data.quickViewFullDetailMsg, data.productUrl, quickViewModal);\n injectAfterpay(quickViewModal);\n injectFitPredictor(quickViewModal);\n\n if (quickviewProductInfo) {\n window.quickviewProductInfo = quickviewProductInfo;\n const swatchEl = quickViewModal.find('.color-attribute .swatch-value');\n const selectedSwatchEl = quickViewModal.find('.color-attribute .swatch-value.selected');\n const sizeElements = quickViewModal.find('.size-btn');\n if (quickviewProductInfo && swatchEl.length && !selectedSwatchEl) {\n quickViewModal.find('.color-attribute').eq(0).click();\n }\n if (selectedSwatchEl && sizeElements.length === 1 && !sizeElements.hasClass('selected')) {\n sizeElements.click();\n }\n }\n\n quickViewModal.modal('show');\n\n requestAnimationFrame(() => {\n $body.trigger('quickview:visible');\n });\n\n // Only for Gift card quickview attach form events\n if (data.gcType) {\n attachFormEvents();\n\n if (data.gcType === 'pgc' && queryFirst('.cart-page')) {\n const productLineItemEl = event.target.closest('.product-info-p-giftcard');\n // Return if the line item is not pgiftcard\n if (!productLineItemEl) {\n return;\n }\n\n const lineItemAmountEl = queryFirst('.gift-card-amount', productLineItemEl);\n if (lineItemAmountEl) {\n quickViewModal\n .find('.gift-card-custom-input-group .form-control')\n .val(lineItemAmountEl.value)\n .trigger('keyup');\n quickViewModal\n .find('.gift-card-amount')\n .val(lineItemAmountEl.value);\n }\n }\n }\n }\n\n $.spinner().stop();\n },\n () => $.spinner().stop()\n );\n}\n\n/**\n * Replaces the content in a quickview container with the template returned by the specified endpoint\n * @param {JQuery} container - jQuery element to inject HTML into\n * @param {string} url - URL of the endpoint that will return a rendered template\n * @param {JQuery} selectedProductDescriptionElement - jQuery element of selected product SEO long description \n */\nfunction injectQuickView(container, url, selectedProductDescriptionElement) {\n const spinner = $.spinner();\n const stopSpinner = () => { spinner.stop(); };\n\n spinner.start();\n\n getJSON(url, 'GET', null,\n data => {\n const { quickviewProductInfo, isEarlyAccessProduct, earlyAccessDate } = data;\n const parent = container.parent();\n const scrollHeight = parent.prop('scrollHeight');\n const scrollY = $window.scrollTop();\n const filledContainers = $('.quickview-container').not(container);\n let containerTop = container.offset().top;\n const isNewContainerBelow = !!filledContainers.length && !!filledContainers.filter((i, openContainer) => $(openContainer).offset().top < containerTop).length;\n\n filledContainers.remove();\n\n if (quickviewProductInfo) {\n window.quickviewProductInfo = quickviewProductInfo;\n }\n\n requestAnimationFrame(() => {\n containerTop = container.offset().top - getNavOffset();\n\n // If the target container is below an a container that's already injected,\n // the emptying of the existing container will cause the content to jump.\n // To offset this, we can scroll up by the difference in scrollHeight.\n if (isNewContainerBelow) {\n scrollTo(scrollY - (scrollHeight - parent.prop('scrollHeight')), 0);\n }\n\n // Modify the template returned by the endpoint so we can keep the OOTB code and\n // so that the OOTB template can be used in other implementation types (e.g. dialogs)\n container.html(modifyTemplate(data.renderedTemplate));\n const sizeElements = container.find('.size-btn');\n const swatchEl = container.find('.color-attribute .swatch-value');\n const selectedSwatchEl = container.find('.color-attribute .swatch-value.selected');\n if (quickviewProductInfo && swatchEl.length && !selectedSwatchEl) {\n container.find('.color-attribute').eq(0).click();\n }\n if (selectedSwatchEl && sizeElements.length === 1 && !sizeElements.hasClass('selected')) {\n sizeElements.click();\n }\n\n // Only for Gift card quickview attach form events\n if (data.gcType) {\n attachFormEvents();\n }\n\n updateFullProductLink(data.quickViewFullDetailMsg, data.productUrl, container);\n injectAfterpay(container);\n injectFitPredictor(container);\n injectLongDescription(selectedProductDescriptionElement, container);\n \n stopSpinner();\n scrollTo(containerTop);\n\n requestAnimationFrame(() => {\n $body.trigger('quickview:visible');\n });\n\n const wishlistButton = queryFirst('.add-to-wish-list', container[0]);\n\n if (wishlistButton) {\n setTimeout(() => {\n wishlistButton.focus();\n }, 0);\n }\n if (earlyAccessDate) {\n const { isEarlyAccessElement } = require('./helper');\n const isEarlyAccessItem = isEarlyAccessElement(earlyAccessDate);\n const quickViewContainer = queryFirst('.quickview-container');\n base.handleEarlyAccessCta(quickViewContainer, isEarlyAccessItem);\n const earlyAccessGuestSignIn = queryFirst('.js-early-access-sign-in-cta', quickViewContainer);\n earlyAccessGuestSignIn.addEventListener('click', e => {\n e.preventDefault();\n handleEarlyAccessLogin(earlyAccessGuestSignIn);\n });\n }\n });\n },\n stopSpinner\n );\n}\n\nmodule.exports = {\n showQuickview: () => {\n $body.on('click', '.product-grid .quickview', e => {\n e.preventDefault();\n\n const { target } = e;\n const $target = $(target);\n const container = $target.closest('.product-tile-container');\n const quickviewURL = $target.closest('.quickview').attr('data-href');\n const lastElementInRow = getLastElementInRow(container[0]);\n const quickviewContainer = $(quickViewTemplates.container).insertAfter(lastElementInRow);\n const seoLongDescriptionElement = $target.parents('.product-tile-container').find('.seo-long-description');\n\n injectQuickView(quickviewContainer, quickviewURL, seoLongDescriptionElement);\n\n $target.trigger('quickview:show');\n });\n $body.on('click', `\n .recommendations-products .quickview,\n .product-listing .quickview,\n .shop-by-style .quickview,\n .style-component .quickview,\n .shop-the-print-tiles .quickview,\n .cart-page .product-edit .edit,\n .cart-page .bundle-edit .edit`, e => {\n e.preventDefault();\n const $target = $(e.target);\n getModalHtmlElement($target);\n const selectedValueUrl = $target.data('href');\n fillModalElement(selectedValueUrl, e);\n $target.trigger('quickview:show');\n });\n\n $body.on('click', '.quickview-container .close-quickview', e => {\n const container = e.target.closest('.quickview-container');\n if (container) {\n const target = $(container).prev();\n const padding = parseInt(getStyles(container, 'padding-top'), 10);\n\n remove(container);\n $body.trigger('quickview:close');\n\n // Scroll back to the target row so the user doesn't lose their position\n scrollTo(target.offset().top - padding - getNavOffset(), 250);\n } else {\n $('#quickViewModal').modal('hide');\n }\n });\n\n $body.on('click', '.product-quickview .notify-me-btn', function (e) {\n e.preventDefault();\n $(this).closest('.product-quickview').find('#notifyMe').modal('show');\n });\n },\n focusQuickview: function () {\n $body.on('shown.bs.modal', '#quickViewModal', function () {\n $('#quickViewModal .close-quickview').focus();\n });\n },\n trapQuickviewFocus: function () {\n $body.on('keydown', '.product-quickview', function (e) {\n var focusParams = {\n event: e,\n containerSelector: '.product-quickview',\n firstElementSelector: '.close-quickview',\n lastElementSelector: '.full-pdp-link',\n nextToLastElementSelector: '.add-to-cart'\n };\n focusHelper.setTabNextFocus(focusParams);\n });\n },\n availability: base.availability,\n addToCart: base.addToCart,\n showSpinner: function () {\n $body.on('product:beforeAddToCart', function (e, data) {\n $(data).closest('.product-quickview').spinner().start();\n });\n },\n sizeChart: detail.sizeChart,\n hideDialog: function () {\n $body.on('product:afterAddToCart', function () {\n $('#quickViewModal').modal('hide');\n\n const isCartPage = queryFirst('.cart-container');\n const addToCartWarningDialog = queryFirst('#add-to-cart-warning-dialog') || false;\n if (isCartPage && !addToCartWarningDialog) {\n location.reload();\n }\n });\n },\n beforeUpdateAttribute: function () {\n $body.on('product:beforeAttributeSelect', function () {\n $('.product-quickview').spinner().start();\n });\n },\n updateAttribute: function () {\n $body.on('product:afterAttributeSelect', function (e, response) {\n const quickView = response.container[0];\n\n if (hasClass(quickView, 'product-quickview')) {\n const { productDetailsUrl } = response.data.product;\n const fullPDPLink = queryFirst('.full-pdp-link', quickView);\n fullPDPLink.setAttribute('href', productDetailsUrl);\n\n updateSelectedSwatchProductName(response.data.product.variationAttributes, $(quickView));\n }\n });\n },\n updateAddToCart: function () {\n $body.on('product:updateAddToCart', function (e, response) {\n const quickView = queryFirst('.product-quickview');\n\n if (quickView) {\n const disabled = !response.product.readyToOrder || !response.product.available;\n\n let buttonToUpdate;\n const addToCartButton = queryFirst('button.add-to-cart', quickView);\n if (addToCartButton) {\n buttonToUpdate = addToCartButton;\n } else {\n const updateCartButton = queryFirst('.update-cart-product-global', quickView);\n if (updateCartButton) {\n buttonToUpdate = updateCartButton;\n }\n }\n\n if (buttonToUpdate) {\n if (disabled) {\n buttonToUpdate.setAttribute('disabled', disabled);\n } else {\n buttonToUpdate.removeAttribute('disabled');\n }\n }\n }\n });\n },\n updateAvailability: function () {\n $body.on('product:updateAvailability', function (e, response) {\n const quickView = queryFirst('.product-quickview');\n\n if (quickView) {\n $('.product-availability', response.$productContainer)\n .data('ready-to-order', response.product.readyToOrder)\n .data('available', response.product.available)\n .find('.availability-msg')\n .empty()\n .html(response.message);\n }\n });\n }\n};\n","'use strict';\n\nimport { queryFirst, addClass, removeClass } from '../domUtil';\nimport { getJSON } from '../util';\n\nconst $body = $('body');\nconst hiddenClass = 'd-none';\n\nexport default {\n validateEmail: function () {\n $body.on('blur', '.notify-email', e => {\n const { target } = e;\n const { value } = target;\n const emailFormGroup = target.closest('.form-group');\n const emailError = queryFirst('.email-error', emailFormGroup);\n const { missingError, patternMismatch } = target.dataset;\n const invalidClass = 'is-invalid';\n if (!value) {\n addClass(target, invalidClass);\n emailError.textContent = missingError;\n } else if (target.checkValidity && !target.checkValidity()) {\n addClass(target, invalidClass);\n emailError.textContent = patternMismatch;\n } else {\n removeClass(target, invalidClass);\n }\n });\n },\n notifyMeSubmit: function () {\n $body.on('submit', '.notify-form', e => {\n e.preventDefault();\n const { target } = e;\n const actionUrl = target.getAttribute('action');\n const checkBoxValue = queryFirst('.notify-checkbox', target);\n const isChecked = checkBoxValue && checkBoxValue.value === 'true';\n const data = {\n productID: queryFirst('.notify-pid', target).value,\n email: queryFirst('.notify-email', target).value,\n subscribe: isChecked\n };\n $('.notify-form').spinner().start();\n getJSON(actionUrl, 'POST', data, (data) => {\n const confirmMessage = data.message;\n const notifyMeCntr = target.closest('.notify-me-container');\n const notifyMeDesc = queryFirst('.notify-me-desc', notifyMeCntr);\n addClass(notifyMeDesc, hiddenClass);\n addClass(target, hiddenClass);\n const notifyConfirm = queryFirst('.notify-me-confirm', notifyMeCntr);\n notifyConfirm.textContent = confirmMessage;\n removeClass(notifyConfirm, hiddenClass);\n removeClass(queryFirst('.footer-close-link', notifyMeCntr), hiddenClass);\n $.spinner().stop();\n }, () => {\n $.spinner().stop();\n });\n });\n },\n notifyMeCloseCTA: function () {\n // Code to close the nearest boostrap modal\n $body.on('click', '.lp-slideout-modal .close-current-modal', e => {\n e.preventDefault();\n const currentModal = $(e.target).closest('.lp-slideout-modal');\n\n if (currentModal.length) {\n currentModal.modal('hide');\n }\n });\n }\n}","'use strict';\n\nvar processInclude = require('base/util');\nimport detail from './product/detail';\nimport notifyMe from './components/notifyMe';\n\ndocument.addEventListener('DOMContentLoaded', () => {\n processInclude(detail.selectSizeAttribute);\n processInclude(detail.afterAttributeSelect);\n processInclude(require('./product/quickView'));\n processInclude(notifyMe);\n});\n","'use strict';\n\nconst { queryFirst } = require('../domUtil');\nconst { sauce } = require('fitpredictor/product/secretsauce');\n\n/**\n * Updates the product view when a product attribute is selected or deselected or when changing quantity\n * @param {Array} variationAttributes - Array of product variation attributes\n * @param {jQuery} $productContainer - DOM element for current product\n */\nfunction updateSelectedSwatchProductName(variationAttributes, $productContainer) {\n if (Array.isArray(variationAttributes) && variationAttributes.length) {\n const colorVariationObject = variationAttributes.find(attribute => attribute.attributeId === 'color');\n\n if (colorVariationObject && Array.isArray(colorVariationObject.values) && colorVariationObject.values.length) {\n const selectedSwatchObject = colorVariationObject.values.find(eachValue => eachValue.selected);\n $productContainer.find('.selected-swatch-name').text(selectedSwatchObject ? selectedSwatchObject.displayValue : '');\n }\n }\n}\n\n/**\n * Function to initialize Fit predictor on quick view\n * @param {jQuery} containerEl - Quickview container element\n */\nfunction injectFitPredictor(containerEl) {\n if (!!document.getElementById('fitPredictorEnabled')) {\n sauce($('.product-detail.product-quickview', containerEl));\n }\n}\n\n/**\n * Initialize Afterpay in QuickViews\n */\nfunction injectAfterpay() {\n require('../afterpay')({\n anchors: '.product-quickview-detail',\n observerTargets: '.prices',\n priceTargets: ['.sales .price-value', '.list .price-value', '.sales .value'],\n renderMode: 'adjacent',\n renderTarget: '.prices',\n showExcluded: false\n });\n}\n\n/**\n * Function to sets href for full pdp link\n * @param {string} label - Label to set\n * @param {string} link - href value\n * @param {jQuery} containerEl - Parent DOM element\n */\nfunction updateFullProductLink(label, link, containerEl) {\n containerEl.find('.full-pdp-link').text(label).attr('href', link);\n}\n\n/**\n * Function to add long Description on quick view\n * @param {jQuery} description - Product Description getting DOM element\n * @param {jQuery} containerEl - Parent DOM element\n */\nfunction injectLongDescription(description, containerEl) {\n containerEl.find('.long-description').html(description.html());\n}\n\nexport default {\n updateSelectedSwatchProductName,\n injectAfterpay,\n injectFitPredictor,\n updateFullProductLink,\n injectLongDescription\n}\n","'use strict';\n\nconst { queryFirst, queryAll, addClass, hasClass, removeClass, matchesBreakpoint } = require('../domUtil');\n\nconst breakpoints = require('../breakpoints');\n\nconst { updatePLPTileHeight } = require('../product/helper');\n\nlet windowWidth = window.innerWidth;\nconst hideClass = 'hidden-filters';\nconst hideEle = 'd-none';\nconst hideBtn = queryFirst('.hide-filter-btn');\nconst hideFilterEle = queryFirst('.hide-filter');\nconst openFilterIcon = queryFirst('.open_filter_icon');\nconst closeFilterIcon = queryFirst('.close_filter_icon');\nconst refinementBar = queryFirst('.refinement-bar');\nconst searchContainerEl = queryFirst('.search-results-container');\nconst refinementsEl = queryFirst('.refinements');\nconst refinementBarTitleEl = queryFirst('h5 .title', refinementsEl);\nconst sortOrderBtn = queryFirst('.sort-order-menu-toggle');\nconst lastAccordionElement = queryFirst('.accordion-container:last-child', refinementsEl);\nconst firstAccordionElement = queryFirst('.accordion-container:first-child .title', refinementsEl);\nconst lastTitleBtnEl = queryFirst('.title', lastAccordionElement);\nlet lastSubBtnEls = queryAll('button:not([disabled]), input:not([disabled]), [href]:not(.d-md-none), [tabindex]:not([tabindex=\"-1\"])', lastAccordionElement);\nlet lastSubBtnEl;\nif ((lastSubBtnEls || []).length) {\n lastSubBtnEl = lastSubBtnEls[lastSubBtnEls.length - 1];\n}\n\nif (refinementBar && !hasClass(queryFirst('.no-filter-results'), 'd-none')) {\n refinementBar.style.setProperty('display', 'none', 'important');\n}\n\nconst filterPill = queryFirst('.toggle-grid .filter-value:first-child button');\nconst KEYCODE_TAB = 9;\nconst mql = window.matchMedia('(max-width: 767px)');\nconst firstAddToWishlistBtn = queryFirst('.product-tile-container .add-to-wish-list');\n\nconst toggleFilterDisplay = () => {\n if (windowWidth < breakpoints.md) {\n return;\n }\n\n if (searchContainerEl && hasClass(searchContainerEl, hideClass)) {\n removeClass(searchContainerEl, hideClass);\n addClass(closeFilterIcon, hideEle);\n removeClass(openFilterIcon, hideEle);\n hideBtn.textContent = 'Filter';\n hideBtn.setAttribute('aria-expanded', 'true');\n refinementBar.removeAttribute('tabindex');\n refinementBar.style.setProperty('display', 'flex', 'important');\n $(hideBtn).trigger('toggle.lp.filters', 'filter menu: show');\n if (!matchesBreakpoint('lg')) {\n setTimeout(() => {\n refinementBarTitleEl.focus();\n updatePLPTileHeight('Filter');\n }, 500);\n }\n return;\n }\n\n addClass(searchContainerEl, hideClass);\n addClass(openFilterIcon, hideEle);\n removeClass(closeFilterIcon, hideEle);\n if (hasClass(openFilterIcon, hideEle) && !hasClass(queryFirst('.no-filter-results'), 'd-none')) {\n refinementBar.style.setProperty('display', 'none', 'important');\n }\n hideBtn.textContent = 'Filter';\n hideBtn.setAttribute('aria-expanded', 'false');\n searchContainerEl.setAttribute('tabindex', '-1');\n $(hideBtn).trigger('toggle.lp.filters', 'filter menu: hide');\n if (!matchesBreakpoint('lg')) {\n setTimeout(() => {\n updatePLPTileHeight('Filter');\n }, 500);\n }\n hideBtn.focus();\n};\n\nif (window.location.search.includes('storeID')) {\n toggleFilterDisplay();\n const showFilterSortHeader = queryFirst('.show-filter-sort-header');\n const displayClass = 'd-md-flex';\n\n addClass(showFilterSortHeader, displayClass);\n removeClass(showFilterSortHeader, 'd-none');\n}\n\nconst handleSortOrderTab = e => {\n const lastElExpanded = lastTitleBtnEl.getAttribute('aria-expanded');\n const sortOrderExpanded = sortOrderBtn.getAttribute('aria-expanded');\n const isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB;\n if (!isTabPressed) {\n return;\n }\n\n if (e.shiftKey) {\n /* shift + tab */\n if (searchContainerEl && hasClass(searchContainerEl, hideClass)) {\n hideBtn.focus();\n } else if (lastElExpanded === 'false') {\n lastTitleBtnEl.focus();\n } else if (lastSubBtnEl) {\n lastSubBtnEl.focus();\n }\n e.preventDefault();\n } else if (sortOrderExpanded === 'true') {\n queryFirst('.sort-order-menu-option:first-child').focus();\n } else if (filterPill) {\n filterPill.focus();\n } else {\n const hiddenFilterPill = hasClass(queryFirst('.product-grid-container .filter-bar .row'), 'd-md-none');\n const filterPill = queryFirst('.product-grid-container .filter-value:first-child button');\n if (!hiddenFilterPill && filterPill) {\n filterPill.focus();\n } else if (firstAddToWishlistBtn) {\n firstAddToWishlistBtn.focus();\n }\n }\n e.preventDefault();\n};\n\nconst handleFilterTab = e => {\n const isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB;\n if (!isTabPressed) {\n return;\n }\n\n if (!e.shiftKey) {\n if (!(searchContainerEl && hasClass(searchContainerEl, hideClass))) {\n refinementBarTitleEl.focus();\n } else {\n sortOrderBtn.focus();\n }\n e.preventDefault();\n }\n};\n\nconst handleLastElTab = e => {\n const lastElExpanded = lastTitleBtnEl.getAttribute('aria-expanded');\n const isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB;\n if (!isTabPressed) {\n return;\n }\n\n if (lastElExpanded === 'false' && !e.shiftKey) {\n sortOrderBtn.focus();\n e.preventDefault();\n } else if (lastElExpanded === 'true' && !e.shiftKey) {\n queryFirst('ul li:first-child button', lastAccordionElement).focus();\n e.preventDefault();\n }\n};\n\nconst handleFirstElTab = e => {\n const isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB;\n if (!isTabPressed) {\n return;\n }\n if (e.shiftKey) {\n hideBtn.focus();\n e.preventDefault();\n }\n};\n\nconst handleLastSubBtnElTab = e => {\n if (e.target.closest('form[name=price-filter-form]')) {\n lastSubBtnEls = queryAll('button:not([disabled]), input:not([disabled]), [href]:not(.d-md-none), [tabindex]:not([tabindex=\"-1\"])', lastAccordionElement);\n lastSubBtnEl.removeEventListener('keydown', handleLastSubBtnElTab);\n if ((lastSubBtnEls || []).length) {\n lastSubBtnEl = lastSubBtnEls[lastSubBtnEls.length - 1];\n lastSubBtnEl.addEventListener('keydown', handleLastSubBtnElTab);\n }\n }\n const isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB;\n if (!isTabPressed) {\n return;\n }\n\n if (!e.shiftKey) {\n sortOrderBtn.focus();\n e.preventDefault();\n }\n};\n\nconst handleWishlistBtnTab = e => {\n const isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB;\n if (!isTabPressed) {\n return;\n }\n if (e.shiftKey) {\n sortOrderBtn.focus();\n e.preventDefault();\n }\n};\n\nconst handleFilterPillBtnTab = e => {\n const isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB;\n if (!isTabPressed) {\n return;\n }\n if (e.shiftKey) {\n sortOrderBtn.focus();\n e.preventDefault();\n }\n};\n\nconst mobileScrollToBottom = () => {\n if (lastAccordionElement) {\n const target = queryFirst('.title', lastAccordionElement).dataset.target;\n $(target).on('shown.bs.collapse', function () {\n queryFirst('.refinement-price').scrollIntoView({ behavior: 'smooth', block: 'start' });\n });\n }\n};\n\nconst windowTest = w => {\n if (w.matches) {\n mobileScrollToBottom();\n }\n};\n\nconst handleSlotsAppearance = () => {\n const categoryMarketingSlots = queryAll('.category-marketing-slot', searchContainerEl);\n if (categoryMarketingSlots) {\n categoryMarketingSlots.forEach(categoryMarketingSlot => {\n if (categoryMarketingSlot && categoryMarketingSlot.children.length === 0) {\n categoryMarketingSlot.remove();\n } else {\n removeClass(categoryMarketingSlot, hideEle);\n }\n });\n }\n};\n\nmodule.exports = () => {\n $('.carousel').carousel();\n $('body').on('search:updateProducts', function () {\n $('.carousel').carousel();\n });\n if (hideBtn && hideFilterEle) {\n hideFilterEle.addEventListener('click', toggleFilterDisplay);\n hideFilterEle.addEventListener('keydown', handleFilterTab);\n }\n if (sortOrderBtn) {\n sortOrderBtn.addEventListener('keydown', handleSortOrderTab);\n }\n if (lastTitleBtnEl) {\n lastTitleBtnEl.addEventListener('keydown', handleLastElTab);\n if (lastSubBtnEl) {\n lastSubBtnEl.addEventListener('keydown', handleLastSubBtnElTab);\n }\n }\n if (firstAccordionElement) {\n firstAccordionElement.addEventListener('keydown', handleFirstElTab);\n }\n if (firstAddToWishlistBtn) {\n firstAddToWishlistBtn.addEventListener('keydown', handleWishlistBtnTab);\n }\n if (filterPill) {\n filterPill.addEventListener('keydown', handleFilterPillBtnTab);\n }\n\n handleSlotsAppearance();\n\n $('body').on('search:updateProducts', function () {\n if (lastAccordionElement) {\n windowTest(mql);\n }\n\n handleSlotsAppearance();\n });\n\n if (lastAccordionElement) {\n windowTest(mql);\n }\n};\n","'use strict';\n\nconst { queryAll, queryFirst, addClass, removeClass, hasClass, matchesBreakpoint } = require('../domUtil');\nconst $body = $('body');\nconst { HIDDEN_CLASS } = require('../constants');\nimport { getNestedValue } from '../util';\n\nconst handleSwatchClickUpdates = () => {\n const selectedClass = 'selected';\n const badgeHideClass = 'hide';\n const badgeShowClass = 'show';\n $(document).on('click', '.clickable-swatch, .non-color-attribute', function (e) {\n e.preventDefault();\n const el = this;\n const productTileWrapper = el.closest('.product-tile-wrapper');\n const quickBuyContainer = el.closest('.quick-buy');\n const productTile = queryFirst('.product-tile', productTileWrapper);\n const imageIndicators = queryFirst('.carousel-indicators', productTileWrapper);\n const productTileId = queryFirst('.mobile-carousel', productTileWrapper);\n const elImgContainer = queryFirst('.carousel-inner', productTile);\n const elSwatchContainer = queryFirst('.color-swatches', productTile);\n const elLoyaltyProductBadgeContainer = queryFirst('.loyalty-product-tile-badge', productTile);\n const addToWishlistIconPlp = queryFirst('.add-to-wish-list-container', productTile);\n const loyaltyEarlyAccessLockPlp = queryFirst('.loyalty-early-access-lock-container', productTile);\n const isLoyaltyHeaderProfile = getNestedValue(window, 'johnnyWasUtils.profile') || {};\n const { isLoyaltyProgramMember, isLoyaltyEnabled } = isLoyaltyHeaderProfile;\n const elProductBadgeContainer = queryFirst('.product-tile-badge', productTile);\n const elProductBadgeTxt = queryFirst('.product-tile-badge-text', productTile);\n const elTileImgURL = queryFirst('.tile-img-link', productTile);\n const elProductName = queryFirst('.pdp-link .product-name a', productTile);\n const elProductMoreColors = queryAll('.swatches-more-colors', productTile);\n const sizeContainer = matchesBreakpoint('lg') ? queryFirst('div.quick-buy ul.size-container', productTileWrapper) : queryFirst('div.quick-buy-modal ul.size-container', productTileWrapper);\n const elFitSizeContainer = matchesBreakpoint('lg') ? queryFirst('div.quick-buy ul.non-color-container', productTileWrapper) : queryFirst('div.quick-buy-modal ul.non-color-container', productTileWrapper);\n\n addClass(elProductBadgeContainer, badgeHideClass);\n removeClass(elProductBadgeContainer, badgeShowClass);\n const data = el.dataset;\n const url = data.swatchurl || data.url;\n const spinner = $.spinner();\n\n if (quickBuyContainer) {\n $(quickBuyContainer).spinner().start();\n } else {\n spinner.start();\n }\n\n $.ajax({\n url: url,\n type: 'get',\n dataType: 'json',\n success: function (data) {\n // handle image update on swatch click\n const { category_id } = window.utag_data || {};\n let imageData = data.product.images.medium;\n const imageDataLength = imageData.length;\n let tileIndicatorTmp = '';\n let sliderTmp = '';\n $body.trigger('swatchClickEvent', el.closest('.product-tile'));\n if ($(el).hasClass('clickable-swatch')) {\n removeClass(queryAll('.clickable-swatch', elSwatchContainer), selectedClass);\n } else {\n removeClass(queryAll('.non-color-attribute', elFitSizeContainer), selectedClass);\n }\n addClass(el, selectedClass);\n\n const { merchAltImageParams } = data.product;\n if (merchAltImageParams) {\n for (let i = 0, n = merchAltImageParams.length; i < n; i++) {\n const params = merchAltImageParams[i].split(\",\");\n const [categoryId, swapIndex] = params;\n let adjustedSwapIndex = swapIndex - 1;\n if (category_id === categoryId && adjustedSwapIndex >= 0 && adjustedSwapIndex < imageDataLength) {\n //Add selected image to front of image queue, shift all others over\n imageData = imageData.splice(adjustedSwapIndex, 1).concat(imageData);\n }\n }\n }\n\n let lastImage = imageData.find(image => image.url.indexOf('catalog') > -1) || imageData[imageData.length - 1];\n\n imageData.forEach((el, i) => {\n sliderTmp += `\n
\n
\n
`;\n tileIndicatorTmp += `
\n `\n });\n\n // handle badging update on swatch click\n const { productBadge, product } = data;\n const { earlyAccess } = product;\n addClass(loyaltyEarlyAccessLockPlp, HIDDEN_CLASS);\n removeClass(addToWishlistIconPlp, HIDDEN_CLASS);\n addClass(elLoyaltyProductBadgeContainer, badgeHideClass);\n if (isLoyaltyEnabled && earlyAccess && earlyAccess.isEarlyAccessProduct) {\n if (!isLoyaltyProgramMember) {\n addClass(addToWishlistIconPlp, HIDDEN_CLASS);\n removeClass(loyaltyEarlyAccessLockPlp, HIDDEN_CLASS);\n } else {\n removeClass(addToWishlistIconPlp, HIDDEN_CLASS);\n addClass(loyaltyEarlyAccessLockPlp, HIDDEN_CLASS);\n }\n removeClass(elLoyaltyProductBadgeContainer, badgeHideClass);\n addClass(elProductBadgeContainer, badgeHideClass);\n removeClass(elProductBadgeContainer, badgeShowClass);\n } else if (productBadge && productBadge.badgeText.length) {\n removeClass(elProductBadgeContainer, badgeHideClass);\n elProductBadgeTxt.setAttribute('style', `color:${productBadge.badgeTextColor || 'inherit'}`);\n elProductBadgeTxt.textContent = productBadge.badgeText;\n } else {\n addClass(elProductBadgeContainer, badgeHideClass);\n removeClass(elProductBadgeContainer, badgeShowClass);\n }\n\n // handle img link update on swatch click\n const { tileImageUrl, id, quickViewURL, productDetailsUrl } = data.product;\n\n if (tileImageUrl && tileImageUrl.length) {\n elTileImgURL.href = tileImageUrl;\n }\n\n const productTile = el.closest('.product');\n productTile.dataset.pid = id;\n productTile.dataset.wishlistId = id;\n const wishlistButton = queryFirst('.add-to-wish-list', productTile);\n if (wishlistButton && hasClass(wishlistButton, 'added-to-wish-list')) {\n removeClass(wishlistButton, 'added-to-wish-list');\n const assistiveText = wishlistButton.getAttribute('data-assistive-text');\n wishlistButton.setAttribute('aria-label', assistiveText);\n }\n\n const quickviewButton = queryFirst('.quickview', productTile);\n if (quickviewButton && quickViewURL) {\n quickviewButton.dataset.href = quickViewURL;\n }\n\n const variationAttributes = data.product.variationAttributes.length ? data.product.variationAttributes : {};\n let li = '';\n let fitSizeLi = '';\n variationAttributes.forEach((variationAttr, i) => {\n if (variationAttr.attributeId === 'size') {\n const sizes = variationAttr.values ? variationAttr.values : {};\n sizeContainer.innerHTML = '';\n if (Object.keys(sizes).length) {\n let title = $('.quick-buy-notifyme .select-size-label').val().split(':');\n sizes.forEach((size, i) => {\n li += `\n
\n \n ${size.id}\n \n `;\n });\n sizeContainer.innerHTML = li;\n }\n } else if (variationAttr.attributeId === 'fitSize') {\n const fitSizes = variationAttr.filteredValues ? variationAttr.filteredValues : {};\n let selected = '';\n if (Object.keys(fitSizes).length) {\n const selectedIndex = fitSizes.findIndex(item => item.selected === true);\n fitSizes.forEach((fitSize, i) => {\n if (selectedIndex != -1) {\n selected = fitSizes[selectedIndex].id === fitSize.id;\n } else {\n selected = fitSizes[0].id === fitSize.id;\n }\n if ($(el).hasClass('clickable-swatch')) {\n if (selected && tileImageUrl.length) {\n elTileImgURL.href = tileImageUrl + '&dwvar_' + id + '_fitSize=' + fitSize.id;\n }\n if (selected && productDetailsUrl.length) {\n elProductName.href = productDetailsUrl + '&dwvar_' + id + '_fitSize=' + fitSize.id;\n }\n if (elFitSizeContainer) {\n elFitSizeContainer.innerHTML = '';\n }\n\n fitSizeLi += `\n
\n \n \n \n ${fitSize.displayValue}\n \n \n `;\n } else {\n if (selected && elProductName) {\n elProductName.href = product.selectedProductTileUrl || elProductName.href;\n elTileImgURL.href = elProductName.href;\n elProductMoreColors.forEach(moreLink => {\n moreLink.href = elProductName.href;\n });\n }\n let $attrValue = $(productTile).find('.quick-buy [data-attr=\"' + variationAttr.attributeId + '\"] [data-attr-value=\"' + fitSize.value + '\"]');\n let $swatchButton = $attrValue.parent();\n $swatchButton.attr('data-product-id', data.product.id);\n if (fitSize.url) {\n $swatchButton.attr('data-url', fitSize.url);\n }\n }\n });\n if ($(el).hasClass('clickable-swatch')) {\n if (elFitSizeContainer) {\n elFitSizeContainer.innerHTML = fitSizeLi;\n }\n spinner.stop();\n const fitSizeEle = $(productTile).find('ul.non-color-container li');\n let requestedFitSize = data.queryString.split('&').find(param => param.includes('fitSize'))?.split('=')[1];\n let fitSizeIncluded = fitSizes.find(fitSize => fitSize.id === requestedFitSize);\n if (fitSizeEle.length && !fitSizeIncluded) {\n $(fitSizeEle).first().find('button.non-color-attribute').trigger('click');\n }\n }\n if (fitSizes.length === 1) {\n $(productTile).find('ul.non-color-container li.fitsize-swatches').hide();\n }\n }\n }\n });\n if (elImgContainer) {\n elImgContainer.innerHTML = sliderTmp;\n imageIndicators.innerHTML = tileIndicatorTmp;\n }\n $body.trigger('swatchChangeEvent', el);\n if (queryAll('li', imageIndicators).length > 0) {\n removeClass(imageIndicators, 'invisible');\n } else {\n addClass(imageIndicators, 'invisible');\n }\n if (matchesBreakpoint('lg')) {\n const imageEl = queryFirst('.js-plp-image', elImgContainer)\n const originalSrc = imageEl.getAttribute('src');\n const hoverSrc = imageEl.dataset.hover || originalSrc;\n const originalAlt = imageEl.getAttribute('alt');\n const hoverAlt = imageEl.dataset.hoveralt || originalAlt;\n\n imageEl.addEventListener('mouseover', () => {\n imageEl.srcset = hoverSrc;\n imageEl.alt = hoverAlt;\n });\n\n imageEl.addEventListener('mouseout', () => {\n imageEl.srcset = originalSrc;\n imageEl.alt = originalAlt;\n });\n }\n spinner.stop();\n },\n error: function () {\n spinner.stop();\n }\n });\n });\n};\n\nexport default handleSwatchClickUpdates;\n","/* OOTB Code\nWe have overridden this file to trigger an event after show more ajax success to re-init lazy load and animate up */\n\n'use strict';\n\nconst baseSearch = require('base/search/search');\nconst { queryFirst, updateUrlQueryParam, addClass, removeClass, queryAll, scrollTo, hasClass, renderFragment, getCookieMap, matchesBreakpoint, throttle } = require('../domUtil');\nconst { appendToUrl, formatMessage, getJSON } = require('../util');\nconst { emptySwatchTemplate } = require('../templates');\nconst { updatePLPTileHeight } = require('../product/helper');\nconst { HIDDEN_CLASS, INVISIBLE_CLASS } = require('../constants');\nconst $window = $(window);\nconst $body = $('body');\nconst $container = $('.container');\nconst $searchResultsContainer = $('.search-results.container');\nconst $refinementBar = $('.refinement-bar');\nconst $modalBG = $('.modal-background');\nconst REFINEMENTS_CONTAINER_SELECTOR = '.refinements-container';\nconst { lp_hsc_enabled: akamaiEnabled, lp_hsc_category: plpCaching, lp_cache_hash: lpCacheHash, lp_group_hash: lpGroupHash } = getCookieMap();\nconst isAkamaiEnabled = (akamaiEnabled === 'true' && plpCaching && lpCacheHash && lpGroupHash);\nconst akamaiSettings = (queryFirst('#akamai-settings') || { dataset: {} }).dataset;\nlet cacheSyncTimer;\nconst plpHeader = queryFirst('.clp-results-header');\nconst mainHeader = queryFirst('.main-header');\n/**\n * Function that updates action url after every ajax call\n * @param {string} actionUrl action url\n */\nfunction updateRefinementsAjaxUrl(actionUrl) {\n const refinementsContainer = queryFirst(REFINEMENTS_CONTAINER_SELECTOR);\n if (!refinementsContainer) return;\n\n refinementsContainer.dataset.actionUrl = actionUrl;\n}\n\n/**\n * Append Store filter params to action Url\n * @param {HTMLElement} storeToggleEl the element which triggered the filter\n * @param {string} actionUrl action url\n * @returns {string} updated action url\n */\nfunction appendStoreFilterQueryParams(storeToggleEl, actionUrl) {\n // If event is triggered on storeToggle Checkbox, then proceed with url updation\n if (hasClass(storeToggleEl, 'store-filter-toggle')) {\n const STORE_ID_PARAM = 'storeID';\n const { storeId } = storeToggleEl.dataset;\n\n // Updating relative URL query params using URL api\n const url = new URL(location.origin + actionUrl);\n const { searchParams } = url;\n if (storeToggleEl.checked) {\n searchParams.set(STORE_ID_PARAM, storeId);\n } else {\n searchParams.delete(STORE_ID_PARAM);\n }\n url.search = searchParams.toString();\n\n // url.pathname -> \"/on/demandware.store/Sites-lillypulitzer-sfra-Site/default/Search-ShowAjax\"\n // url.search -> \"?cgid=dresses-1-all&prefn1=refinementCategoryDresses&prefv1=Shift%7cA-Line%2fEasy%7cStraight\"\n return url.pathname + url.search;\n }\n return actionUrl;\n}\n\n/**\n * Update sort option URLs from Ajax response\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @return {string} - Selected sort.\n */\nfunction updateSortOptions(fragment) {\n const toggleEl = queryFirst('.sort-order-menu-toggle span');\n const gridFooter = queryFirst('.grid-footer', fragment);\n\n if (gridFooter && toggleEl) {\n const dataSortLabel = gridFooter.dataset.sortLabel;\n toggleEl.textContent = dataSortLabel;\n\n const { options: sortOptions, ruleId: selectedRule } = JSON.parse(gridFooter.dataset.sortOptions);\n\n sortOptions.forEach(function (option) {\n const $sortOption = $('.sort-order-menu-dropdown button[data-id=\"' + option.id + '\"], button[data-id=\"' + option.id + '\"].sort-order-menu-option');\n $sortOption.val(option.url);\n if (option.id === selectedRule) {\n $sortOption.addClass('selected');\n $sortOption.attr('aria-selected', 'true');\n toggleEl.textContent = option.displayName;\n } else {\n $sortOption.removeClass('selected');\n $sortOption.attr('aria-selected', 'false');\n }\n });\n }\n return toggleEl ? toggleEl.textContent : '';\n}\n\n/**\n * Update DOM elements with Ajax results\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @param {string} selector - DOM element to look up in the $results\n * @return {undefined}\n */\nfunction updateDom(fragment, selector) {\n const containers = queryAll(selector);\n const updates = queryFirst(selector, fragment);\n\n if (containers.length && updates) {\n containers.forEach(container => {\n const clone = updates.cloneNode(true);\n\n container.parentElement.replaceChild(clone, container);\n });\n }\n}\n\n/**\n * Keep refinement panes expanded/collapsed after Ajax refresh\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @return {undefined}\n */\nfunction handleRefinements(fragment) {\n $('.refinement.active').each(function () {\n $(this).removeClass('active');\n var activeDiv = queryFirst('.' + $(this)[0].className.replace(/ /g, '.'), fragment);\n addClass(activeDiv, 'active');\n queryFirst('button.title', activeDiv).setAttribute('aria-expanded', 'true');\n });\n\n updateDom(fragment, '.refinements');\n}\n\n/**\n * Parse Ajax results and updated select DOM elements\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n */\nfunction parseResults(fragment) {\n var specialHandlers = {\n '.refinements': handleRefinements\n };\n\n // Update DOM elements that do not require special handling\n ['.grid-header', '.header-bar', '.header.page-title', '.product-grid', '.show-more', '.filter-bar'].forEach(function (selector) {\n updateDom(fragment, selector);\n });\n\n Object.keys(specialHandlers).forEach(function (selector) {\n specialHandlers[selector](fragment);\n });\n}\n\n/**\n * Update search results count\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @return {number} Returns the total number of search results\n */\nfunction updateCount(fragment) {\n const productCount = queryFirst('.current-product-count', fragment);\n const resultCounts = queryAll('.result-count');\n\n if (!productCount) {\n const noFilterResults = queryFirst('.no-filter-results', fragment);\n\n if (noFilterResults) {\n resultCounts.forEach(item => item.textContent = noFilterResults.dataset.noproductcount);\n }\n } else {\n resultCounts.forEach(item => item.textContent = productCount.value);\n }\n\n const container = queryFirst('.no-filter-results');\n\n if (container) {\n const numOfProducts = parseInt(resultCounts[0].innerText.replace(/\\D/g, ''), 10);\n\n if (numOfProducts > 0) {\n addClass(container, HIDDEN_CLASS);\n } else {\n removeClass(container, HIDDEN_CLASS);\n }\n }\n\n return parseInt((resultCounts[0].innerText.split(' result ')[0] || '0').replace(/\\D/g, ''), 10);\n}\n\n/**\n * Count the number of filters applied\n * @param {Element} element - The element containing the filter count\n * @returns {string} A display string of the filter count\n */\nfunction refinementFilterCount(element) {\n if (!element) return '';\n\n let filterText = element.innerText;\n let filterAppliedCount = element.dataset.filterCount;\n const storeFilterToggle = queryFirst('.store-filter-toggle');\n const isStoreFilterApplied = storeFilterToggle && storeFilterToggle.checked;\n\n if (isStoreFilterApplied) {\n filterAppliedCount = parseInt(filterAppliedCount, 10) + 1;\n filterText = `${element.dataset.filterLabel} (${filterAppliedCount})`;\n }\n\n return filterText;\n}\n\n/**\n * Update filter count\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @return {undefined}\n */\nfunction updateFilterCount(fragment) {\n const filterCount = queryFirst('.selected-filter-count', fragment);\n const productCount = queryFirst('.no-filter-results', fragment);\n const selectedFilterCount = queryFirst('.selected-filter-count');\n const showFilterSortHeader = queryFirst('.show-filter-sort-header');\n const correctFilterCount = filterCount || selectedFilterCount;\n const displayClass = 'd-md-flex';\n\n if (selectedFilterCount) {\n selectedFilterCount.textContent = refinementFilterCount(correctFilterCount);\n }\n\n // This will show/hide desktop filter and sorting fillter in desktop if product count is zero\n if (!productCount || productCount.dataset.productcount !== '0') {\n addClass(showFilterSortHeader, displayClass);\n } else {\n removeClass(showFilterSortHeader, displayClass);\n }\n}\n\n/**\n * Update show no results message\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @return {undefined}\n */\nfunction showNoResultsText(fragment) {\n const noFilterResults = queryFirst('.no-filter-results', fragment);\n if (noFilterResults) {\n const numOfProducts = parseInt(noFilterResults.dataset.productcount, 10);\n if (numOfProducts > 0 && !noFilterResults.classList.contains(HIDDEN_CLASS)) {\n noFilterResults.classList.add(HIDDEN_CLASS);\n } else {\n noFilterResults.classList.remove(HIDDEN_CLASS);\n }\n const container = queryFirst('.no-filter-results');\n if (container) container.parentElement.replaceChild(noFilterResults, container);\n }\n}\n\n\n/**\n * Update Section based off the selector passed\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @param {String} selector - Element selector\n * @return {undefined}\n */\nfunction updateDOMElement(fragment, selector) {\n const elementToUpdate = queryFirst(selector, fragment);\n if (elementToUpdate) {\n const container = queryFirst(selector);\n if (container) container.parentElement.replaceChild(elementToUpdate, container);\n }\n}\n/**\n * Update Page Title, Description and Canonical URL with color filter\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @return {undefined}\n */\nconst updatePageTitle = fragment => {\n const pageTitle = queryFirst('.seo-page-title', fragment);\n const pageDescription = queryFirst('.seo-page-description');\n const canonicalUrl = queryFirst('.canonical-url');\n\n if (pageTitle) document.title = pageTitle.value;\n\n if (pageDescription) {\n const metaTag = queryFirst('meta[name=\"description\"]');\n\n if (metaTag) metaTag.setAttribute('content', pageDescription.value);\n }\n\n if (canonicalUrl) {\n const canonLink = queryFirst('link[rel=\"canonical\"]');\n\n if (canonLink) canonLink.setAttribute('href', canonicalUrl.value);\n }\n};\n\n/**\n * Update plp filters swatch images\n *\n * @param {DocumentFragment} fragment - A DocumentFragment object\n * @return {undefined}\n */\nfunction updatePatternImageSwatch(fragment) {\n const refinementPatterns = queryFirst('#refinement-print-and-solid', fragment);\n\n if (!refinementPatterns) return;\n\n const imgItems = queryAll('.refinement-image', refinementPatterns);\n\n imgItems.forEach(imageEl => {\n const { src, srcset } = imageEl.dataset;\n\n imageEl.src = src;\n\n if (srcset) imageEl.srcset = srcset;\n\n removeClass(imageEl, INVISIBLE_CLASS);\n imageEl.onload = () => addClass(imageEl, 'image-loaded');\n });\n\n const container = queryFirst('#refinement-print-and-solid');\n\n if (container) container.parentElement.replaceChild(refinementPatterns, container);\n}\n\n/**\n * Updates PLP products with out of stock text where applicable.\n * @param {Object} staleProductIds - A plain object of variation group IDs / inStock status\n */\nfunction updateProducts(staleProductIds) {\n if (!staleProductIds || Object.keys(staleProductIds).length === 0) return;\n\n const productGrid = queryFirst('.product-grid');\n const currentProductIds = queryAll('.product', productGrid).map(node => node.dataset.pid).filter(Boolean);\n\n if (currentProductIds.length === 0) return;\n\n const oosProducts = Object.keys(staleProductIds).filter(productId => !staleProductIds[productId]);\n const { outOfStockMessage = '' } = productGrid.dataset;\n const oosClass = 'out-of-stock';\n\n oosProducts.forEach(productId => {\n const node = queryFirst(`.product[data-pid=\"${productId}\"]`, productGrid);\n if (!node || node.classList.contains(oosClass)) return;\n\n const numSwatches = queryAll('.color-swatches button', node).length;\n // If there are multiple swatches, we don't know whether those are OOS too.\n if (numSwatches > 1) return;\n\n node.classList.add(oosClass);\n\n // If there's just 1 swatch, mark it as Sold Out.\n const swatches = queryFirst('.color-swatches .swatches', node);\n if (swatches) swatches.innerHTML = formatMessage(emptySwatchTemplate, outOfStockMessage);\n });\n}\n\n/**\n *\n * @param {Object} element dom element\n * @param {string} actionUrl action url\n */\nfunction getResultsOnPriceFilter(element, actionUrl) {\n const prevActionUrl = actionUrl;\n const updatedActionUrl = appendStoreFilterQueryParams(element, actionUrl);\n const akamaiActionUrl = isAkamaiEnabled ? appendToUrl(updatedActionUrl, {\n 'lp-cache-hash': lpCacheHash,\n 'lp-group-hash': lpGroupHash\n }) : updatedActionUrl;\n const gridFooter = queryFirst('.grid-footer');\n const pageNumber = (gridFooter && gridFooter.dataset.pageNumber) || 0;\n\n $.ajax({\n url: akamaiActionUrl,\n data: {\n page: pageNumber,\n selectedUrl: akamaiActionUrl\n },\n success: function (response, status, xhr) {\n const serverTiming = xhr.getResponseHeader('server-timing') || '';\n const isCached = !!(serverTiming && serverTiming.split('desc=')[1].split(',')[0] === 'HIT');\n\n if (hasClass(element, 'clear-filters-btn') && ($('.no-filter-results').attr('data-productcount') === '0' || !akamaiActionUrl.includes('storeID'))) {\n $('.store-filter-toggle').prop('checked', false);\n }\n updateRefinementsAjaxUrl(prevActionUrl);\n\n const fragment = renderFragment(response);\n\n updateUrlQueryParam(fragment);\n parseResults(fragment);\n updateSortOptions(fragment);\n updatePageTitle(fragment);\n showNoResultsText(fragment);\n if (hasClass(element, 'cat-ref') || hasClass(element, 'cat-filter')) {\n updateDOMElement(fragment, '.category-breadcrumb');\n updateDOMElement(fragment, '.search-banner');\n updateDOMElement(fragment, '.cat-result-count');\n }\n // update SEO Section (it depends on selected filters)\n updateDOMElement(fragment, '.category-seo-copy');\n\n const productCount = updateCount(fragment);\n\n updateFilterCount(fragment);\n updatePatternImageSwatch(fragment);\n\n const container = queryFirst('.no-filter-results');\n if (container) {\n if ($('.no-filter-results').attr('data-productcount') !== '0') {\n addClass(container, HIDDEN_CLASS);\n } else {\n removeClass(container, HIDDEN_CLASS);\n }\n }\n $body.trigger('search:updateProducts', element); // LP custom changes end\n\n if (!matchesBreakpoint('lg')) {\n updatePLPTileHeight();\n }\n // Check Akamai cache\n if (isCached) {\n const cacheKey = encodeURIComponent(xhr.getResponseHeader('x-cache-key'));\n const productIds = queryAll('.product-grid .product').map(node => `${node.dataset.pid}:${!queryFirst('.swatches-empty', node)}`).filter(Boolean).join(',');\n const syncUrl = akamaiActionUrl.replace('ShowAjax', 'SyncShowAjax');\n\n clearTimeout(cacheSyncTimer);\n\n cacheSyncTimer = setTimeout(() => {\n getJSON(syncUrl, 'POST', { productCount, cacheKey, productIds }, data => {\n if (data.stale) {\n // Update products with fresh stock status if we can\n updateProducts(data.staleProductIds);\n\n if (data.cacheInvalidated) {\n // Akamai takes about 5 seconds to clear an entry\n // Once that's complete, we should rebuild the cache with a fresh request\n setTimeout(() => {\n $.ajax({\n url: akamaiActionUrl,\n data: {\n page: pageNumber,\n selectedUrl: akamaiActionUrl\n }\n });\n }, akamaiSettings.cacheRefreshDelay);\n }\n }\n });\n }, akamaiSettings.cacheSyncDelay);\n }\n\n $.spinner().stop();\n scrollTo(plpHeader && mainHeader ? plpHeader.offsetTop - mainHeader.offsetHeight : 0);\n // Attaching the hover event in new DOM loaded\n imageAndQuickbuyHoverHandler();\n if ($('.infinite-scroll-enabled').length > 0) {\n initialiseSearchIntersection();\n }\n },\n error: function () {\n $.spinner().stop();\n }\n });\n}\n\n/**\n *\n * @param {string} showMoreUrl URL used to fetch new products\n * @param {Object} e Event causing this update\n * @param {boolean} isPagination Boolean true if this is a pagination-based update; false if \"Show More\"\n * @param {boolean} isBackButton true if loading because of a back button click; false otherwise. Avoids pushing duplicate history entries.\n */\nfunction loadProducts(showMoreUrl, e, isPagination, observerObj = {}, isBackButton = false) {\n $.spinner().start();\n $body.trigger('search:showMore', e);\n\n if (isPagination) { // scrolling to top before the new products are added to the page allows the lazy loader to be more effective\n scrollTo(plpHeader && mainHeader ? plpHeader.offsetTop - mainHeader.offsetHeight : 0);\n }\n\n const akamaiActionUrl = isAkamaiEnabled ? appendToUrl(showMoreUrl, {\n 'lp-cache-hash': lpCacheHash,\n 'lp-group-hash': lpGroupHash\n }) : showMoreUrl;\n\n $.ajax({\n url: akamaiActionUrl,\n data: { selectedUrl: akamaiActionUrl },\n success: (response, status, xhr) => {\n const serverTiming = xhr.getResponseHeader('server-timing') || '';\n const isCached = !!(serverTiming && serverTiming.split('desc=')[1].split(',')[0] === 'HIT');\n\n if (isPagination) {\n $('.product-grid').html(response);\n } else {\n $('.grid-footer').replaceWith(response);\n }\n\n const fragment = renderFragment(response);\n\n updateSortOptions(fragment);\n // LP custom changes start\n if (!isBackButton) {\n // Pagination: don't update querystring on back button click -- otherwise user gets stuck after the fist time they click back due to a new history entry being pushed\n updateUrlQueryParam(fragment);\n }\n\n const productCount = updateCount(fragment);\n\n $body.trigger('search:updateProducts');\n if (!matchesBreakpoint('lg')) {\n updatePLPTileHeight();\n }\n\n // Check Akamai cache\n if (isCached) {\n const cacheKey = encodeURIComponent(xhr.getResponseHeader('x-cache-key'));\n const gridFooter = queryFirst('.grid-footer', fragment);\n const pageSize = (gridFooter && parseInt(gridFooter.dataset.pageSize)) || 48;\n const productIds = queryAll('.product-grid .product').slice(-pageSize).map(node => `${node.dataset.pid}:${!queryFirst('.swatches-empty', node)}`).filter(Boolean).join(',');\n const syncUrl = akamaiActionUrl.replace('UpdateGrid', 'SyncUpdateGrid');\n\n clearTimeout(cacheSyncTimer);\n\n cacheSyncTimer = setTimeout(() => {\n getJSON(syncUrl, 'POST', { productCount, cacheKey, productIds }, data => {\n if (data.stale) {\n // Update products with fresh stock status if we can\n updateProducts(data.staleProductIds);\n\n if (data.cacheInvalidated) {\n // Once that's complete, we should rebuild the cache with a fresh request\n setTimeout(() => {\n $.ajax({\n url: akamaiActionUrl,\n data: {\n selectedUrl: akamaiActionUrl\n }\n });\n }, akamaiSettings.cacheRefreshDelay);\n }\n }\n });\n }, akamaiSettings.cacheSyncDelay);\n }\n\n // LP custom changes end\n $.spinner().stop();\n\n // Attaching the hover event in new DOM loaded\n imageAndQuickbuyHoverHandler();\n // intersection observer changes\n if (observerObj && observerObj.target) {\n observerObj.observer.unobserve(observerObj.target);\n initialiseSearchIntersection();\n }\n },\n error: function () {\n $.spinner().stop();\n }\n });\n}\n\n/**\n * Function to apply store filter on PLP page\n * @param {HTMLElement} checkboxToggleEl Store filter toggle checkbox element\n * @param {boolean} appendStoreID Flag to append storeID to URL params\n */\nfunction applyStoreFilter(checkboxToggleEl) {\n const refinementsContainer = queryFirst(REFINEMENTS_CONTAINER_SELECTOR);\n if (!refinementsContainer) return;\n\n const { actionUrl } = refinementsContainer.dataset;\n\n // Perform Filter\n $.spinner().start();\n getResultsOnPriceFilter(checkboxToggleEl, actionUrl);\n}\n\n/**\n * Update The filter count if storefilter is applied on load\n */\n$(function () {\n const selectedFilterCountEl = queryFirst('.selected-filter-count');\n const noResultsRecommendationPage = queryFirst('.no-results-recommendations');\n const noFilterResults = queryFirst('.no-filter-results');\n const refinementPrice = queryFirst('.refinement-price');\n\n if (refinementPrice) {\n const minPrice = queryFirst('.price-filter-min', refinementPrice)?.value;\n const maxPrice = queryFirst('.price-filter-max', refinementPrice)?.value;\n\n if ((minPrice || maxPrice) && noResultsRecommendationPage) {\n addClass(noResultsRecommendationPage, HIDDEN_CLASS);\n }\n }\n if (selectedFilterCountEl) {\n const refinementFilterText = refinementFilterCount(selectedFilterCountEl);\n selectedFilterCountEl.textContent = refinementFilterText;\n }\n\n // On page reload or category change, if products are available\n // hide the clear filter (no results section)\n\n if (noFilterResults) {\n const numOfProducts = noFilterResults.dataset.productcount;\n if (numOfProducts > 0) {\n addClass(noFilterResults, HIDDEN_CLASS);\n } else {\n removeClass(noFilterResults, HIDDEN_CLASS);\n }\n }\n});\n\n\n$(document).ready(function () {\n if ($('.infinite-scroll-enabled').length > 0) {\n initialiseSearchIntersection();\n }\n // Attaching the hover event in new DOM loaded\n imageAndQuickbuyHoverHandler();\n});\n\nwindow.onload = () => {\n if (!matchesBreakpoint('lg')) {\n updatePLPTileHeight();\n }\n};\n\n/**\n * Method to initialise the intersection observer\n *\n */\nfunction initialiseSearchIntersection() {\n const backToTopButtonEL = queryFirst('.back-to-top-icon');\n var observerTarget = document.querySelector('.show-more.lazy-load-target');\n var options = {\n threshold: 1\n };\n\n /**\n * Represents a callback function which will be called when the observed target element enters the viewport\n * @param {Array} entries IntersectionObserverEntry Objects\n */\n function handleIntersect(entries) {\n entries.forEach(function (entry) {\n if (entry.isIntersecting) {\n var targetURL = $('.show-more button').data('url');\n if (!targetURL) return;\n var pagination = '';\n var infiniteScrollEvent = new Event('infiniteScrollEvent');\n var observerObj = {\n observer: observer,\n target: observerTarget\n };\n loadProducts(targetURL, infiniteScrollEvent, !!pagination, observerObj);\n observer.unobserve(observerTarget);\n\n if (hasClass(backToTopButtonEL, HIDDEN_CLASS)) {\n removeClass(backToTopButtonEL, HIDDEN_CLASS);\n }\n } else {\n return;\n }\n });\n }\n var observer = new IntersectionObserver(handleIntersect, options);\n if (observerTarget) {\n observer.observe(observerTarget);\n }\n}\n\n/**\n * Method to add the image change on hover and open quickbuy size option on hover\n *\n */\nconst imageAndQuickbuyHoverHandler = () => {\n if (matchesBreakpoint('lg')) {\n $('.product-grid-container .image-container').hover(function (e) {\n }, function (e) {\n var fitSelect = (e.target.closest('.non-color-list'))\n if (!hasClass(e.target, 'fitSize-value') && !fitSelect) {\n $(this).find('.quickbuy-btn').css('opacity', '');\n $(this).find('.quick-buy').addClass('d-none');\n }\n });\n }\n $(\".product-grid-container .image-container .quickbuy-btn\").hover(function () {\n $(this).css('opacity', '0');\n $(this).parent().find('.quick-buy').removeClass('d-none');\n });\n};\nbaseSearch.showMore = function () {\n const productGrid = queryFirst('.product-grid');\n const pagination = queryFirst('.pagination', productGrid);\n // Show more, traditional, and new pagination link event to load new products\n $container.on('click', '.show-more button, .product-grid .pagination a', function (e) {\n e.stopPropagation();\n e.preventDefault();\n\n const { url } = this.dataset;\n\n if (!url) return;\n\n loadProducts(url, e, !!pagination);\n });\n\n if (pagination) {\n const { getNestedValue } = require('../util');\n\n if (hasClass(pagination, 'new-pagination')) {\n $container.on('change', '.pagination-pages', e => {\n e.stopPropagation();\n loadProducts(getNestedValue(e, 'target.selectedOptions[0].dataset.url'), e, true);\n });\n }\n\n window.addEventListener('popstate', e => {\n const baseUrlElem = queryFirst('.ajax-base-url');\n const baseUrlWithParams = baseUrlElem && baseUrlElem.value;\n const baseUrl = baseUrlWithParams && new URL(baseUrlWithParams);\n const baseParams = baseUrl && new URLSearchParams(baseUrl.search);\n const qsParams = getNestedValue(e, 'state.path');\n\n if (qsParams) {\n const newParams = new URLSearchParams(qsParams.split('?')[1]);\n newParams.forEach((value, key) => {\n baseParams.set(key, value);\n });\n }\n\n const finalUrl = baseUrl.origin + baseUrl.pathname + '?' + baseParams.toString();\n loadProducts(finalUrl, e, true, true);\n });\n }\n};\n\nbaseSearch.applyFilter = function () {\n function onRefinement(e) {\n const target = e.currentTarget || this;\n let isSelected = hasClass(target, 'selected');\n let isCatfilter = hasClass(target, 'cat-ref');\n if (isSelected && isCatfilter) {\n return;\n }\n\n if (hasClass(target, 'store-filter-pill')) {\n $('.store-filter-toggle').prop('checked', false);\n }\n const { dataset } = target;\n\n e.preventDefault();\n e.stopPropagation();\n\n $.spinner().start();\n $(target).trigger('search:filter', e);\n const actionUrl = dataset.href || dataset.actionUrl;\n getResultsOnPriceFilter(target, actionUrl);\n }\n\n // Handle refinement value selection and reset click\n $container.on('click', '.refinements li button, .refinement-bar button.reset, .filter-value button, .swatch-filter button', onRefinement);\n\n $container.on('submit', '.price-filter-form', function (e) {\n e.preventDefault();\n e.stopPropagation();\n\n $.spinner().start();\n $(this).trigger('search:filter', e);\n const { target } = e;\n const applyButton = queryFirst('.price-apply-button', target);\n const actionUrl = $(applyButton).attr('data-href');\n getResultsOnPriceFilter(applyButton, actionUrl);\n });\n\n // Prevent checkbox/toggle change is store id attribute is not present\n $container.on('click', '.store-filter-toggle', (event) => {\n if (!event.target.dataset.storeId) {\n event.preventDefault();\n }\n });\n\n // Toggle checkbox change event\n $container.on('change', '.store-filter-toggle', (event) => {\n applyStoreFilter(event.target);\n });\n\n // Selecting a store from the drawer\n $searchResultsContainer.on('filter:updateStoreId', (_e, data) => {\n // Updating new storeId on DOM\n const storeFilterToggleEl = queryFirst('.store-filter-toggle');\n const { storeId, storeName, storeCity, storeStateCode } = data;\n\n if (storeId) {\n // Updating toggle data attrs and state\n storeFilterToggleEl.dataset.storeId = storeId;\n storeFilterToggleEl.dataset.storeName = storeName;\n storeFilterToggleEl.disabled = false;\n storeFilterToggleEl.checked = true;\n\n // Updating Change store link\n const buttonLabel = `${storeName || ''} - ${storeCity || ''}, ${storeStateCode}`;\n const storeSelectorEl = queryFirst('.btn-in-store-pickup');\n if (storeSelectorEl) {\n storeSelectorEl.textContent = buttonLabel;\n }\n\n // Apply a store filter\n applyStoreFilter(storeFilterToggleEl);\n }\n });\n // Allow store filter to be seen / clicked now that the event handler is in place\n /** @type {HTMLInputElement} */\n const storeFilterToggle = queryFirst('.store-filter .switch');\n /** @type {HTMLInputElement} */\n const storeToggleCTA = queryFirst('.store-filter-toggle');\n if (storeFilterToggle) {\n storeToggleCTA.disabled = false;\n removeClass(storeFilterToggle, INVISIBLE_CLASS);\n }\n};\n\nbaseSearch.updatePrice = function () {\n $container.on('click', '.refinement-price .values button', () => {\n addClass(queryFirst('.values button', queryFirst('.refinement-price')), 'is-not-custom');\n });\n $container.on('focus', '.refinement-price input', () => {\n removeClass(queryFirst('.price-filter', queryFirst('.refinement-price')), 'is-not-custom');\n });\n // prevent negative value\n $container.on('keydown', '.refinement-price .price-filter-min, .refinement-price .price-filter-max', e => {\n if (!((e.keyCode > 95 && e.keyCode < 106) || (e.keyCode > 47 && e.keyCode < 58) || e.keyCode == 8 || e.keyCode == 9 || e.keyCode == 38 || e.keyCode == 40 || e.keyCode == 13)) {\n return false;\n }\n });\n\n $container.on('keyup', '.refinement-price .price-filter-min, .refinement-price .price-filter-max', e => {\n const refinementPrice = queryFirst('.refinement-price');\n const minPrice = queryFirst('.price-filter-min', refinementPrice).value;\n const maxPrice = queryFirst('.price-filter-max', refinementPrice).value;\n const applyButton = queryFirst('.price-apply-button', refinementPrice);\n removeClass(queryAll('.values button', refinementPrice), 'selected');\n if (minPrice) {\n queryFirst('.price-filter-max', refinementPrice).min = parseInt(minPrice) + 1; // setting min value for max input\n }\n\n // Enable or disable apply button based min and max filter value\n if (minPrice && maxPrice && parseInt(minPrice) < parseInt(maxPrice)) {\n applyButton.disabled = false;\n } else {\n applyButton.disabled = true;\n }\n });\n\n $container.on('change', '.refinement-price .price-filter-min, .refinement-price .price-filter-max', e => {\n const refinementPrice = queryFirst('.refinement-price');\n const minPrice = queryFirst('.price-filter-min', refinementPrice).value;\n const maxPrice = queryFirst('.price-filter-max', refinementPrice).value;\n const applyButton = queryFirst('.price-apply-button', refinementPrice);\n const uri = applyButton.dataset.href;\n\n let newUrl = '';\n\n if (minPrice && maxPrice) {\n const updateQueryStringParameter = (key, value) => {\n const re = new RegExp('([?&])' + key + '=.*?(&|$)', 'i');\n const separator = uri.indexOf('?') !== -1 ? '&' : '?';\n if (uri.match(re)) {\n newUrl = newUrl ? newUrl.replace(re, '$1' + key + '=' + value + '$2') : uri.replace(re, '$1' + key + '=' + value + '$2');\n } else {\n newUrl = newUrl ? newUrl + separator + key + '=' + value : uri + separator + key + '=' + value;\n }\n };\n\n updateQueryStringParameter('pmin', parseInt(minPrice, 10));\n updateQueryStringParameter('pmax', parseInt(maxPrice, 10));\n applyButton.dataset.href = newUrl;\n }\n });\n};\n\n/**\n * Show the filter refinements UI\n */\nfunction showRefinements() {\n $refinementBar.show();\n $modalBG.show();\n $refinementBar.siblings().attr('aria-hidden', true);\n $refinementBar.closest('.row').siblings().attr('aria-hidden', true);\n $refinementBar.closest('.tab-pane.active').siblings().attr('aria-hidden', true);\n $refinementBar.closest('.container.search-results').siblings().attr('aria-hidden', true);\n $refinementBar.find('.close').trigger('focus');\n}\n\n/**\n * Hide the filter refinements UI\n */\nfunction hideRefinements() {\n $refinementBar.hide();\n $modalBG.hide();\n $refinementBar.siblings().attr('aria-hidden', false);\n $refinementBar.closest('.row').siblings().attr('aria-hidden', false);\n $refinementBar.closest('.tab-pane.active').siblings().attr('aria-hidden', false);\n $refinementBar.closest('.container.search-results').siblings().attr('aria-hidden', false);\n}\n\nbaseSearch.filter = function () {\n // Display refinements bar when Menu icon clicked\n $container.on('click', 'button.filter-results', function () {\n showRefinements();\n\n // LP custom changes start\n $body.addClass('modal-open');\n // LP custom changes end\n });\n};\n\nbaseSearch.closeRefinements = function () {\n // Refinements close button\n $container.on('click', '.refinement-bar button.close, .modal-background', function () {\n hideRefinements();\n\n const filterResults = queryFirst('.filter-results');\n\n if (filterResults) filterResults.focus();\n\n // LP custom changes start\n $body.removeClass('modal-open');\n // LP custom changes end\n });\n};\n\nbaseSearch.resize = function () {\n const { documentElement } = document;\n const { clientWidth } = documentElement;\n // Close refinement bar and hide modal background if user resizes browser\n $window.on('resize', throttle(() => {\n // Check if the window width has actually changed and it's not just iOS triggering a resize event on scroll\n if (documentElement.clientWidth !== clientWidth) {\n if (window.matchMedia('(min-width: 768px)').matches) {\n hideRefinements();\n\n // LP custom changes start\n $body.removeClass('modal-open');\n // LP custom changes end\n }\n if (!matchesBreakpoint('lg')) {\n setTimeout(() => {\n updatePLPTileHeight('filter');\n }, 200);\n } else {\n let cards = $('.tile-img-link');\n cards.height('100%');\n }\n }\n }, 100));\n};\n\nbaseSearch.sortHandler = function () {\n $body.on('search:sortOptions', function (e, data) {\n const { response } = data;\n const fragment = renderFragment(response);\n\n updateUrlQueryParam(fragment);\n parseResults(fragment);\n const sortText = updateSortOptions(fragment);\n showNoResultsText(fragment);\n updateCount(fragment);\n updateFilterCount(fragment);\n updatePatternImageSwatch(fragment);\n // Attaching the hover event in new DOM loaded\n imageAndQuickbuyHoverHandler();\n if ($('.infinite-scroll-enabled').length > 0) {\n initialiseSearchIntersection();\n }\n $body.trigger('search:updateProducts', { sortText: sortText.toLowerCase() });\n });\n};\n\n/**\n * Sometimes when user back to PLP with infinite scroll,\n * safari for some reason lost scroll position.\n * This is dirty hack to fix for this. We store last interacted tile\n * in url and then force browser to scroll to it.\n */\nbaseSearch.focusTileOnBackButton = function () {\n const productGridContainer = queryFirst('.product-grid-container');\n let activeTileId = '';\n\n function hasParentTile(el) {\n let tile = null;\n\n while ((el = el.parentNode) && el !== document) {\n if (el.id && el.id.startsWith('product-tile-')) {\n tile = el;\n break;\n }\n }\n\n return tile;\n }\n\n function tileInteractionHandler(event) {\n const tile = hasParentTile(event.target);\n if (tile !== null) {\n activeTileId = tile.getAttribute('id');\n }\n }\n\n function unloadHandler() {\n if (activeTileId === '') { return; }\n\n const url = new URL(window.location.href);\n url.hash = activeTileId;\n window.history.replaceState(window.location.href, '', url);\n }\n\n if (productGridContainer) {\n productGridContainer.addEventListener('click', tileInteractionHandler);\n }\n\n window.addEventListener('pagehide', unloadHandler);\n\n function scrollToProductTile() {\n const url = new URL(window.location.href);\n if (!url.hash.startsWith('#product-tile')) return;\n\n const target = queryFirst(url.hash);\n if (!target) return;\n\n target.focus();\n target.scrollIntoView();\n }\n\n scrollToProductTile();\n}\n\nmodule.exports = baseSearch;\n","'use strict';\nconst handleOptionBtnClick = e => {\n e.stopPropagation();\n const { currentTarget } = e;\n const { value } = currentTarget;\n const spinner = $.spinner();\n\n // ajax code is taken from SFRA search/search.js in sort\n spinner.start();\n $(this).trigger('search:sort', value);\n $.ajax({\n url: value,\n data: {\n selectedUrl: value\n },\n method: 'GET',\n success: function (response) {\n $('body').trigger('search:sortOptions', { response: response });\n spinner.stop();\n },\n error: function () {\n spinner.stop();\n }\n });\n};\n\nmodule.exports = () => {\n $('.sort-order-dropdown, .sort-order-menu').on('click', '.sort-order-menu-option', handleOptionBtnClick);\n};\n","/**\n * HTML Templates for use in client-side rendering.\n *\n * @module dom.templates\n * @version 1.0.0\n */\n\n'use strict';\n\n/**\n * QuickView Templates\n */\nexports.quickView = {\n container: '
',\n quickViewModal: `\n
\n `\n};\n\n/**\n * Get All Wishlist Collection Templates\n */\nexports.addToWishlist = {\n container: '
',\n addToWishlistModal: `\n
\n
\n\n `\n};\n\n/**\n * Cart error message template\n */\nexports.cart = {\n errorMessage: '
{0}
',\n cartAvailabilityMessageOOS: (message, url) => (`\n
${message}\n Browse Similar Styles
\n \n `),\n};\n\n/**\n * Cart & Checkout promo template\n */\nexports.promo = {\n shippingMethod: `\n
\n
\n
\n {0}:{1} \n
\n
\n {3} \n
\n
\n
\n
`,\n checkoutNormalShipping: '
{0} ',\n checkoutDiscountShipping: `\n
{0}\n
{1} \n `\n};\n\n/**\n * Checkout template\n */\nexports.checkout = {\n discountPrice: '
{0}{1} '\n};\n\n/**\n * Selected swatch name template\n */\nexports.swatchNameTemplate = {\n swatchNameHtml: '
Color: {0}
'\n};\n\nexports.emptySwatchTemplate = '
{0} ';\n\n/*\n * Address Suggestions template\n */\nexports.addressSuggestions = {\n suggestionTextTemplate: '
',\n suggestionsTemplate: `\n
`\n};\n\n/*\n * Approaching Discounts template\n */\nexports.approachingDiscounts = {\n discountContainerTemplate: '
',\n singleDiscountTemplate: '
{0} ',\n multipleDiscountsTemplate: `\n
\n \n `,\n nonCouponBasedAdjustmentTemplate: `
\n
\n
{0}\n {2} \n
\n
\n {1} \n
\n
\n
`\n};\n\n/**\n * Video Template\n * @param {Object} options video setting values\n * @return {html} video html template\n */\nexports.videoTemplate = (options = {}) => {\n // Note: I don't believe this template is used anywhere anymore\n const { loop = '', videoUrl = '', imgUrl = '', classNames = '', autoplay = false, muted = true, controls = false, icontitle = '', icondesc = '' } = options;\n\n return `\n
\n \n \n \n \n \n ${icontitle} \n ${icondesc} \n \n \n \n
\n `;\n};\n\n/**\n * Image Template\n * @param {string} imgUrl value\n * @param {string} altText value\n * @param {string} classNames value\n * @return {html} video html template\n */\nexports.imageTemplate = (imgUrl, altText, classNames) => {\n return `\n
\n
\n
\n `;\n};\n\n/**\n * Video Thumbnail Template on PDP\n * @param {string} carouselId value\n * @param {string} imgs value\n * @param {string} videoUrl value\n * @param {string} pId value\n * @return {html} list item html template\n */\nexports.videoThumbnailTemplate = (carouselId, imgs, videoUrl, pId) => {\n return `\n
\n \n \n \n Play \n \n \n \n \n `;\n};\n\n/**\n * Size option template\n * @param {string} url - Size variant url\n * @param {string} value - Size value\n * @return {html} size option html template\n */\nexports.sizeOptionTemplate = (url, value) => {\n return `
${value} `;\n};\n\n/**\n * Function to rerender size button element\n * @param {Object} variantData - variant details\n * @param {string} ariaLabel - aria label\n * @param {string} ariaDescribedby - aria described by\n * @param {string} selectedText - selected text\n * @param {string} oosMessage - out of the stock text\n * @return {html} size button html template\n */\nexports.sizeButtonTemplate = (variantData, ariaLabel, ariaDescribedby, selectedText, oosMessage) => {\n const { selected, forceOutOfStock, inStock, value, url, sizeSwatchNotAvailable } = variantData;\n return `
\n ${value} \n ${selected ? selectedText : ''} ${!inStock || forceOutOfStock ? oosMessage : ''} \n `;\n};\n\n/**\n * Function to render empty wishlist markup for guest user\n * @param {string} emptyWishlistMessage - empty wishlist message\n * @return {html} wishlist html template\n */\nexports.guestEmptyWishlistTemplate = (emptyWishlistMessage, emptyWishlistContentAssetBody) => {\n return `
\n
\n
${emptyWishlistMessage}
\n ${emptyWishlistContentAssetBody}\n
\n
`;\n};\n\n/**\n * Function to render empty wishlist markup for guest user\n * @param {string} emptySFLMessage - empty SFL message\n * @param {string} continueShopURL - continue shopping URL\n * @param {string} continueShopMsg - continue shopping message\n * @param {string} signInMsg - sign In message\n * @param {string} signInSFLURL - sign in URL\n * @return {html} SFL html template\n */\nexports.emptySFL = (emptySFLMessage, continueShopURL, continueShopMsg, signInMsg, signInSFLURL) => {\n return `
\n
`;\n};\n\n/**\n * GWP Site Templates\n */\nexports.gwpSizeTemplate = {\n singleSize: '
{0} ',\n multiSize: `\n
\n \n \n {1}\n \n
\n `,\n multiDefaultSizeOption: '
{1} ',\n multiSizeOption: '
{3} '\n};\n\n/**\n * Address autocomplete templates\n */\nexports.autoComplete = {\n suggestionLink: (suggestion, addressLine, secondaryEntryAddressLine) => (`\n
1}\"\n data-secondary-entry-search-value=\"${secondaryEntryAddressLine}\"\n >${addressLine} \n `),\n suggestionContainer: containerClass => (`
`)\n};\n\nexports.contactUsTemplate = {\n signupMessage: (status, msg) => (`\n
\n ${msg}\n
\n `)\n};\n\nexports.browserWarningTemplate = `\n We're sorry, this browser is no longer supported.
\n Please update your browser for a smoother, more secure shopping experience. We recommend downloading the latest version of\n
Google Chrome ,\n
Microsoft Edge or\n
Mozilla Firefox .\n`;\n\n/*\n * Shipping preference radio buttons\n */\nexports.shippingPreferenceTemplates = {\n shippingPreferences: (ispuRadioLabel, ispuRadioValue, shipToRadioLabel, shipToRadioValue, changeStoreLabel, preferISPU = false) => (`\n
\n
\n `),\n storeDetail: (storeId, name, address1, city, stateCode, postalCode) => (`\n
\n
${name}
\n
\n
${address1}, \n ${city}, ${stateCode} ${postalCode} \n
\n
\n
\n `)\n};\n\n/*\n * Product detail page - messaging templates\n */\nexports.productDetail = {\n selectStyleMessageTmpl: message => `
${message}
`,\n availabilityMessageTmpl: message => `
${message}
`,\n restrictedMessageTmpl: message => `
${message}
`,\n availabilityMessageOOS: (message, url) => (`\n
${message}\n Browse Similar Styles
\n \n `),\n availabilityMessagePreorder: (message, url) => (`\n
\n \n `),\n ispuSelectStyleMessageTmpl: message => `
${message}
`,\n ispuAvailabilityMessageTmpl: message => `
${message}
`,\n ispuLowStockMessageTmpl: message => `
${message}
`\n};\n\nexports.dialogTemplate = options => {\n const {\n buttons = [{ text: 'OK', primary: true, link: '' }],\n className = '',\n modalContentHeading = '',\n modalContentBody = '',\n id = 'dialog-' + Date.now(),\n slideOut = false\n } = options;\n\n const buttonSpace = Math.floor(12 / buttons.length);\n\n return `\n
\n
\n
\n
\n ${slideOut && modalContentHeading ? `
${modalContentHeading} ` : ''}\n \n \n Close dialog \n Cross mark icon to close this dialog \n \n \n \n \n ${!slideOut && modalContentHeading ? `
${modalContentHeading}
` : ''}\n
${modalContentBody}
\n
\n ${buttons.map(button => `\n
`).join('')\n }\n
\n
\n
\n
\n `;\n};\n\nexports.errorTextTemplate = errorMessage => `
`;\n\nexports.oneTrust = {\n privacyDialogCookieBanner: `\n
\n
\n You can opt out of 3rd party cookies by clicking Cookie Preferences .\n
\n
\n `\n};\nexports.loyalty = {\n carouselBadge: '
{0}
'\n};\n","const { addClass, hasClass, queryFirst } = require('./domUtil');\n\n/**\n * Tokenize strings\n *\n * @param {string | Object} string Resource message that need to be tokenized\n * @param {string | Object} values Values that need to be replaced.\n * @param {string | Object} leftToken Left token type with default as {{\n * @param {string | Object} rightToken Right token type with defaulat as }}\n * @return {string} Updated string.\n */\nexports.tokenize = (string, values, leftToken = '{{', rightToken = '}}') => {\n if (typeof values !== 'object') return string;\n const operators = /([{}+.\\-!?[\\]])/g;\n return string.replace(new RegExp(leftToken.replace(operators, '\\\\$1') + '[\\\\r\\\\n\\\\s\\\\t]*([\\\\s\\\\S]+?)[\\\\r\\\\n\\\\s\\\\t]*' + rightToken.replace(operators, '\\\\$1'), 'igm'), (_, code) => {\n return values[code] || '';\n });\n};\n\n/**\n * Transforms all text to a kebab-case string.\n * @param {string} text - The text to transform\n * @returns {string} - The transformed string value\n * @example toKebabCase('.suggestions-related-products', ['.product-tile', '.link']) // suggestions-related-products-product-tile-link\n */\nconst toKebabCase = exports.toKebabCase = (...values) => values.map(value => {\n if (!Array.isArray(value)) value = [value];\n return value.map(text => typeof text === 'undefined' ? '' : String(text).toLowerCase().replace(/\\W/g, '-').trim()).join('-');\n}).join('-').replace(/-+/g, '-').replace(/^-+|-+$/g, '');\n\n/**\n * Transforms any input into a hash value.\n * @param {*} input - The input to transform\n * @returns {string} - The transformed string hash value\n * @example hashValue(function(a){ return a++; }) // 66756e6374696f6e2861297b2072657475726e20612b2b3b207d\n */\nexports.hashValue = input => {\n let value = JSON.stringify(String(input));\n\n if (value === '\"[object Object]\"') {\n // Sort the object first so hashes match despite key order\n value = JSON.stringify(Object.keys(input).sort().reduce((result, key) => {\n result[key] = input[key];\n return result;\n }, {}));\n }\n\n if (value.startsWith('\"') && value.endsWith('\"')) {\n value = value.substr(1, value.length - 2);\n }\n\n return value.split(\"\").map(digit => digit.charCodeAt(0).toString(16)).join('');\n};\n\n/**\n * Transforms all text to a valid dataset key.\n * @param {string} text - The text to transform\n * @returns {string} - The transformed string value\n * @example toDatasetKey('.suggestions-related-products', ['.product-tile', '.link']) // suggestionsRelatedProductsProductTileLink\n */\nexports.toDatasetKey = (...values) => toKebabCase(...values).split('-').map((text, index) => index === 0 ? text : text.charAt(0).toUpperCase() + text.substr(1)).join('');\n\n/**\n * Format dynamic resource messages.\n *\n * @param {string | Object} string Resource message that need to be tokenized\n * @param {string | Object} tokens Tokens that need to be replaced.\n * @return {string} Updated string.\n */\nexports.formatMessage = (string, ...tokens) => {\n return this.tokenize(\n string,\n tokens.reduce((result, item, index) => {\n result[index] = item;\n return result;\n }, {}),\n '{',\n '}'\n );\n};\n\n/**\n * Safely gets nested object properties. Returns the value if found, undefined if not found.\n * @param {*} obj The parent object in which the property exists\n * @param {*} keyString String denoting where in the parent object your target property should exist\n * @param {...any} replaceValues Values in the keyString to replace -- reference in the keyString with a number encapsulated in {} (e.g. {0}, {1}, etc)\n * @return {Object} returns nested object properties\n */\nexports.getNestedValue = function (obj, keyString, ...replaceValues) {\n const keys = keyString.split(/\\[|\\]|\\./).filter(el => el !== '');\n\n return keys.reduce((o, i) => (o || {})[/\\{\\d+\\}/.test(i) ? replaceValues[i.split(/\\{|\\}/)[1]] : i], obj);\n};\n\n/**\n * Ensures an event handler is only bound to an element once\n * @param {HTMLElement} element The element to bind the event to\n * @param {string} eventType The type of event\n * @param {function} handler The handler to execute when the event occurs, or the immediate callback if not defined\n * @param {string} initFlag The name of the flag to use for init\n */\nexports.initOnce = (element, eventType = '', handler, initFlag = '') => {\n const flag = 'init' + initFlag + eventType.toLowerCase();\n\n if (!element || element.dataset[flag]) return;\n\n element.dataset[flag] = true;\n if (eventType) {\n element.addEventListener(eventType, handler);\n } else {\n handler();\n }\n};\n\n/**\n * appends params to a url\n * @param {string} url - Original url\n * @param {Object} params - Parameters to append\n * @returns {string} result url with appended parameters\n */\nexports.appendToUrl = (url, params) => {\n let newUrl = url;\n newUrl +=\n (newUrl.indexOf('?') !== -1 ? '&' : '?') +\n Object.keys(params)\n .map(key => key + '=' + encodeURIComponent(params[key]))\n .join('&');\n\n return newUrl;\n};\n\n/**\n * This method performs an ajax call\n * @param {string} url endpoint url\n * @param {string} type ajax method type\n * @param {Object} data data for an ajax call\n * @param {function} onSuccess success call back function\n * @param {function} onError error call back function\n * @return {function} returns ajax function\n */\nexports.getJSON = (url, type, data = {}, onSuccess = function () { }, onError = function () { }) => {\n return $.ajax({\n url,\n type,\n dataType: 'json',\n data,\n success: onSuccess,\n error: onError\n });\n};\n\n/**\n * This method renders geo location\n * @param {function} successCallback Success callback function\n * @param {Object} mixin additional parameters\n * @param {function} errorCallback Error callback function\n */\nexports.geolocate = (successCallback, mixin = {}, errorCallback) => {\n if (!navigator.geolocation) return;\n const data = Object.assign({}, mixin);\n const successHandler = response => {\n const { coords } = response;\n if (coords) {\n const { latitude, longitude } = coords;\n data.latitude = latitude;\n data.longitude = longitude;\n }\n\n if (successCallback) {\n successCallback(data);\n }\n };\n const errorHandler = error => {\n if (errorCallback) {\n errorCallback(data);\n }\n };\n navigator.geolocation.getCurrentPosition(successHandler, errorHandler);\n};\n\n/**\n * This method stores data in key-value pair into browser's localStorage\n * @param {string} key Identifier to be stored\n * @param {string | Object} value Value to be stored\n */\nexports.setItemInLocalStorage = function (key, value) {\n if (!window.localStorage || !key) {\n return;\n }\n\n localStorage.setItem(key, JSON.stringify(value));\n};\n\n/**\n * This method stores data into browser's localStorage\n * @param {string} key Identifier for retrieving the value\n * @return {string | Object | boolean} returns parsed value\n */\nexports.getItemFromLocalStorage = function (key) {\n if (!window.localStorage || !key) {\n return false;\n }\n\n const value = localStorage.getItem(key);\n\n if (!value) {\n return false;\n }\n\n return JSON.parse(value);\n};\n\n/**\n * This method removes data from browser's localStorage\n * @param {string} key Identifier\n */\nexports.removeItemFromLocalStorage = function (key) {\n if (!window.localStorage || !key) {\n return;\n }\n\n localStorage.removeItem(key);\n};\n\n/**\n * This method formats phone number\n * @param {HTMLElement} element - current element for which formatting should be one\n */\nexports.formatPhoneNumber = function (element) {\n const Cleave = require('cleave.js').default;\n if (element) {\n let selector = '#' + element.id;\n setTimeout(() => {\n var cleave = new Cleave(selector, {\n delimiters: ['(', ') ', '-'],\n blocks: [0, 3, 3, 9],\n numericOnly: true\n });\n\n $(element).data('cleave', cleave);\n }, 0);\n }\n}\n\n/**\n * @function\n * @desc Determines if the device that is being used is mobile\n * @returns {Boolean}\n */\nexports.isMobile = function () {\n const mobileAgentHash = ['mobile', 'tablet', 'phone', 'ipad', 'ipod', 'android', 'blackberry', 'windows ce', 'opera mini', 'palm'];\n let idx = 0;\n let isMobile = false;\n const userAgent = navigator.userAgent.toLowerCase();\n\n while (mobileAgentHash[idx] && !isMobile) {\n isMobile = userAgent.indexOf(mobileAgentHash[idx]) >= 0;\n idx++;\n }\n return isMobile;\n};\n\n/**\n * @function\n * @desc Fixes position sticky scrolling behavior for elements with greater height than widnow height. Ensures content is scrollable above the fold\n * @param {Array} items - items to set scroll height position\n * @param {Boolean} isTopOnly - Whether stick to top side only\n * @param {Number} topOffset - additional top space\n */\nexports.stickyScrollPosition = (items, isTopOnly, topOffset = 0) => {\n const $window = $(window);\n const handleStickyPositionOnScroll = item => {\n let ticking = false;\n const detailStickyScroll = () => {\n ticking = false;\n const itemHeight = item.getBoundingClientRect().height;\n const windowHeight = window.innerHeight;\n const headerHeight = $('.main-header').outerHeight();\n const newTop = itemHeight - windowHeight + headerHeight;\n\n if (!isTopOnly && itemHeight > windowHeight - headerHeight) {\n item.style.setProperty('--top', `${-newTop}px`);\n } else {\n item.style.setProperty('--top', `${headerHeight + topOffset}px`);\n }\n };\n const requestTick = () => {\n if (!ticking) {\n requestAnimationFrame(detailStickyScroll);\n }\n ticking = true;\n };\n const onScroll = () => {\n requestTick(item);\n };\n $window.scroll(onScroll);\n };\n\n items.forEach(item => {\n handleStickyPositionOnScroll(item);\n });\n};\n\n/**\n * Determines whether the user is browsing with an old/unsupported browser.\n * @returns {boolean} True if the browser is old/unsupported.\n */\nexports.isUnsupportedBrowser = () => {\n const { userAgent } = navigator;\n const sitePrefs = document.getElementById('site-prefs');\n\n if (!sitePrefs) return false;\n\n let unsupportedBrowserTypes;\n\n if (sitePrefs.dataset) {\n ({ unsupportedBrowserTypes } = sitePrefs.dataset);\n } else {\n // For old IE\n unsupportedBrowserTypes = sitePrefs.getAttribute('data-unsupported-browser-types');\n }\n\n return JSON.parse(unsupportedBrowserTypes).some(function (uaFragment) {\n return ~userAgent.indexOf(uaFragment);\n });\n};\n\n/**\n * Get remaining time object for given time string \n * @param {string} endtime - remaining time string comes as parameter\n * @return {Object} remainTimeObject - Date Object with day, hours, minutes, Sec\n */\nexports.getTimeRemaining = (endtime) => {\n const total = Date.parse(endtime) - Date.now();\n const seconds = Math.floor((total / 1000) % 60).toString();\n const minutes = Math.floor((total / 1000 / 60) % 60).toString();\n const hours = Math.floor((total / (1000 * 60 * 60)) % 24).toString();\n const days = Math.floor(total / (1000 * 60 * 60 * 24));\n\n return {\n total,\n days,\n hours,\n minutes,\n seconds\n };\n};\n\n\n/**\n * Converts the range to Absolute, according to the Rounding Rules configured on Global-e side.\n * @param {number} price - Price\n * @param {Object} range - Range\n * @returns {Object} - result Absolute\n */\nfunction convertRangeToAbsolute(price, range) {\n let result;\n let intPart;\n let base;\n if (range.RangeBehavior === 1) {\n // range already has absolute behavior\n result = range;\n } else {\n result = {};\n result.RangeBehavior = range.RangeBehavior;\n result.RoundingExceptions = [];\n result.From = range.From;\n result.To = range.To;\n\n intPart = Math.floor(price);\n\n if (range.RangeBehavior === 2) {\n // Relative Decimal\n result.LowerTarget = intPart - 1;\n result.LowerTarget += range.LowerTarget;\n result.UpperTarget = intPart + range.UpperTarget;\n result.Threshold = intPart + range.Threshold;\n for (let i = 0; i < range.RoundingExceptions.length; i++) {\n let ex = range.RoundingExceptions[i];\n ex.ExceptionValue += intPart;\n result.RoundingExceptions.push(ex);\n }\n } else if (range.RangeBehavior === 3) {\n // Relative Whole\n if (range.TargetBehaviorHelperValue === 0) {\n range.TargetBehaviorHelperValue = 10; // eslint-disable-line no-param-reassign\n }\n base = Math.floor(price / range.TargetBehaviorHelperValue) * range.TargetBehaviorHelperValue;\n result.LowerTarget = (base - range.TargetBehaviorHelperValue) + range.LowerTarget;\n result.UpperTarget = base + range.UpperTarget;\n result.Threshold = base + range.Threshold;\n for (let i = 0; i < range.RoundingExceptions.length; i++) {\n let ex = range.RoundingExceptions[i];\n ex.ExceptionValue += base;\n result.RoundingExceptions.push(ex);\n }\n } else if (range.RangeBehavior === 4) {\n // Nearest target\n if (range.TargetBehaviorHelperValue === 0) {\n range.TargetBehaviorHelperValue = 5; // eslint-disable-line no-param-reassign\n }\n base = Math.floor(price / range.TargetBehaviorHelperValue) * range.TargetBehaviorHelperValue;\n result.LowerTarget = (base - 1) + range.LowerTarget;\n result.UpperTarget = ((base - 1) + range.TargetBehaviorHelperValue) + range.UpperTarget;\n result.Threshold = base + range.Threshold;\n for (let i = 0; i < range.RoundingExceptions.length; i++) {\n let ex = range.RoundingExceptions[i];\n ex.ExceptionValue += base;\n result.RoundingExceptions.push(ex);\n }\n }\n }\n return (result || null);\n}\n\n/**\n * Rounds the given price, according to the Rounding Rules configured on Global-e side\n * @param {number} price - Price\n * @param {Object} range - Range\n * @returns {number} - Absolute\n */\nfunction absoluteRounding(price, range) {\n let result = null;\n // check exceptions\n if (range.RoundingExceptions.length > 0) {\n for (let i = 0; i < range.RoundingExceptions.length; i++) {\n let ex = range.RoundingExceptions[i];\n if (price === ex.ExceptionValue) {\n result = price;\n }\n }\n }\n // no exception was found\n if (!result) {\n // check threshold\n if (price < range.Threshold) {\n result = range.LowerTarget;\n } else {\n result = range.UpperTarget;\n }\n }\n return result;\n}\n\n/**\n * Calculate and returns currecy price for Stylitics widget\n * @param {string} gePrice - price\n * @param {Object} roundingRanges - globale rouding rules json\n * @return {string} - Rounded price\n */\nfunction roundPrice(gePrice, roundingRanges) {\n let range = null;\n let price = gePrice;\n for (let i = 0; i < roundingRanges.length; i++) {\n let rg = roundingRanges[i];\n if (rg.From < price && price <= rg.To) {\n range = rg;\n break;\n }\n }\n if (range) {\n range = convertRangeToAbsolute(price, range);\n price = absoluteRounding(price, range); // eslint-disable-line no-param-reassign\n }\n if (price < 0) {\n price = 0; // eslint-disable-line no-param-reassign\n }\n return price;\n}\n\n/**\n * Calculate and returns currecy price for Stylitics widget\n * @param {string} price - list price\n * @param {string} salesPrice - sales price\n * @return {Object} - localized price object with list and sales price\n */\nexports.globaleCalculation = (price, salesPrice) => {\n const countryCurrency = window.currencySymbol;\n if (price.innerText.indexOf(countryCurrency) === -1) {\n let salesPriceText;\n let geSalesPrice;\n\n let priceText = price.innerText.replace('$', '');\n let gePrice = priceText;\n\n if (salesPrice) {\n salesPriceText = salesPrice.innerText.replace('$', '');\n geSalesPrice = salesPriceText;\n }\n\n const countryCoefficientIncludeVAT = window.countryCoefficientIncludeVAT;\n const countryVATRate = parseFloat(window.countryVATRate);\n const merchantTaxRate = parseFloat(window.merchantTaxRate);\n const currenyRate = parseFloat(window.currenyRate);\n const coefficientRate = parseFloat(window.coefficientRate);\n\n if (['2', '4', '6'].indexOf(countryCoefficientIncludeVAT) !== -1) {\n gePrice += gePrice * countryVATRate;\n if (geSalesPrice) {\n geSalesPrice += (geSalesPrice * countryVATRate);\n }\n } else if (['0', '8'].indexOf(countryCoefficientIncludeVAT) !== -1\n || (parseInt(countryCoefficientIncludeVAT) === 6 && window.useCountryVAT)) {\n gePrice /= (1 + (merchantTaxRate / 100));\n geSalesPrice /= (1 + (merchantTaxRate / 100));\n if (parseInt(countryCoefficientIncludeVAT) === 6) {\n gePrice += gePrice * countryVATRate;\n if (geSalesPrice) {\n geSalesPrice += geSalesPrice * countryVATRate;\n }\n }\n }\n\n gePrice = gePrice * currenyRate * coefficientRate;\n geSalesPrice = geSalesPrice ? geSalesPrice * currenyRate * coefficientRate : null;\n\n const globaleRoundingRanges = JSON.parse(JSON.stringify(window.roundingRanges));\n if (globaleRoundingRanges) {\n const roundingRanges = JSON.parse(globaleRoundingRanges);\n gePrice = roundPrice(gePrice, roundingRanges);\n geSalesPrice = geSalesPrice ? roundPrice(geSalesPrice, roundingRanges) : '';\n }\n\n return {\n gePrice: countryCurrency + ' ' + gePrice,\n geSalesPrice: countryCurrency + ' ' + geSalesPrice\n };\n }\n return {\n gePrice: price.innerText,\n geSalesPrice: salesPrice ? salesPrice.innerText : ''\n };\n};\n","'use strict';\n\nvar scrollAnimate = require('../components/scrollAnimate');\n\n/**\n * Display error messages and highlight form fields with errors.\n * @param {string} parentSelector - the form which contains the fields\n * @param {Object} fieldErrors - the fields with errors\n */\nfunction loadFormErrors(parentSelector, fieldErrors) { // eslint-disable-line\n // Display error messages and highlight form fields with errors.\n $.each(fieldErrors, function (attr) {\n $('*[name=' + attr + ']', parentSelector)\n .addClass('is-invalid')\n .siblings('.invalid-feedback')\n .html(fieldErrors[attr]);\n });\n // Animate to top of form that has errors\n scrollAnimate($(parentSelector));\n}\n\n/**\n * Clear the form errors.\n * @param {string} parentSelector - the parent form selector.\n */\nfunction clearPreviousErrors(parentSelector) {\n $(parentSelector).find('.form-control.is-invalid').removeClass('is-invalid');\n $('.error-message').hide();\n}\n\nmodule.exports = {\n loadFormErrors: loadFormErrors,\n clearPreviousErrors: clearPreviousErrors\n};\n","'use strict';\n\nmodule.exports = function (element, message) {\n var errorHtml = '
' +\n '' +\n '× ' +\n ' ' + message + '
';\n\n $(element).append(errorHtml);\n};\n","'use strict';\n\nmodule.exports = {\n setTabNextFocus: function (focusParams) {\n var KEYCODE_TAB = 9;\n var isTabPressed = (focusParams.event.key === 'Tab' || focusParams.event.keyCode === KEYCODE_TAB);\n\n if (!isTabPressed) {\n return;\n }\n\n var firstFocusableEl = $(focusParams.containerSelector + ' ' + focusParams.firstElementSelector);\n var lastFocusableEl = $(focusParams.containerSelector + ' ' + focusParams.lastElementSelector);\n\n if ($(focusParams.containerSelector + ' ' + focusParams.lastElementSelector).is(':disabled')) {\n lastFocusableEl = $(focusParams.containerSelector + ' ' + focusParams.nextToLastElementSelector);\n if ($('.product-quickview.product-set').length > 0) {\n var linkElements = $(focusParams.containerSelector + ' a#fa-link.share-icons');\n lastFocusableEl = linkElements[linkElements.length - 1];\n }\n }\n\n if (focusParams.event.shiftKey) /* shift + tab */ {\n if ($(':focus').is(firstFocusableEl)) {\n lastFocusableEl.focus();\n focusParams.event.preventDefault();\n }\n } else /* tab */ {\n if ($(':focus').is(lastFocusableEl)) { // eslint-disable-line\n firstFocusableEl.focus();\n focusParams.event.preventDefault();\n }\n }\n }\n};\n","'use strict';\n\n/**\n * Remove all validation. Should be called every time before revalidating form\n * @param {element} form - Form to be cleared\n * @returns {void}\n */\nfunction clearFormErrors(form) {\n $(form).find('.form-control.is-invalid').removeClass('is-invalid');\n}\n\nmodule.exports = function (formElement, payload) {\n // clear form validation first\n clearFormErrors(formElement);\n $('.alert', formElement).remove();\n\n if (typeof payload === 'object' && payload.fields) {\n Object.keys(payload.fields).forEach(function (key) {\n if (payload.fields[key]) {\n var feedbackElement = $(formElement).find('[name=\"' + key + '\"]')\n .parent()\n .children('.invalid-feedback');\n\n if (feedbackElement.length > 0) {\n if (Array.isArray(payload[key])) {\n feedbackElement.html(payload.fields[key].join('
'));\n } else {\n feedbackElement.html(payload.fields[key]);\n }\n feedbackElement.siblings('.form-control').addClass('is-invalid');\n }\n }\n });\n }\n if (payload && payload.error) {\n var form = $(formElement).prop('tagName') === 'FORM'\n ? $(formElement)\n : $(formElement).parents('form');\n\n form.prepend('
'\n + payload.error.join(' ') + '
');\n }\n};\n","'use strict';\n\nmodule.exports = function (element) {\n var position = element && element.length ? element.offset().top : 0;\n $('html, body').animate({\n scrollTop: position\n }, 500);\n if (!element) {\n $('.logo-home').focus();\n }\n};\n","'use strict';\n\nvar formValidation = require('../components/formValidation');\nvar createErrorNotification = require('../components/errorNotification');\n\nmodule.exports = {\n login: function () {\n $('form.login').submit(function (e) {\n var form = $(this);\n e.preventDefault();\n var url = form.attr('action');\n form.spinner().start();\n $('form.login').trigger('login:submit', e);\n $.ajax({\n url: url,\n type: 'post',\n dataType: 'json',\n data: form.serialize(),\n success: function (data) {\n form.spinner().stop();\n if (!data.success) {\n formValidation(form, data);\n $('form.login').trigger('login:error', data);\n } else {\n $('form.login').trigger('login:success', data);\n location.href = data.redirectUrl;\n }\n },\n error: function (data) {\n if (data.responseJSON.redirectUrl) {\n window.location.href = data.responseJSON.redirectUrl;\n } else {\n $('form.login').trigger('login:error', data);\n form.spinner().stop();\n }\n }\n });\n return false;\n });\n },\n\n register: function () {\n $('form.registration').submit(function (e) {\n var form = $(this);\n e.preventDefault();\n var url = form.attr('action');\n form.spinner().start();\n $('form.registration').trigger('login:register', e);\n $.ajax({\n url: url,\n type: 'post',\n dataType: 'json',\n data: form.serialize(),\n success: function (data) {\n form.spinner().stop();\n if (!data.success) {\n $('form.registration').trigger('login:register:error', data);\n formValidation(form, data);\n } else {\n $('form.registration').trigger('login:register:success', data);\n location.href = data.redirectUrl;\n }\n },\n error: function (err) {\n if (err.responseJSON.redirectUrl) {\n window.location.href = err.responseJSON.redirectUrl;\n } else {\n createErrorNotification($('.error-messaging'), err.responseJSON.errorMessage);\n }\n\n form.spinner().stop();\n }\n });\n return false;\n });\n },\n\n resetPassword: function () {\n $('.reset-password-form').submit(function (e) {\n var form = $(this);\n e.preventDefault();\n var url = form.attr('action');\n form.spinner().start();\n $('.reset-password-form').trigger('login:register', e);\n $.ajax({\n url: url,\n type: 'post',\n dataType: 'json',\n data: form.serialize(),\n success: function (data) {\n form.spinner().stop();\n if (!data.success) {\n formValidation(form, data);\n } else {\n $('.request-password-title').text(data.receivedMsgHeading);\n $('.request-password-body').empty()\n .append('
' + data.receivedMsgBody + '
');\n if (!data.mobile) {\n $('#submitEmailButton').text(data.buttonText)\n .attr('data-dismiss', 'modal');\n } else {\n $('.send-email-btn').empty()\n .html('
'\n + data.buttonText + ' '\n );\n }\n }\n },\n error: function () {\n form.spinner().stop();\n }\n });\n return false;\n });\n },\n\n clearResetForm: function () {\n $('#login .modal').on('hidden.bs.modal', function () {\n $('#reset-password-email').val('');\n $('.modal-dialog .form-control.is-invalid').removeClass('is-invalid');\n });\n }\n};\n","'use strict';\n\n/**\n * Update DOM elements with Ajax results\n *\n * @param {Object} $results - jQuery DOM element\n * @param {string} selector - DOM element to look up in the $results\n * @return {undefined}\n */\nfunction updateDom($results, selector) {\n var $updates = $results.find(selector);\n $(selector).empty().html($updates.html());\n}\n\n/**\n * Keep refinement panes expanded/collapsed after Ajax refresh\n *\n * @param {Object} $results - jQuery DOM element\n * @return {undefined}\n */\nfunction handleRefinements($results) {\n $('.refinement.active').each(function () {\n $(this).removeClass('active');\n var activeDiv = $results.find('.' + $(this)[0].className.replace(/ /g, '.'));\n activeDiv.addClass('active');\n activeDiv.find('button.title').attr('aria-expanded', 'true');\n });\n\n updateDom($results, '.refinements');\n}\n\n/**\n * Parse Ajax results and updated select DOM elements\n *\n * @param {string} response - Ajax response HTML code\n * @return {undefined}\n */\nfunction parseResults(response) {\n var $results = $(response);\n var specialHandlers = {\n '.refinements': handleRefinements\n };\n\n // Update DOM elements that do not require special handling\n [\n '.grid-header',\n '.header-bar',\n '.header.page-title',\n '.product-grid',\n '.show-more',\n '.filter-bar'\n ].forEach(function (selector) {\n updateDom($results, selector);\n });\n\n Object.keys(specialHandlers).forEach(function (selector) {\n specialHandlers[selector]($results);\n });\n}\n\n/**\n * This function retrieves another page of content to display in the content search grid\n * @param {JQuery} $element - the jquery element that has the click event attached\n * @param {JQuery} $target - the jquery element that will receive the response\n * @return {undefined}\n */\nfunction getContent($element, $target) {\n var showMoreUrl = $element.data('url');\n $.spinner().start();\n $.ajax({\n url: showMoreUrl,\n method: 'GET',\n success: function (response) {\n $target.append(response);\n $.spinner().stop();\n },\n error: function () {\n $.spinner().stop();\n }\n });\n}\n\n/**\n * Update sort option URLs from Ajax response\n *\n * @param {string} response - Ajax response HTML code\n * @return {undefined}\n */\nfunction updateSortOptions(response) {\n var $tempDom = $('
').append($(response));\n var sortOptions = $tempDom.find('.grid-footer').data('sort-options').options;\n sortOptions.forEach(function (option) {\n $('option.' + option.id).val(option.url);\n });\n}\n\nmodule.exports = {\n filter: function () {\n // Display refinements bar when Menu icon clicked\n $('.container').on('click', 'button.filter-results', function () {\n $('.refinement-bar, .modal-background').show();\n $('.refinement-bar').siblings().attr('aria-hidden', true);\n $('.refinement-bar').closest('.row').siblings().attr('aria-hidden', true);\n $('.refinement-bar').closest('.tab-pane.active').siblings().attr('aria-hidden', true);\n $('.refinement-bar').closest('.container.search-results').siblings().attr('aria-hidden', true);\n $('.refinement-bar .close').focus();\n });\n },\n\n closeRefinements: function () {\n // Refinements close button\n $('.container').on('click', '.refinement-bar button.close, .modal-background', function () {\n $('.refinement-bar, .modal-background').hide();\n $('.refinement-bar').siblings().attr('aria-hidden', false);\n $('.refinement-bar').closest('.row').siblings().attr('aria-hidden', false);\n $('.refinement-bar').closest('.tab-pane.active').siblings().attr('aria-hidden', false);\n $('.refinement-bar').closest('.container.search-results').siblings().attr('aria-hidden', false);\n $('.btn.filter-results').focus();\n });\n },\n\n resize: function () {\n // Close refinement bar and hide modal background if user resizes browser\n $(window).resize(function () {\n $('.refinement-bar, .modal-background').hide();\n $('.refinement-bar').siblings().attr('aria-hidden', false);\n $('.refinement-bar').closest('.row').siblings().attr('aria-hidden', false);\n $('.refinement-bar').closest('.tab-pane.active').siblings().attr('aria-hidden', false);\n $('.refinement-bar').closest('.container.search-results').siblings().attr('aria-hidden', false);\n });\n },\n\n sort: function () {\n // Handle sort order menu selection\n $('.container').on('change', '[name=sort-order]', function (e) {\n e.preventDefault();\n\n $.spinner().start();\n $(this).trigger('search:sort', this.value);\n $.ajax({\n url: this.value,\n data: { selectedUrl: this.value },\n method: 'GET',\n success: function (response) {\n $('.product-grid').empty().html(response);\n $.spinner().stop();\n },\n error: function () {\n $.spinner().stop();\n }\n });\n });\n },\n\n showMore: function () {\n // Show more products\n $('.container').on('click', '.show-more button', function (e) {\n e.stopPropagation();\n var showMoreUrl = $(this).data('url');\n e.preventDefault();\n\n $.spinner().start();\n $(this).trigger('search:showMore', e);\n $.ajax({\n url: showMoreUrl,\n data: { selectedUrl: showMoreUrl },\n method: 'GET',\n success: function (response) {\n $('.grid-footer').replaceWith(response);\n updateSortOptions(response);\n $.spinner().stop();\n },\n error: function () {\n $.spinner().stop();\n }\n });\n });\n },\n\n applyFilter: function () {\n // Handle refinement value selection and reset click\n $('.container').on(\n 'click',\n '.refinements li button, .refinement-bar button.reset, .filter-value button, .swatch-filter button',\n function (e) {\n e.preventDefault();\n e.stopPropagation();\n\n $.spinner().start();\n $(this).trigger('search:filter', e);\n var attributeId = '#' + $(this).find('span').last().attr('id');\n $.ajax({\n url: $(this).data('href'),\n data: {\n page: $('.grid-footer').data('page-number'),\n selectedUrl: $(this).data('href')\n },\n method: 'GET',\n success: function (response) {\n parseResults(response);\n $.spinner().stop();\n $(attributeId).parent('button').focus();\n },\n error: function () {\n $.spinner().stop();\n $(attributeId).parent('button').focus();\n }\n });\n });\n },\n\n showContentTab: function () {\n // Display content results from the search\n $('.container').on('click', '.content-search', function () {\n if ($('#content-search-results').html() === '') {\n getContent($(this), $('#content-search-results'));\n }\n });\n\n // Display the next page of content results from the search\n $('.container').on('click', '.show-more-content button', function () {\n getContent($(this), $('#content-search-results'));\n $('.show-more-content').remove();\n });\n }\n};\n","'use strict';\n\nmodule.exports = function (include) {\n if (typeof include === 'function') {\n include();\n } else if (typeof include === 'object') {\n Object.keys(include).forEach(function (key) {\n if (typeof include[key] === 'function') {\n include[key]();\n }\n });\n }\n};\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * OOTB SFRA JS code\n * DRP-453 implemented productTileSwatch\n */\n\n'use strict';\n\nvar processInclude = require('base/util');\nimport { matchesBreakpoint } from './domUtil';\nimport { stickyScrollPosition } from './util';\nconst { queryAll } = require('./domUtil');\n\n$(document).ready(function () {\n processInclude(require('./search/search'));\n processInclude(require('./search/productGrid'));\n processInclude(require('./search/productTileSwatch'));\n processInclude(require('./search/sortOrderMenu'));\n processInclude(require('./components/selectStore'));\n processInclude(require('./components/modal'));\n\n if (matchesBreakpoint('md')) {\n // 70px - size of PLP filter bar\n stickyScrollPosition(queryAll('.refinement-bar'), true, 70);\n }\n $('.product-grid-container').on('click', '.quickbuy-btn.qmob', function (e) {\n e.preventDefault();\n $('#' + $(this).data('product-id')).modal('show');\n $('.quick-buy-add-toast').attr('is-quick-buy', true);\n });\n\n $('.einstein-carousel-new').on('click', '.quickbuy-btn.qmob', function (e) {\n e.preventDefault();\n $('#' + $(this).data('product-id')).modal('show');\n $('.quick-buy-add-toast').attr('is-quick-buy', true);\n });\n\n $('.search-results').on('click', '.quick-buy-add-toast .close', function (e) {\n e.preventDefault();\n $('.quick-buy-add-toast').addClass('d-none');\n });\n});\n\nprocessInclude(require('./productTile'));\nprocessInclude(require('./pGiftCardQuickView'));\n"],"names":["_arrayLikeToArray","r","a","length","e","n","Array","isFitPredictorEnabled","document","getElementById","noop","queryFirst","selector","parent","arguments","undefined","querySelector","queryAll","slice","call","querySelectorAll","hasClass","el","classList","c","contains","getPriceFromContainer","priceContainerId","container","price","value","parseFloat","replace","getPrice","getSalePrice","getSelectedColor","colorElement","getSelectedSize","sizeElement","getSizes","sizeArray","forEach","element","size","dataset","attrValue","push","startFP","ssp","getAvailableSizes","getFitName","selectedFitElement","fitName","hasAttribute","fitSwatchName","getAttribute","updateProductSetData","$container","context","sizes","availableSizes","find","each","$","this","attr","productId","data","toString","first","val","salePrice","color","selectedFitName","sizeType","productContext","$giftCardAmount","pid","masterid","useSale","closest","prediction","event","productContainer","service","sizeOption","trigger","setAttribute","module","exports","Object","entries","handleColor","attribute","handleSize","sauce","deviceWidth","channelValue","custID","email","window","screen","width","layout","currency","language","market","shippingCountry","userId","emailHash","pt","type","pageContext","setupTrigger","initializeDom","ssAddToCart","_container$dataset","variantId","quantity","startOM","startSF","updateProductData","newColor","setSelectedColor","newSize","setSelectedSize","newPrice","priceElement","setPrice","newSalePrice","salesPriceElement","setSalePrice","reduce","exported","_ref","_ref2","isArray","_arrayWithHoles","l","t","Symbol","iterator","i","u","f","o","next","done","return","_iterableToArrayLimit","constructor","name","from","test","_unsupportedIterableToArray","TypeError","_nonIterableRest","alias","method","featureSwitch","commonjsGlobal","global","self","NumeralFormatter","numeralDecimalMark","numeralIntegerScale","numeralDecimalScale","numeralThousandsGroupStyle","numeralPositiveOnly","stripLeadingZeroes","prefix","signBeforePrefix","tailPrefix","delimiter","owner","groupStyle","thousand","delimiterRE","RegExp","lakh","wan","none","prototype","getRawValue","format","parts","partSign","partSignAndPrefix","partInteger","partDecimal","indexOf","split","NumeralFormatter_1","DateFormatter","datePattern","dateMin","dateMax","date","blocks","reverse","map","x","parseInt","unshift","initBlocks","getISOFormatDate","addLeadingZero","getBlocks","getValidatedDate","result","index","sub","sub0","rest","getFixedDateString","day","month","year","dayIndex","monthIndex","yearIndex","dayStartIndex","monthStartIndex","yearStartIndex","fullYearDone","toLowerCase","getFixedDate","getRangeFixedDate","previous","current","addLeadingZeroForYear","Math","min","isLeapYear","number","fullYearMode","DateFormatter_1","TimeFormatter","timePattern","timeFormat","time","getISOFormatTime","getTimeFormatOptions","String","maxHourFirstDigit","maxHours","maxMinutesFirstDigit","maxMinutes","getValidatedTime","timeFormatOptions","getFixedTimeString","second","minute","hour","secondIndex","minuteIndex","hourIndex","secondStartIndex","minuteStartIndex","hourStartIndex","getFixedTime","TimeFormatter_1","PhoneFormatter","formatter","setFormatter","phoneNumber","clear","validated","iMax","inputDigit","charAt","PhoneFormatter_1","CreditCardDetector","uatp","amex","diners","discover","mastercard","dankort","instapayment","jcb15","jcb","maestro","visa","mir","unionPay","general","re","getStrictBlocks","block","total","prev","concat","getInfo","strictMode","key","matchedBlocks","CreditCardDetector_1","Util_1","strip","getPostDelimiter","delimiters","matchedDelimiter","getDelimiterREByDelimiter","getNextCursorPosition","prevPos","oldValue","newValue","getPositionOffset","oldRawValue","newRawValue","lengthOffset","stripDelimiters","abs","letter","headStr","str","getMaxLength","getPrefixStrippedValue","prefixLength","prevResult","noImmediatePrefix","prevValue","getFirstDiffIndex","getFormattedValue","blocksLength","delimiterLazyShow","multipleDelimiters","currentDelimiter","fixPrefixCursor","appendix","setSelectionRange","len","setTimeout","checkFullSelection","getSelection","ex","setSelection","position","doc","getActiveElement","createTextRange","range","move","select","console","warn","activeElement","shadowRoot","isAndroid","navigator","userAgent","isAndroidBackspaceKeydown","lastInputValue","currentInputValue","DefaultProperties_1","assign","target","opts","creditCard","creditCardStrictMode","creditCardType","onCreditCardTypeChanged","phone","phoneRegionCode","phoneFormatter","timeFormatter","dateFormatter","numeral","swapHiddenInput","numericOnly","uppercase","lowercase","rawValueTrimPrefix","copyDelimiter","initValue","delimiterLength","root","_typeof","maxLength","backspace","onValueChanged","Cleave","hasMultipleElements","Error","properties","DefaultProperties","init","pps","Util","isBackward","onChangeListener","onChange","bind","onKeyDownListener","onKeyDown","onFocusListener","onFocus","onCutListener","onCut","onCopyListener","onCopy","initSwapHiddenInput","addEventListener","initPhoneFormatter","initDateFormatter","initTimeFormatter","initNumeralFormatter","onInput","inputFormatter","cloneNode","parentNode","insertBefore","elementSwapHidden","id","numeralFormatter","AsYouTypeFormatter","charCode","which","keyCode","inputType","postDelimiter","postDelimiterBackspace","copyClipboardData","textToCopy","inputValue","clipboardData","setData","preventDefault","postDelimiterAfter","updateValueState","toUpperCase","updateCreditCardPropsByValue","creditCardInfo","endPos","selectionEnd","callOnValueChanged","rawValue","setPhoneRegionCode","setRawValue","destroy","removeEventListener","Cleave_1","exportName","VENDOR_PREFIXES","TEST_ELEMENT","createElement","TYPE_FUNCTION","round","now","Date","setTimeoutContext","fn","timeout","bindFn","invokeArrayArg","arg","obj","hasOwnProperty","deprecate","message","deprecationMessage","stack","log","apply","output","source","nextKey","extend","dest","src","merge","keys","inherit","child","base","childP","baseP","create","_super","boolOrFn","args","ifUndefined","val1","val2","addEventListeners","types","handler","splitStr","removeEventListeners","hasParent","node","inStr","trim","inArray","findByKey","toArray","uniqueArray","sort","results","values","b","prefixed","property","prop","camelProp","_uniqueId","getWindowForElement","ownerDocument","defaultView","parentWindow","SUPPORT_TOUCH","SUPPORT_POINTER_EVENTS","SUPPORT_ONLY_TOUCH","INPUT_TYPE_TOUCH","INPUT_TYPE_MOUSE","COMPUTE_INTERVAL","INPUT_START","INPUT_END","INPUT_CANCEL","DIRECTION_NONE","DIRECTION_LEFT","DIRECTION_RIGHT","DIRECTION_UP","DIRECTION_DOWN","DIRECTION_HORIZONTAL","DIRECTION_VERTICAL","DIRECTION_ALL","PROPS_XY","PROPS_CLIENT_XY","Input","manager","callback","options","inputTarget","domHandler","ev","enable","inputHandler","eventType","input","pointersLen","pointers","changedPointersLen","changedPointers","isFirst","isFinal","session","pointersLength","firstInput","simpleCloneInputData","firstMultiple","offsetCenter","center","getCenter","timeStamp","deltaTime","angle","getAngle","distance","getDistance","offset","offsetDelta","prevDelta","prevInput","deltaX","y","deltaY","computeDeltaXY","offsetDirection","getDirection","start","end","overallVelocity","getVelocity","overallVelocityX","overallVelocityY","scale","rotation","getRotation","maxPointers","velocity","velocityX","velocityY","direction","last","lastInterval","v","computeIntervalInputData","srcEvent","computeInputData","emit","recognize","clientX","clientY","p1","p2","props","sqrt","atan2","PI","evEl","evTarget","evWin","MOUSE_INPUT_MAP","mousedown","mousemove","mouseup","MOUSE_ELEMENT_EVENTS","MOUSE_WINDOW_EVENTS","MouseInput","pressed","button","pointerType","POINTER_INPUT_MAP","pointerdown","pointermove","pointerup","pointercancel","pointerout","IE10_POINTER_TYPE_ENUM","POINTER_ELEMENT_EVENTS","POINTER_WINDOW_EVENTS","PointerEventInput","store","pointerEvents","MSPointerEvent","PointerEvent","removePointer","eventTypeNormalized","isTouch","storeIndex","pointerId","splice","SINGLE_TOUCH_INPUT_MAP","touchstart","touchmove","touchend","touchcancel","SingleTouchInput","started","normalizeSingleTouches","all","touches","changed","changedTouches","TOUCH_INPUT_MAP","TOUCH_TARGET_EVENTS","TouchInput","targetIds","getTouches","allTouches","identifier","targetTouches","changedTargetTouches","filter","touch","DEDUP_TIMEOUT","TouchMouseInput","mouse","primaryTouch","lastTouches","recordTouches","eventData","setLastTouch","lastTouch","lts","isSyntheticEvent","dx","dy","inputEvent","inputData","isMouse","sourceCapabilities","firesTouchEvents","PREFIXED_TOUCH_ACTION","style","NATIVE_TOUCH_ACTION","TOUCH_ACTION_COMPUTE","TOUCH_ACTION_AUTO","TOUCH_ACTION_MANIPULATION","TOUCH_ACTION_NONE","TOUCH_ACTION_PAN_X","TOUCH_ACTION_PAN_Y","TOUCH_ACTION_MAP","touchMap","cssSupports","CSS","supports","getTouchActionProps","TouchAction","set","compute","actions","update","touchAction","recognizers","recognizer","getTouchAction","hasPanX","hasPanY","cleanTouchActions","join","preventDefaults","prevented","hasNone","isTapPointer","isTapMovement","isTapTouchTime","preventSrc","STATE_POSSIBLE","STATE_FAILED","Recognizer","defaults","state","simultaneous","requireFail","stateStr","directionStr","getRecognizerByNameIfManager","otherRecognizer","get","AttrRecognizer","PanRecognizer","pX","pY","PinchRecognizer","PressRecognizer","_timer","_input","RotateRecognizer","SwipeRecognizer","TapRecognizer","pTime","pCenter","count","Hammer","preset","Manager","handlers","oldCssProps","inputClass","toggleCssProps","item","add","recognizeWith","requireFailure","cssProps","dropRecognizeWith","dropRequireFailure","hasRequireFailures","canRecognizeWith","additionalEvent","tryEmit","canEmit","inputDataClone","reset","process","attrTest","optionPointers","isRecognized","isValid","threshold","directionTest","hasMoved","inOut","validPointers","validMovement","validTime","clearTimeout","taps","interval","posThreshold","validTouchTime","failTimeout","validInterval","validMultiTap","tapCount","VERSION","domEvents","userSelect","touchSelect","touchCallout","contentZooming","userDrag","tapHighlightColor","stop","force","stopped","curRecognizer","existing","remove","on","events","off","gestureEvent","createEvent","initEvent","gesture","dispatchEvent","triggerDomEvent","INPUT_MOVE","STATE_BEGAN","STATE_CHANGED","STATE_ENDED","STATE_RECOGNIZED","STATE_CANCELLED","Tap","Pan","Swipe","Pinch","Rotate","Press","define","_require","require","getProductData","formatMessage","afterpayTimeout","elementArray","items","scope","matches","afterpay","_options$alwaysShow","alwaysShow","anchors","observerTargets","priceTargets","renderMode","renderTarget","_options$showExcluded","showExcluded","_options$thresholds","thresholds","_options$logoPosition","logoPosition","presentAfterpay","afterpayPrefsEl","afterpayPrefs","apConfig","afterpayLogoColor","locale","exclusions","JSON","parse","apThresholds","minMaxThreshold","max","updateAmount","config","stringValue","isDecimalValue","intValue","amount","observerTarget","innerText","renderAfterpay","instance","anchor","mode","_config$minMaxThresho","notWithinThreshold","excluded","hidden","_getProductData","masterId","productName","afterpayNode","afterpayMessage","parentElement","firstChild","lastToken","pop","tokenText","excludedMultiSuffix","textContent","notWithinThresholdMessage","instanceNode","insertAdjacentElement","replaceChild","appendChild","instanceConfig","anchorObserverTargets","priceValue","isNaN","apInstance","observer","MutationObserver","mutations","observe","childList","subtree","xs","sm","md","lg","xl","addClass","isInViewport","removeClass","scrollTo","errorTextTemplate","checkoutContainerEl","checkoutContainer","showClass","scrollToError","formEl","headerEl","headerHeight","offsetHeight","invalidEl","top","validateForm","valid","checkValidity","stopPropagation","stopImmediatePropagation","validity","clearForm","form","enableOrDisableButton","disabled","getValidationMessage","validationMessage","$this","patternMismatchValue","rangeErrorValue","missingErrorValue","badInputErrorValue","stepMismatchErrorValue","_this$validity","patternMismatch","rangeOverflow","rangeUnderflow","tooLong","tooShort","valueMissing","badInput","stepMismatch","onFormInvalidHandler","setCustomValidity","parents","text","onFormSubmit","validateInputs","getAddressValidationHandler","addressLengthLimit","addressForm","timeoutID","formHelpers","addressEl","loadFormErrors","toPrimitive","_toPrimitive","_toPropertyKey","defineProperty","enumerable","configurable","writable","invalid","ajaxFormInvalid","formElSelector","submit","ajaxFormSubmit","validateAddressForm","address1","address2","addressLimit","addressValidationHandler","validateCheckoutForm","guestCustomerForm","registeredCustomerForm","shippingForm","billingForm","submitShippingBtn","billingAddress","reauthForm","submitReauthBtn","spinner","submitCustomerBtn","submitCustomerLoginBtn","shippingAddress1","shippingAddress2","shippingAddressLimit","shippingAddressValidationHandler","billingAddress1","billingAddress2","billingAddressLimit","billingAddressValidationHandler","click","errorElement","shippingError","addressMode","customerType","innerHTML","giftMessageEl","submitPaymentBtn","isPaymentDisabled","isCreditTabActive","isNewPayment","isRequired","savedPaymentCvv","required","checkoutStage","link","enableFormSubmitButton","$form","isFieldsMatched","newFieldValue","confirmFieldValue","matchId","confirmEl","isFieldMatched","mismatchError","selectorContainer","notMatchedClass","matchedClass","thisValue","regexPattern","regexpattern","buttonClick","functions","debounce","SCROLLABLE_CONTENT_SELECTOR","initSpecificCarousel","scrollableContainerEl","parentEl","leftArrowEl","left","scrollLeft","offsetWidth","behavior","rightArrowEl","scrollWidth","initCarousel","hasEtmc","_etmc","trackCart","trackPageView","trackWishlist","setUserInfo","$body","currentModal","modal","css","overflow","hiddenClass","ispuContainer","$ispuModalContainer","$ispuClosestParent","handleStoreResults","noStoresMessage","storeResults","storesResultsHtml","noStoresErrorMessage","errorCallBack","handleInStore","locationData","latitude","longitude","address","actionUrl","inputSearchParameter","forceGeoLocation","isPLP","getJSON","googleKey","includeGoogleMaps","_target$dataset","storeId","storeName","storeCity","storeStateCode","getLatLong","toggle","findStoreSubmit","removeAttribute","confirmSection","geolocateError","handleISPUModalClose","mixinData","geolocate","handleDetectLocation","SHIPPING_PREFERENCES_CONTAINER_SELECTOR","STORE_DETAIL_CONTAINER_SELECTOR","ISPU_PREFERENCE_CONTAINER_SELECTOR","ISPU_PREFERENCE_CONTENT_SELECTOR","ISPU_RADIO_SELECTOR","SHIP_TO_ADDRESS_RADIO_SELECTOR","STORE_DETAIL_SELECTOR","STORE_SERVICE_INFO_MESSAGE_SELECTOR","STORE_AVAILABILITY_MESSAGE_SELECTOR","ISPU_INFO_MESSAGE_SELECTOR","SHIP_TO_INFO_MESSAGE_SELECTOR","ISPU_SELECT_STYLE_MESSAGE_SELECTOR","DISABLED_CLASS","NOT_AVAILABLE_CLASS","ISPU_STORE_NAME_CLASS","PRE_ORDER_CLASS","SHIP_TO_LOW_INVENTORY_CLASS","ISPU_SERVICE_ERROR_ATTR_NAME","ISPU_SERVICE_BLOCKED","CHECKOUT_HIDDEN_CLASS","PDP_SET_PAGE","PRODUCT_DETAIL_CONTAINER_SELECTOR","PDP_CONTAINER_SELECTOR","PREFERENCE_SELECTOR","SHIP_TO_ADDRESS_CONTENT_SELECTOR","SHIPPING_PREFERENCE_RADIO_BUTTON_SELECTOR","RADIO_BUTTON_LABEL_SELECTOR","SHIPPING_PREFERENCE_KEY","ISPU_RADIO_VALUE","SHIP_TO_RADIO_VALUE","BOLT_PAY","CHANGE_STORE_LINK_SELECTOR","AVAILABILITY_MSG_SELECTOR","INVENTORY_MSG_SELECTOR","LOW_STOCK_ISPU_SELECTOR","WISHLIST_NAME_REGEX","TRACKER_FUNCTIONAL_COOKIE","LOYALTY_POSTAL_CODE_REGEX","MY_ACCOUNT","ORDER_CONFIRMATION","getNestedValue","_require3","HIDDEN_CLASS","handleNotifyMe","getISPUradioButtonEl","productContainerEl","getShipToAddressContentEl","getShipToAddressradioButtonEl","getISPUPreferenceContentEl","addStoreNameClass","storeNameEl","removeStoreNameClass","getSelectedSizeEl","getChangeStoreLinkEl","getSelectedPreferenceEl","getShippingPreferencesContainerEl","selectISPURadioButton","ispuRadioButtonEl","enableISPUSection","checked","ispuContentEl","disableISPURadioButton","disableISPUSection","selectShipToRadioButton","shipToRadioButtonEl","enableShipToContent","shipToContentEl","disableShipToRadioButton","disableShipToContent","getPreferedShippingPreference","activeStoreFilter","updateVisibilityOfLowInventoryMsg","ispuLowStockEl","availabilityElement","ispuLowInventory","ispuLowInventoryMsg","notifyMeButton","notifyMeDesc","addToCartSection","selectedSizeElement","ispuProductInventory","isSetPage","selectedSizeValue","selectedColorId","variantGroupData","productInfo","variants","images","formattedPrice","selectedSizeData","isNotifyMeEnabled","ID","forceOutOfStock","productInventory","availabilityStatus","productData","available","imageData","ispu","getAvailableForInStorePickup","availableForInStorePickup","breakpoints","PREFERRED_STORE_ID","EMPTY_STRING","INVALID_CLASS","INVISIBLE_CLASS","NO_SCROLL_CLASS","IS_STICKY_CLASS","SELECTED_CLASS","PREORDER_STATUS","IN_STOCK_STATUS","NOT_AVAILABLE_STATUS","KEYCODE_TAB","KEYCODE_ESCAPE","KEYCODE_UP","KEYCODE_DOWN","loadScript","isAsync","Promise","resolve","script","async","onload","body","append","loadInput","referrerID","formElement","getStyles","styles","getComputedStyle","_len","rules","_key","rule","NodeList","removeChild","_len2","_key2","_el$classList","_node$classList","_len3","_key3","_el$classList2","_node$classList2","toggleClass","_len4","_key4","_el$classList3","_node$classList3","_len5","classes","_key5","every","className","throttle","limit","waitCallback","isThrottling","_len6","_key6","returnValue","_this","timer","minimumDelay","condition","unrestrictedCallback","_len7","_key7","_len8","_key8","newTarget","array","makeArray","outerHeight","marginTop","marginBottom","isInViewportCheck","scroll","scrollY","pageYOffset","boundsTop","getBoundingClientRect","numberOfViewportToCheck","nextViewportLazyLoad","viewport","innerHeight","bounds","clientHeight","rect","bottom","right","innerWidth","documentElement","clientWidth","emptyCart","cartElement","duration","getLastElementInRow","nextElementSibling","sibling","offsetTop","scrollHeight","previousElementSibling","updateUrlQueryParam","fragment","queryParamsElement","permaLink","history","pushState","path","newUrl","location","href","getCharacterCount","waitForElement","reject","elements","disconnect","eventTypes","eventCondition","_options$bindEngine","bindEngine","_options$once","once","useJQuery","_options$targetSelect","targetSelectors","extraData","Element","jQuery","Event","targetElement","_targetElement","$element","variationGroupId","originalPrice","productPrice","isPreorder","containerData","monetatePid","isQuickview","_window","wishlistId","productSize","swatchName","colorCode","colorEl","swatchButton","attrDisplayvalue","tileEl","standardPrice","groupId","productNameEl","productSizeEl","valueId","originalPriceEl","productPriceEl","productColorEl","productColor","matchesBreakpoint","breakpoint","matchMedia","getCSRFToken","token","renderFragment","html","template","content","getCookieMap","cookie","keyValue","_keyValue$trim$split2","decodeURIComponent","validateDate","monthSelector","dateSelector","validateDateOption","m","d","mlength","labelOption","Option","option","selected","googleMapScript","geocoder","head","callBack","mixin","google","maps","Geocoder","geocode","status","GeocoderStatus","OK","geometry","lat","lng","ownKeys","getOwnPropertySymbols","getOwnPropertyDescriptor","_objectSpread","_defineProperty","getOwnPropertyDescriptors","defineProperties","formValidation","createErrorNotification","baseLogin","_require2","formatPhoneNumber","getItemFromLocalStorage","registrationFormPhone","loyaltyGuestReferralModal","login","one","redirectUrl","url","ajax","dataType","serialize","success","error","responseJSON","register","err","errorMessage","resetPassword","resetPasswordDialog","emailEl","handleLogin","loginBtnEl","$loginFormEl","mobileImg","desktopImg","getTimeRemaining","loyaltyWelcomeDialog","loyaltyEnrollNowDialog","invalidClass","activeClass","exclusiveCarouselIdSelector","loyaltyEarlyAccessRegisterForm","earlyAccessPdpSignInRegistration","_require6","swatchImageDownload","swatchImageDownloaded","downloadCtaDesktop","downloadCtaMobile","handleEarlyAccessEnrollModal","welcomeDialogEarlyAccessMsgEl","welcomeDialogMsgEl","removeWelcomeModalShowSession","reload","handlePdpEarlyAccessLoginRegistration","isLoyaltyMember","postalCode","showWelcomeModal","loyaltyEnrollModalForm","loyaltyEnrollPostalCodeEl","loyaltyGuestEnrollment","closeButton","welcomeSessionUrl","attachLoginRegistrationFormEvents","handleEarlyAccessLogin","earlyAccessCta","accountRegistrationForm","loginForm","signInForm","registerForm","accountHelpEl","earlyAccessRegisterLeft","earlyAccessRegisterRight","loyaltyRegistrationForm","loyaltyLoginForm","loyaltyProgramMemberId","earlyAccessSignIn","optedInToLoyalty","earlyAccessRegistration","hideShowDrawerImage","drawerMobileImg","drawerDesktopImg","desktopImageWrapper","mobileImageWrapper","drawerMobileImgEl","drawerDesktopImgEl","loyaltyDrawerImageView","updateReferralBg","loyaltyReferralBg","_loyaltyReferralBg$da","bgColor","bgImageDesktop","bgImageMobile","setProperty","drawerImage","loyaltyModalEl","withImageEl","withoutImageEl","loyaltyDrawerBackground","updateImgURLOnDownloadCta","selectedWallpaperId","selectTab","imageElement","swatchImageDownloadCtaDesktop","swatchImageDownloadCtaMobile","swatchImageDownloadedCtaDesktop","swatchImageDownloadedCtaMobile","_imageElement$dataset","desktopDownloadedImage","mobileDownloadedImage","carousel","wrap","carouselControlsToggle","exclusiveCarousel","carouselControl","lastElementChild","firstElementChild","previousControl","nextControl","hash","exclusiveExperiencesTile","_loop","exclusiveModule","countDownTime","countDownTimer","countDownEle","countDownEleNoDays","countDataMsg","counterMsg","countDataMsgNoDays","timeinterval","setInterval","tokenize","newCountDataMsg","days","clearInterval","updateClock","exclusiveExperiencesCountDown","earlyAccessBtn","loyaltyDrawer","loyaltyAppImage","loyaltyDrawerContent","isAppDrawer","drawerAppImgEl","appImageWrapper","appMobileImgEl","isLoyaltyProgramDrawerClick","isLoyaltyProgramOverviewFromHeader","loyaltyContainer","guestEnrollment","memberSignInEnrollment","loyaltyIsImage","title","closeButtonLabel","drawerTitle","drawerCloseButtonLabel","drawerTitleE1","drawerCloseButtonE1","ariaLabel","loyaltyEnrollPostalCodeContainer","loyaltyEnrollPostalEl","loyaltyEnrollCheckboxEl","enrollNowSource","loyaltyRemoveClass","loyaltyEnrollNowSubmit","postalCodeEl","referrerIDEl","postalCodeRegex","regexp","invalidFeedback","requestData","lillyLoyaltyProgram","loyaltyUnenrollDashboard","accountLoyaltyDashboard","showWelcomePopup","loyaltyDashboardShow","checkLoyaltyAccess","showEnrollmentModel","imageUrls","modelImages","enrollmentModel","welcomeModel","loyaltyaccesspopupmobile","LoyaltyguestenrollmentnonloyaltyD2x","loyaltywelcomepopupmobile","LoyaltywelcomeloyaltyD2x","loyaltyDashboardOffersTile","expirationDateTime","cardFlippedEl","cardFront","_e$target$dataset","expiryDate","couponCode","formatString","offerDiscountDialog","offerDiscountTileData","offerDiscountModalData","copyCodeText","getFormatDateString","clipboard","writeText","loyaltyReferralDrawer","referralUrlElement","referralUrl","loyaltyCopyReferralUrl","copyReferralUrl","copyCta","copiedLinkCta","then","loyaltyOopsRefreshSection","successServiceResData","tooltipModule","tooltipInnerData","serviceResHTMLData","updatedToolTip","popContent","tooltipIcon","popover","placement","clickEvent","clicked","scrollableContent","referralModuleBg","referralSection","loyaltyEarlyAccessSignUp","guestEmptyWishlistTemplate","giftCardContainerSelector","selectedClass","updateHiddenAmountField","giftCardContainer","amountHiddenInput","clearAmountErrorMessage","amountSelectionHandler","customAmountInput","inputOverlay","wishlistProductCard","addToToteButton","amountInputEnableHandler","focus","amountInputHandler","disabledClass","addToCart","pGiftCardContainer","selectedColorAttributeEl","attributesEl","invalidSwatchError","displaySwatchErrorMessage","wishlistCardItem","response","removedWishListItem","wishListCountMessage","updatedWishListCount","itemsMsg","shopNewAsset","selectedListDiv","detailsTabItemCount","listItemCount","emptyWishlistMarkup","wishlistCardItems","outerHTML","messageType","postAddToCart","setPid","_event","giftCardProductIdInputs","product","giftCardProductIdInput","pGiftCardForm","initializeEvents","processInclude","giftCardDetail","focusHelper","toggleSelectSizeInfo","isEarlyAccessElement","swatchNameTemplate","sizeButtonTemplate","sizeOptionTemplate","gwpSizeTemplate","dialogTemplate","videoThumbnailTemplate","loyalty","$gwpDialog","readyClass","selectedProductClass","notAvailable","_require4","loyaltyProfile","isLoyaltyProgramMember","isLoyaltyAuthenticated","isLoyaltyEnabled","isMcEnable","selectedSizeCTA","getPidValue","$el","getQuantitySelector","getQuantitySelected","updateAttrs","attrs","$productContainer","msgs","attrsWithSwatches","fitSizes","filteredValues","fitSizeLi","counter","elFitSizeContainer","fitSize","isDirectlyPurchasable","displayName","displayValue","selectable","hide","show","isChoiceOfBonusProducts","$attrValue","$swatchButton","siblings","assistiveSelectedText","empty","bonusVariationUrl","removeAttr","processSwatchValues","$bonusProductItem","sizeContainer","singleSize","loopStatus","resetUrl","selectLabel","selectId","sizeOptions","multiDefaultSizeOption","inStock","outOfStockMsg","outOfStock","multiSizeOption","multiSize","productContainerEle","isPDPSetPage","li","selectedSize","variantID","manufacturerSKU","ssSize","insertAdjacentHTML","selectedSizeEle","processNonSwatchValues","updateOptions","$optionEl","handleEarlyAccessCta","isEarlyAccessProduct","earlyAccessLockIcon","earlyAccessWishlistIcon","addToCartCta","earlyAccessPdpEl","earlyAccessGuest","earlyAccessRegistered","createCarousel","imgs","isEarlyAccess","videoUrl","carouselId","displayCounter","pdpPageCarousels","pId","EGCPage","pdpCarouselClass","counterHtml","dataSrc","imageZoomUrl","imagePresetUrl","enableCache","includes","srcset","alt","appendTo","addToWishlistIconPdp","loyaltyEarlyAccessEl","addToCartButtonPdp","loyaltyEarlyAccessLockContainer","firstImageElement","videoTemplate","templateVideoElement","eachElement","load","replaceVideoThumbnailImage","detach","MagicZoom","handleVariantResponse","triggerColorAction","_response$product","variationAttributes","productType","readyToOrder","bonusVariationAtrributes","isFinalSale","earlyAccess","videoFile","saleMessageEl","resources","sizeElements","primaryImageUrls","checkout","large","productImageElement","setModalImages","swatchNameElement","selectedSwatch","selectedSwatchName","swatchHtml","swatchNameHtml","selectedSwatchElement","manufacturerID","$priceSelector","replaceWith","promotionElement","promotionsHtml","variantGroupId","swatchParam","queryParams","UpdatedParams","promotionsPopover","availabilityValue","availabilityMessages","availability","messages","availabilityMsgEl","notPurchasable","updateAvailability","attributes","attributeGroup","label","getAttributesHtml","_response$queryString","_variationAttributes$","fitSizeEle","requestedFitSize","queryString","param","fitSizeIncluded","attributeId","search","eachParam","replaceState","updateQuantities","quantities","optionsHtml","attributeSelect","selectedValueUrl","$choiceOfBonusProductEl","updatedimageSlideArrowPDP","carouselArrows","height","videoThumbnailEl","playPromise","videoThumbnailImgEl","videoComponentSourceEl","video","canvas","ctx","getContext","img","Image","videoWidth","videoHeight","pause","catch","drawImage","toBlob","blob","URL","revokeObjectURL","createObjectURL","_videoComponentSource","xhr","XMLHttpRequest","open","responseType","muted","play","send","fetchAndPlayVideo","updateProductPrice","priceTemplate","priceSection","priceContainer","strikeThroughContainer","salesContainer","fixedPrice","fixedStandardPrice","toFixed","updateSizeElements","variantsList","quickviewProductInfo","_sizeContainer$datase","selectedText","describedby","sizeButtonHtml","eachVariant","eachSize","sizeId","inventoryData","variantData","sizeSwatchNotAvailable","sizeswatchnotavailable","updateImageDetails","imageObj","srcsetPresets","srcsetString","imageScene7","parseHtml","$html","parseHTML","selectedProducts","footer","getOptions","$elOption","urlValue","selectedValueId","optionId","stringify","setControlsEnabled","control","methods","editBonusProducts","bonusUrl","bonusChoiceRuleBased","showProductsUrlRuleBased","showProductsUrlListBased","maxBonusItems","addToCartUrl","uuid","pliUUID","pageSize","bonusDiscountLineItems","parsedHtml","renderedTemplate","enterDialogMessage","insertAfter","selectedBonusProducts","modalDialog","selectedProductsCount","eachProductList","bonusAccordionContainer","maxCount","maxItems","productListLength","eachProduct","selectedProduct","selectBonusCheckbox","selectedIndex","productDialog","accordionContainer","bonusAccordionElements","sizeEl","isSizeSelected","isSelectedSizeUnavailable","children","firstOption","isEnabled","validProducts","chooseBonusProducts","updateProductDetails","currentElement","elementData","swatchContainer","assistiveElements","assistiveTextElement","monogramBtn","_productInfo$variants","shopThePrint","mgFlag","mgLocs","hasWaysToWear","colorElements","customPageTitle","pageTitle","includeLillyColor","lillyColorName","customPageDescription","pageDescription","titleElement","descriptionElement","waysToWearEl","variationGridUrl","colorlabel","colorLabel","longDescriptionElement","description","longDescription","lillyColor","productFinalSaleMessage","productFreeReturnsMessage","variationUrl","variationGroup","updateContentModules","shopThePrintElement","updateShopThePrint","ssColor","ssSizeElement","carouselContainerEl","carouselContainerHeight","minHeight","wishlistButton","assistiveText","focusChooseBonusProductModal","onClosingChooseBonusProductModal","trapChooseBonusProductModalFocus","focusParams","containerSelector","firstElementSelector","lastElementSelector","setTabNextFocus","colorAttribute","productDetailContainer","selectedSizeBtn","notifyMeCTA","addToCartCTA","_productInfo$variants2","pdpBreadCrumbs","monetateData","updateQuickViewDetails","_data$product","selectColorAttribute","renderSizeElements","swatchEl","_productInfo$variants3","selectAttribute","currentTarget","pidsObj","setPids","setMasterPid","storeLocatoreContainer","ispuAddToCart","ispuModalContainer","isSet","triggerSSAddToCart","setModal","setProducts","qty","childProducts","displayModal","addToCartWarningDialog","isOnCartPage","pathname","buttons","primary","redirectLink","modalContentHeading","messageHeading","modalContentBody","messageBodyOnCart","messageBodyOffCart","handlePostCartAdd","productContainerPrice","selectBonusProduct","$choiceOfBonusProduct","maxPids","totalQty","choiceOfBonusProduct","selectedProductElement","bonusCountElement","selectedCount","enableAddTocart","optionID","selectedBonusProductHtml","removeBonusProduct","$selected","enableBonusProductSelection","bonusProductDialog","showMoreBonusProducts","addBonusProductsToCart","$readyToOrderBonusProducts","pidsObject","bonusProducts","qtyOption","revealRecommendations","eachRecommendation","titleEl","productEl","display","handleEarlyAccessPLPLockIcon","earlyAccessPLPContainer","earlyAccessPlpIcon","lockIconContainer","earlyAccessPLPBadge","earlyAccessDate","isEarlyAccessItem","isShippingPreferencesViewEnabled","_require$productDetai","availabilityMessageTmpl","restrictedMessageTmpl","availabilityMessageOOS","availabilityMessagePreorder","ispuAvailabilityMessageTmpl","ispuLowStockMessageTmpl","sizeChartClasses","ACTIVE_CLASS","IN_STOCK","NOT_AVAILABLE","PREORDER","handleProductImageZoom","imageObserver","mutationList","_step","_iterator","_n","F","s","_createForOfIteratorHelper","mutation","addedNodes","zoomAlt","pdpImages","pdpIndicators","imageEl","zoomed","mobileZoomed","touchZoom","elm","thisHammer","transform","xPos","yPos","ceil","createTouchZoom","createHoverZoom","not","hiresUrl","zoom","magnify","onSizeChangeHandler","sizeDetailsContainer","selectedSizeErrMsg","assistiveElementOfSelected","_assistiveElementOfSe","updateQuickViewProductInfo","currentSizeElement","quickViewInfo","vgProductDetailsUrl","addToCartButton","productDetailsUrl","fullPDPLink","variantProductDetailsUrl","isLowInventory","selectedColorName","updateScarcityMessage","fitSizeScarcityLabel","ctaScarcityLabel","oosMsg","updateProductInfo","formattedStandardPrice","totalPrice","monogramProductPrice","ispuButton","restrictedMsg","restrictedItem","isGlobaleSession","scarcityMessage","ispuInventoryData","ispuMessage","ispuLowStockMessage","ispuAvailabilityStatus","isISPULowInventory","shippingPreferencesEnabled","ispuAvailabilityValue","ispuLowStockValue","lowStockAvailabilityMessage","breadcrumbItems","categoryUrl","shipToAddressAvailabilityStatus","inStorePickUpAvailabilityStatus","isStorePickUpLowInventory","inStorePickUpAvailabilityMessage","inStorePickUpLowStockMessage","pickupImageElement","_ispu$","imageHasLoaded","pickupSalesPrice","pickupStandardPrice","pickupSize","sizeSelected","ispuCheckBoxChecked","monogramImages","monogram","updatedImageData","updateFitSizeTab","fitSizeSelectableCount","fitSizeSelectableConatiner","sizeAccordionEle","fitSizeText","sizeText","fitSizeCount","selectableCount","firstAvailableFit","handleLastLinkTab","sizeChartCatBtn","shiftKey","setDynamicHeight","imgContainer","carouselIndicators","mainImageHeight","maxHeight","_carouselInnerItem$ge","clickedContainerEle","carouselIndicatorsActivedImages","carouselIndicatorsActivedPips","idx","carouselIndicatorsToBeActivedImages","carouselIndicatorsToBeActivedPips","carouselMzThumbSelected","carouselInnerItem","carouselItemImage","carouselMzZoomWindow","newImgSrc","newImgAlt","triggerHandler","imgEle","mzZoomImg","scrollFitRatingToReviews","bvReviews","updateAttribute","_response$data$produc","gtmData","gtmGA4Data","eq","$addToCart","colorVariationObject","selectedSwatchObject","eachValue","$swatchSection","updateSelectedSwatchProductName","selectSizeAttribute","buttonElement","productTileItem","selectedColor","plpItemImage","notifyImageElementMarkup","notifyContainer","sizeLabel","notifySize","notifySizeSeperator","notifySelectedSize","custEmail","notifyForm","notifyConfirm","selectedColorElement","selectedColorIdValue","selectedSizeEleValue","attrUrl","availabilityEle","quickViewCarouselEl","afterAttributeSelect","wishListID","responseContainer","sizeCard","sizeSeparator","_assistiveElementOfSe2","quickviewContainer","availabilityMessageEl","sales","formatted","updateCartButton","giftWrapAvailableFlag","giftWrapAvailable","_ispu$2","ssColorElement","pricesObject","list","ssSalesPrice","ssPrice","productSetModal","addAllToToteButton","selectPdpSizeAttribute","selectedSizeEl","allSelectableSwatches","updateAttributesAndDetails","attributesHtml","shortDescription","showSpinner","quickViewModal","allAvailable","allReady","info_selectforstock","sizeChart","$prodSizeChart","$lpSlideout","activeCategoryVal","defaultText","setStickyNav","is","complete","$activeCategoryEl","$lpSizechartTitle","tab","animate","lastLinkEl","handleEarlyAccessLockIcon","productContainerEarlyAccessIcon","earlyAccessItem","handleOflineProduct","offlineContainerEl","getTime","resizeTimeout","selectStyleMessageTmpl","ispuSelectStyleMessageTmpl","selectStylesMessage","ispuAvailabilityMessageEl","earlyAccessUntilDate","isPDPPage","mainImageEle","notifyImageElement","updatePLPTileHeight","cards","carouselImageHeight","detail","_require$default","injectAfterpay","injectFitPredictor","injectLongDescription","updateFullProductLink","quickViewTemplates","quickView","$window","header","getNavOffset","attachFormEvents","quickViewFormSelector","showQuickview","$target","quickviewURL","lastElementInRow","selectedProductDescriptionElement","stopSpinner","scrollTop","filledContainers","containerTop","isNewContainerBelow","openContainer","requestAnimationFrame","openTagIndex","substr","selectedSwatchEl","gcType","quickViewFullDetailMsg","productUrl","quickViewContainer","earlyAccessGuestSignIn","injectQuickView","srcElement","quickViewModalEl","quickview","getModalHtmlElement","productLineItemEl","lineItemAmountEl","padding","focusQuickview","trapQuickviewFocus","nextToLastElementSelector","hideDialog","isCartPage","beforeUpdateAttribute","updateAddToCart","buttonToUpdate","validateEmail","emailFormGroup","emailError","missingError","notifyMeSubmit","checkBoxValue","isChecked","productID","subscribe","confirmMessage","notifyMeCntr","notifyMeCloseCTA","notifyMe","containerEl","lastSubBtnEl","windowWidth","hideClass","hideEle","hideBtn","hideFilterEle","openFilterIcon","closeFilterIcon","refinementBar","searchContainerEl","refinementsEl","refinementBarTitleEl","sortOrderBtn","lastAccordionElement","firstAccordionElement","lastTitleBtnEl","lastSubBtnEls","filterPill","mql","firstAddToWishlistBtn","toggleFilterDisplay","showFilterSortHeader","handleSortOrderTab","lastElExpanded","sortOrderExpanded","hiddenFilterPill","handleFilterTab","handleLastElTab","handleFirstElTab","handleLastSubBtnElTab","handleWishlistBtnTab","handleFilterPillBtnTab","windowTest","w","scrollIntoView","mobileScrollToBottom","handleSlotsAppearance","categoryMarketingSlots","categoryMarketingSlot","_slicedToArray","badgeHideClass","badgeShowClass","productTileWrapper","quickBuyContainer","productTile","imageIndicators","productTileId","elImgContainer","elSwatchContainer","elLoyaltyProductBadgeContainer","addToWishlistIconPlp","loyaltyEarlyAccessLockPlp","isLoyaltyHeaderProfile","elProductBadgeContainer","elProductBadgeTxt","elTileImgURL","elProductName","elProductMoreColors","swatchurl","category_id","utag_data","medium","imageDataLength","tileIndicatorTmp","sliderTmp","merchAltImageParams","_params","categoryId","adjustedSwapIndex","lastImage","image","productBadge","badgeText","badgeTextColor","tileImageUrl","quickViewURL","quickviewButton","variationAttr","isRestricted","stockNotificationAllowed","findIndex","selectedProductTileUrl","moreLink","_data$queryString$spl","originalSrc","hoverSrc","hover","originalAlt","hoverAlt","hoveralt","cacheSyncTimer","baseSearch","appendToUrl","emptySwatchTemplate","_require5","$searchResultsContainer","$refinementBar","$modalBG","REFINEMENTS_CONTAINER_SELECTOR","_getCookieMap","akamaiEnabled","lp_hsc_enabled","plpCaching","lp_hsc_category","lpCacheHash","lp_cache_hash","lpGroupHash","lp_group_hash","isAkamaiEnabled","akamaiSettings","plpHeader","mainHeader","updateSortOptions","toggleEl","gridFooter","dataSortLabel","sortLabel","_JSON$parse","sortOptions","selectedRule","ruleId","$sortOption","updateDom","containers","updates","clone","handleRefinements","activeDiv","parseResults","specialHandlers","updateCount","productCount","resultCounts","noFilterResults","noproductcount","refinementFilterCount","filterText","filterAppliedCount","filterCount","storeFilterToggle","filterLabel","updateFilterCount","selectedFilterCount","correctFilterCount","displayClass","productcount","showNoResultsText","updateDOMElement","elementToUpdate","updatePageTitle","canonicalUrl","metaTag","canonLink","updatePatternImageSwatch","refinementPatterns","_imageEl$dataset","updateProducts","staleProductIds","productGrid","Boolean","oosProducts","_productGrid$dataset$","outOfStockMessage","oosClass","swatches","getResultsOnPriceFilter","prevActionUrl","updatedActionUrl","storeToggleEl","STORE_ID_PARAM","origin","searchParams","delete","appendStoreFilterQueryParams","akamaiActionUrl","pageNumber","page","selectedUrl","serverTiming","getResponseHeader","isCached","refinementsContainer","updateRefinementsAjaxUrl","cacheKey","encodeURIComponent","productIds","syncUrl","stale","cacheInvalidated","cacheRefreshDelay","cacheSyncDelay","imageAndQuickbuyHoverHandler","initialiseSearchIntersection","loadProducts","showMoreUrl","isPagination","observerObj","isBackButton","unobserve","applyStoreFilter","checkboxToggleEl","backToTopButtonEL","IntersectionObserver","entry","isIntersecting","targetURL","selectedFilterCountEl","noResultsRecommendationPage","refinementPrice","_queryFirst","_queryFirst2","minPrice","maxPrice","refinementFilterText","ready","fitSelect","hideRefinements","showMore","pagination","baseUrlElem","baseUrlWithParams","baseUrl","baseParams","URLSearchParams","qsParams","applyFilter","isSelected","isCatfilter","applyButton","_e","storeFilterToggleEl","buttonLabel","storeSelectorEl","storeToggleCTA","updatePrice","uri","updateQueryStringParameter","separator","match","closeRefinements","filterResults","resize","sortHandler","sortText","focusTileOnBackButton","productGridContainer","activeTileId","tile","startsWith","hasParentTile","scrollToProductTile","handleOptionBtnClick","addToWishlist","addToWishlistModal","cart","cartAvailabilityMessageOOS","promo","shippingMethod","checkoutNormalShipping","checkoutDiscountShipping","discountPrice","addressSuggestions","suggestionTextTemplate","suggestionsTemplate","approachingDiscounts","discountContainerTemplate","singleDiscountTemplate","multipleDiscountsTemplate","nonCouponBasedAdjustmentTemplate","_options$loop","loop","_options$videoUrl","_options$imgUrl","imgUrl","_options$classNames","classNames","_options$autoplay","autoplay","_options$muted","_options$controls","controls","_options$icontitle","icontitle","_options$icondesc","icondesc","imageTemplate","altText","ariaDescribedby","oosMessage","emptyWishlistMessage","emptyWishlistContentAssetBody","emptySFL","emptySFLMessage","continueShopURL","continueShopMsg","signInMsg","signInSFLURL","autoComplete","suggestionLink","suggestion","addressLine","secondaryEntryAddressLine","street_line","secondary","city","zipcode","suggestionContainer","containerClass","contactUsTemplate","signupMessage","msg","browserWarningTemplate","shippingPreferenceTemplates","shippingPreferences","ispuRadioLabel","ispuRadioValue","shipToRadioLabel","shipToRadioValue","changeStoreLabel","preferISPU","storeDetail","stateCode","productDetail","_options$buttons","_options$className","_options$modalContent","_options$modalContent2","_options$id","_options$slideOut","slideOut","buttonSpace","floor","oneTrust","privacyDialogCookieBanner","carouselBadge","string","leftToken","rightToken","operators","_","code","toKebabCase","roundPrice","gePrice","roundingRanges","rg","From","To","intPart","RangeBehavior","RoundingExceptions","LowerTarget","UpperTarget","Threshold","ExceptionValue","TargetBehaviorHelperValue","convertRangeToAbsolute","absoluteRounding","hashValue","endsWith","digit","charCodeAt","toDatasetKey","tokens","keyString","replaceValues","initOnce","flag","params","onSuccess","onError","successCallback","errorCallback","geolocation","getCurrentPosition","coords","setItemInLocalStorage","localStorage","setItem","getItem","removeItemFromLocalStorage","removeItem","cleave","isMobile","mobileAgentHash","stickyScrollPosition","isTopOnly","topOffset","ticking","detailStickyScroll","itemHeight","windowHeight","newTop","handleStickyPositionOnScroll","isUnsupportedBrowser","unsupportedBrowserTypes","sitePrefs","some","uaFragment","endtime","seconds","minutes","hours","globaleCalculation","salesPrice","countryCurrency","currencySymbol","geSalesPrice","countryCoefficientIncludeVAT","countryVATRate","merchantTaxRate","currenyRate","coefficientRate","useCountryVAT","globaleRoundingRanges","scrollAnimate","parentSelector","fieldErrors","clearPreviousErrors","errorHtml","firstFocusableEl","lastFocusableEl","linkElements","payload","fields","feedbackElement","prepend","receivedMsgHeading","receivedMsgBody","mobile","returnUrl","buttonText","clearResetForm","$results","$updates","getContent","showContentTab","include","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","getter","__esModule","definition","g","globalThis","Function","toStringTag"],"sourceRoot":""}