{"version":3,"file":"modernProductDetails.js","names":["document","addEventListener","attributeSelect","selectedValueUrl","$productContainer","$","trigger","url","container","ajax","method","success","data","response","isVaraint","isChoiceOfBonusProducts","parents","length","product","variationAttributes","attrs","msgs","attrsWithSwatches","forEach","attr","indexOf","id","values","attrValue","$attrValue","find","value","$swatchButton","parent","selected","addClass","siblings","text","assistiveSelectedText","removeClass","empty","removeAttr","selectable","processSwatchValues","$attr","$defaultOption","resetUrl","processNonSwatchValues","updateAttrs","resources","productType","readyToOrder","imgs","carousel","carouselId","append","i","alt","parseInt","index","title","appendTo","first","detach","createCarousel","images","large","replaceWith","price","html","promotionsHtml","availabilityValue","availabilityMessages","availability","messages","message","info_selectforstock","updateAvailability","attributes","attributeGroup","ID","attribute","label","getAttributesHtml","handleVariantResponse","optionsHtml","updateOptions","quantities","map","quantity","join","getQuantitySelector","updateQuantities","querySelectorAll","element","closest","isDisabled","hasAttribute","style","opacity","pointerEvents","cursor","parentColorDisabled","classList","contains","emblem","Imagewrappercontainer","querySelector","upButton","downButton","add","remove","firstChild","removeChild","wrapper","createElement","transform","image","div","border","setAttribute","img","src","mixBlendMode","appendChild","productImages","imageContainer","imageSelected","this","getAttribute","attachImageListeners","updateImage","spinner","stop","error","$el","quantitySelected","quantitySelectedModal","quantitySelectedPDP","undefined","val","getChildProducts","childProducts","each","push","pid","JSON","stringify","getOptions","options","$elOption","urlValue","selectedValueId","optionId","toArray","on","e","eq","dataUrl","editPid","URLSearchParams","window","location","search","get","css","selectedVariant","inCart","err","click","scrollTop","engravingline","input","idType","trim","editProductID","key","type","redirectUrl","sessionStorage","setItem","productId","href","xhr","status","preventDefault","params","linkedVariantElementId","linkedVariantElement","getElementById","currentTarget","addToCartUrl","pidsObj","setPids","hasClass","qty","getPidValue","form","messageType","newBonusDiscountLineItem","Object","keys","start","bonusUrl","bonusChoiceRuleBased","showProductsUrlRuleBased","showProductsUrlListBased","htmlString","maxBonusItems","uuid","pliUUID","pageSize","labels","selectprods","dataType","parsedHtml","parseHtml","renderedTemplate","enterDialogMessage","closeButtonText","body","footer","modal","chooseBonusProducts","setTimeout","handlePostCartAdd","reportingURL","animate","offset","top","cartURL"],"sources":["product/modernProductDetails.js"],"sourcesContent":["document.addEventListener(\"DOMContentLoaded\", function() {\n\n function getLinkedVariantImage(params) {\n $.ajax({\n url: params,\n method: \"GET\",\n success: function(data) {\n if (data.product.images.emblem && data.product.images.emblem.length > 0) {\n document.getElementById(\"emblemEngrave\").src = data.product.images.emblem[0].url;\n }\n // $(\".pdpLoader\").hide();\n },\n error: function() {\n $.spinner().stop();\n }\n });\n }\n /**\n * updates the product view when a product attribute is selected or deselected or when\n * changing quantity\n * @param {string} selectedValueUrl - the Url for the selected variation value\n * @param {jQuery} $productContainer - DOM element for current product\n */\n function attributeSelect(selectedValueUrl, $productContainer) {\n // $(\".pdpLoader\").show();\n if (selectedValueUrl) {\n $(\"body\").trigger(\"product:beforeAttributeSelect\", {\n url: selectedValueUrl,\n container: $productContainer\n });\n\n $.ajax({\n url: selectedValueUrl,\n method: \"GET\",\n success: function(data) {\n handleVariantResponse(data, $productContainer);\n updateOptions(data.product.optionsHtml, $productContainer);\n updateQuantities(data.product.quantities, $productContainer);\n hideDisabledAttributes();\n updateImage(data.product.images.large, data.product.images.emblem);\n $(\"body\").trigger(\"product:afterAttributeSelect\", {\n data: data,\n container: $productContainer\n });\n $.spinner().stop();\n // $(\".pdpLoader\").hide();\n },\n error: function() {\n $.spinner().stop();\n }\n });\n }\n }\n\n function attachImageListeners() {\n const imagesWrapper = document.querySelector(\".images-wrapper\");\n const productImages = imagesWrapper.querySelectorAll(\n \".product-colors-image\"\n );\n\n // Handle product image selection\n productImages.forEach(function(imageContainer) {\n imageContainer.addEventListener(\"click\", function() {\n // Update selected image\n const imageSelected = this.querySelector(\"img\").getAttribute(\"src\");\n document\n .querySelector(\".Product-image img\")\n .setAttribute(\"src\", imageSelected);\n\n // Remove border from all images\n productImages.forEach(function(img) {\n img.classList.remove(\"product-colors-image-border\");\n });\n // Add border to the selected image\n this.classList.add(\"product-colors-image-border\");\n });\n });\n }\n\n function updateImage(images, emblem) {\n if (emblem && emblem.length > 0 && emblem[0].url) {\n $(\"#emblemQr\").attr(\"src\", emblem[0].url);\n }\n // Select the existing image wrapper container\n const Imagewrappercontainer = document.querySelector(\n \".images-wrapper-container\"\n );\n const upButton = document.querySelector(\".up-button\");\n const downButton = document.querySelector(\".down-button\");\n if (images.length <= 5) {\n if (upButton) upButton.classList.add(\"d-none\");\n if (downButton) downButton.classList.add(\"d-none\");\n } else {\n if (upButton) upButton.classList.remove(\"d-none\");\n if (downButton) downButton.classList.remove(\"d-none\");\n }\n\n // Remove all existing images\n while (Imagewrappercontainer.firstChild) {\n Imagewrappercontainer.removeChild(Imagewrappercontainer.firstChild);\n }\n\n // Create the new wrapper element\n const wrapper = document.createElement(\"div\");\n wrapper.classList.add(\"images-wrapper\");\n wrapper.style.transform = \"translateY(0px)\";\n\n // Loop through the images array and create elements dynamically\n images.forEach(function(image) {\n const div = document.createElement(\"div\");\n div.classList.add(\"product-colors-image\");\n if (image.border) {\n div.classList.add(\"product-colors-image-border\");\n }\n div.setAttribute(\"role\", \"listbox\");\n\n const img = document.createElement(\"img\");\n img.src = image.url;\n img.alt = image.alt;\n img.classList.add(\"p-image\");\n img.setAttribute(\"itemprop\", \"image\");\n img.style.mixBlendMode = \"darken\";\n\n div.appendChild(img);\n wrapper.appendChild(div);\n });\n\n // Append the new wrapper to the Imagewrappercontainer\n Imagewrappercontainer.appendChild(wrapper);\n attachImageListeners();\n }\n\n function hideDisabledAttributes() {\n // Hide and disable sizes which is not available\n document\n .querySelectorAll(\".size-custom-attribute\")\n .forEach(function(element) {\n var parent = element.closest(\".customize-size-container\");\n if (!parent) return;\n\n const isDisabled = element.hasAttribute(\"disabled\");\n parent.style.opacity = isDisabled ? \"0.5\" : \"\";\n parent.style.pointerEvents = isDisabled ? \"none\" : \"\";\n parent.style.cursor = isDisabled ? \"not-allowed\" : \"\";\n });\n\n // Hide and disable color options which is not available\n document.querySelectorAll('.customize-color-container').forEach(function(parent) {\n const parentColorDisabled = parent.classList.contains('unselectable');\n if (!parent) return;\n parent.style.opacity = parentColorDisabled ? '0.5' : '';\n parent.style.pointerEvents = parentColorDisabled ? 'none' : '';\n parent.style.cursor = parentColorDisabled ? 'not-allowed' : '';\n });\n }\n\n /**\n * @typedef OptionSelectionResponse\n * @type Object\n * @property {string} priceHtml - Updated price HTML code\n * @property {Object} options - Updated Options\n * @property {string} options.id - Option ID\n * @property {UpdatedOptionValue[]} options.values - Option values\n */\n\n /**\n * Updates DOM using post-option selection Ajax response\n *\n * @param {OptionSelectionResponse} optionsHtml - Ajax response optionsHtml from selecting a product option\n * @param {jQuery} $productContainer - DOM element for current product\n */\n function updateOptions(optionsHtml, $productContainer) {\n // Update options\n $productContainer.find(\".product-options\").empty().html(optionsHtml);\n }\n\n /**\n * @typespec UpdatedQuantity\n * @type Object\n * @property {boolean} selected - Whether the quantity has been selected\n * @property {string} value - The number of products to purchase\n * @property {string} url - Compiled URL that specifies variation attributes, product ID, options,\n * etc.\n */\n\n /**\n * Updates the quantity DOM elements post Ajax call\n * @param {UpdatedQuantity[]} quantities -\n * @param {jQuery} $productContainer - DOM container for a given product\n */\n function updateQuantities(quantities, $productContainer) {\n if ($productContainer.parent(\".bonus-product-item\").length <= 0) {\n var optionsHtml = quantities\n .map(function(quantity) {\n var selected = quantity.selected ? \" selected \" : \"\";\n return (\n '\"\n );\n })\n .join(\"\");\n getQuantitySelector($productContainer).empty().html(optionsHtml);\n }\n }\n /**\n * Retrieve contextual quantity selector\n * @param {jquery} $el - DOM container for the relevant quantity\n * @return {jquery} - quantity selector DOM container\n */\n function getQuantitySelector($el) {\n var quantitySelected;\n if ($el && $(\".set-items\").length) {\n quantitySelected = $($el)\n .closest(\".modern-product-detail\")\n .find(\".quantity-select\");\n } else if ($el && $(\".product-bundle\").length) {\n var quantitySelectedModal = $($el)\n .closest(\".modal-footer\")\n .find(\".quantity-select\");\n var quantitySelectedPDP = $($el)\n .closest(\".bundle-footer\")\n .find(\".quantity-select\");\n if (quantitySelectedModal.val() === undefined) {\n quantitySelected = quantitySelectedPDP;\n } else {\n quantitySelected = quantitySelectedModal;\n }\n } else {\n quantitySelected = $(\".quantity-select\");\n }\n return quantitySelected;\n }\n /**\n * Parses JSON from Ajax call made whenever an attribute value is [de]selected\n * @param {Object} response - response from Ajax call\n * @param {Object} response.product - Product object\n * @param {string} response.product.id - Product ID\n * @param {Object[]} response.product.variationAttributes - Product attributes\n * @param {Object[]} response.product.images - Product images\n * @param {boolean} response.product.hasRequiredAttrsSelected - Flag as to whether all required\n * attributes have been selected. Used partially to\n * determine whether the Add to Cart button can be enabled\n * @param {jQuery} $productContainer - DOM element for a given product.\n */\n function handleVariantResponse(response, $productContainer) {\n var isChoiceOfBonusProducts =\n $productContainer.parents(\".choose-bonus-product-dialog\").length > 0;\n var isVaraint;\n if (response.product.variationAttributes) {\n updateAttrs(\n response.product.variationAttributes,\n $productContainer,\n response.resources\n );\n isVaraint = response.product.productType === \"variant\";\n if (isChoiceOfBonusProducts && isVaraint) {\n $productContainer\n .parent(\".bonus-product-item\")\n .data(\"pid\", response.product.id);\n\n $productContainer\n .parent(\".bonus-product-item\")\n .data(\"ready-to-order\", response.product.readyToOrder);\n }\n }\n\n // Update primary images\n var primaryImageUrls = response.product.images.large;\n createCarousel(primaryImageUrls, $productContainer);\n\n // Update pricing\n if (!isChoiceOfBonusProducts) {\n var $priceSelector = $(\".prices .price\", $productContainer).length\n ? $(\".prices .price\", $productContainer)\n : $(\".prices .price\");\n $priceSelector.replaceWith(response.product.price.html);\n }\n\n // Update promotions\n $productContainer\n .find(\".promotions\")\n .empty()\n .html(response.product.promotionsHtml);\n\n updateAvailability(response, $productContainer);\n\n if (isChoiceOfBonusProducts) {\n var $selectButton = $productContainer.find(\".select-bonus-product\");\n $selectButton.trigger(\"bonusproduct:updateSelectButton\", {\n product: response.product,\n $productContainer: $productContainer\n });\n } else {\n // Enable \"Add to Cart\" button if all required attributes have been selected\n $(\n \"button.add-to-cart, button.add-to-cart-global, button.update-cart-product-global\"\n )\n .trigger(\"product:updateAddToCart\", {\n product: response.product,\n $productContainer: $productContainer\n })\n .trigger(\"product:statusUpdate\", response.product);\n }\n\n // Update attributes\n $productContainer\n .find(\".main-attributes\")\n .empty()\n .html(getAttributesHtml(response.product.attributes));\n }\n /**\n * Generates html for product attributes section\n *\n * @param {array} attributes - list of attributes\n * @return {string} - Compiled HTML\n */\n function getAttributesHtml(attributes) {\n if (!attributes) {\n return \"\";\n }\n\n var html = \"\";\n\n attributes.forEach(function(attributeGroup) {\n if (attributeGroup.ID === \"mainAttributes\") {\n attributeGroup.attributes.forEach(function(attribute) {\n html +=\n '