{"version":3,"file":"default/js/main.js","sources":["webpack://rws/./cartridges/gtm/int_gtm_sfra/cartridge/client/default/js/gtm/init.js","webpack://rws/./cartridges/gtm/int_gtm_sfra/cartridge/client/default/js/gtm/polyfills.js","webpack://rws/./cartridges/gtm/int_gtm_sfra/cartridge/client/default/js/gtm/preprocessors.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/cart/cart.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/components/clientSideValidation.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/components/cookie.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/components/countrySelector.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/components/focus.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/components/footer.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/components/keyboardAccessibility.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/components/scrollAnimate.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/components/toolTip.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/product/base.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/thirdParty/bootstrap.js","webpack://rws/./dependencies/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/util.js","webpack://rws/./node_modules/@accessible360/accessible-slick/slick/slick.js","webpack://rws/./node_modules/bootstrap/js/src/alert.js","webpack://rws/./node_modules/bootstrap/js/src/carousel.js","webpack://rws/./node_modules/bootstrap/js/src/collapse.js","webpack://rws/./node_modules/bootstrap/js/src/modal.js","webpack://rws/./node_modules/bootstrap/js/src/scrollspy.js","webpack://rws/./node_modules/bootstrap/js/src/tab.js","webpack://rws/./node_modules/bootstrap/js/src/util.js","webpack://rws/./node_modules/intersection-observer/intersection-observer.js","webpack://rws/./node_modules/jquery-ui/ui/widget.js","webpack://rws/./node_modules/jquery-zoom/jquery.zoom.js","webpack://rws/./node_modules/jquery/dist/jquery.js","webpack://rws/./node_modules/lodash/_Symbol.js","webpack://rws/./node_modules/lodash/_baseGetTag.js","webpack://rws/./node_modules/lodash/_baseTrim.js","webpack://rws/./node_modules/lodash/_freeGlobal.js","webpack://rws/./node_modules/lodash/_getRawTag.js","webpack://rws/./node_modules/lodash/_objectToString.js","webpack://rws/./node_modules/lodash/_root.js","webpack://rws/./node_modules/lodash/_trimmedEndIndex.js","webpack://rws/./node_modules/lodash/debounce.js","webpack://rws/./node_modules/lodash/isObject.js","webpack://rws/./node_modules/lodash/isObjectLike.js","webpack://rws/./node_modules/lodash/isSymbol.js","webpack://rws/./node_modules/lodash/lodash.js","webpack://rws/./node_modules/lodash/now.js","webpack://rws/./node_modules/lodash/toNumber.js","webpack://rws/./node_modules/svgxuse/svgxuse.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/clientSideValidation.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/collapsibleItem.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/cookie.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/country-selector.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/emailSubscription.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/flyout-panel.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/footer.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/form-helpers.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/header-banner.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/image-carousel.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/legacy-component-support.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/menu.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/miniCart.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/modal.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/modalDrawer.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/orderHistoryList.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/pdp-carousel.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/refinement-tooltips.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/scrollAnimate.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/search.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/spinner.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/stickyheader.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/tabs.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/toggle.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/components/volumental.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/content/navigation.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/forms/front-end-validation.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/helpers/video-media-query.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/linkModal.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/liveagent/liveagent.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/product/base.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/product/swatchableAttribute.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/silverpop.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/util/matchBreakpoints.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/util/toggleActiveClass.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/util/urlUtils.js","webpack://rws/./cartridges/app_rws/cartridge/client/default/js/main.js"],"sourcesContent":["/* eslint no-underscore-dangle:0,no-console:0,no-unused-vars:0 */\n/**\n * @module GTM\n *\n * Google Tag Manager data layer support for Storefront Reference Architechture (SFRA)\n *\n * Assumes jQuery available on window object as this is the current methodology of\n * SFRA. If that changes to use webpack and commonjs properly this would need refactoring to\n * include it properly.\n */\n\nrequire('./polyfills');\nrequire('intersection-observer');\n\nvar preprocessors = require('./preprocessors');\nvar $ = window.jQuery;\n\nvar GDL_MARKER = /gdl:(.*?)(\\s|-)/;\n\nfunction debounce(func, wait, immediate) {\n var timeout;\n return function () {\n var context = this;\n var args = arguments;\n var later = function () {\n timeout = null;\n if (!immediate) func.apply(context, args);\n };\n var callNow = immediate && !timeout;\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n if (callNow) func.apply(context, args);\n };\n}\n\nfunction findGDLNode(parent, id) {\n var node = null;\n if (parent.childNodes) {\n for (var i = 0; i < parent.childNodes.length; i++) {\n var n = parent.childNodes[i];\n if (n.nodeType === 1) {\n var candidate = findGDLNode(n, id);\n if (candidate) {\n node = candidate;\n }\n } else if (n.nodeType === 8) {\n var match = n.textContent.match(GDL_MARKER);\n if (match && match[1] === id) {\n var elementSibling = n.nextElementSibling;\n if (!elementSibling) {\n elementSibling = n.nextSibling;\n var count = 0;\n while (!elementSibling || elementSibling.nodeType !== 1) {\n count++;\n elementSibling = elementSibling.nextSibling;\n\n if (count > 10) {\n break;\n }\n }\n }\n node = { id: match[1], node: n, element: elementSibling };\n }\n }\n }\n }\n return node;\n}\n\nfunction processDataLayer(dataLayer) {\n window.dataLayer = window.dataLayer || [];\n for (var i = 0; i < dataLayer.length; i++) {\n // The data layer is a merge within the context of the ecommerce array\n // If it is sent to the data layer we need to ensure that it is empty before adding what was sent\n if (dataLayer[i] && dataLayer[i].ecommerce) {\n window.dataLayer.push({ ecommerce: null });\n }\n window.dataLayer.push(dataLayer[i]);\n }\n}\n\nfunction enqueueDataLayerUpdate(dataLayer) {\n setTimeout(function () {\n processDataLayer(dataLayer);\n }, 0);\n}\n\nfunction GTMPageContext() {\n var i;\n var This = this;\n window._gdl = window._gdl || []; // eslint-disable-line\n var existingDataLayer = window._gdl;\n\n this.dataLayer = [];\n this.nodes = [];\n this.nodesByID = {};\n this.dataLayerByID = {};\n this.reportedImpressions = [];\n this.observedImpressions = [];\n\n window._gdl = this.dataLayer;\n\n this.io = new IntersectionObserver(this.observer.bind(this), {\n threshold: 0.5\n });\n this.io.POLL_INTERVAL = 1000;\n\n var originalPush = this.dataLayer.push;\n this.dataLayer.push = function () {\n for (var j = 0; j < arguments.length; j++) {\n var item = arguments[j];\n var node = findGDLNode(document, item.ID);\n This.addInlineDataLayer(item, node);\n }\n originalPush.apply(This.dataLayer, arguments);\n };\n\n for (i = 0; i < existingDataLayer.length; i++) {\n var dl = existingDataLayer[i];\n this.dataLayer.push(dl);\n }\n\n GTMPageContext.prototype.impressionReporterDebounced = debounce.call(this, function () {\n this.impressionReporter();\n }, 1000);\n}\n\nGTMPageContext.prototype.observer = function (entries, io) {\n for (var i = 0; i < entries.length; i++) {\n var entry = entries[i];\n if (entry.intersectionRatio <= 0) {\n continue; // eslint-disable-line\n }\n io.unobserve(entry.target);\n\n if (this.reportedImpressions.indexOf(entry.target) === -1 &&\n this.observedImpressions.indexOf(entry.target) === -1) {\n this.observedImpressions.push(entry.target);\n }\n }\n\n this.impressionReporterDebounced();\n};\n\nGTMPageContext.prototype.impressionReporter = function () {\n if (this.observedImpressions.length === 0) {\n return;\n }\n\n var _dataLayer = {\n ecommerce: {}\n };\n\n _dataLayer.event = 'impressions';\n\n var impressions = [];\n for (var i = 0; i < this.observedImpressions.length; i++) {\n var el = this.observedImpressions[i];\n var dataLayer = this.dataLayerByID[el._gtmDataLayerID];\n if (dataLayer) {\n impressions.push(dataLayer.d);\n }\n }\n\n Array.prototype.push.apply(this.reportedImpressions, this.observedImpressions);\n\n this.observedImpressions = [];\n _dataLayer.ecommerce.impressions = impressions;\n\n window.dataLayer.push(_dataLayer);\n};\n\nGTMPageContext.prototype.addInlineDataLayer = function (item, node) {\n var This = this;\n if (node) {\n if (item.e === 'impressions') {\n item.d = preprocessors.preprocessImpression(item.d, node.element);\n this.io.observe(node.element);\n\n $(node.element).on('click', 'a', function (e) {\n This.impressionReporter();\n var list = item.d.list;\n window.dataLayer.push({\n event: 'productClick',\n ecommerce: {\n click: {\n actionField: {\n list: list\n },\n products: [item.d]\n }\n }\n });\n });\n }\n\n this.nodes.push(node);\n this.nodesByID[item.ID] = node;\n node.element._gtmDataLayerID = item.ID;\n this.dataLayerByID[item.ID] = item;\n }\n};\n\n/**\n * Initialize SFRA GTM Datalayer routines\n *\n * This should only be called once per page load.\n */\nexports.init = function () {\n // Find data layer \"nodes\" rendered prior to initialization\n window.gtmPageContext = new GTMPageContext();\n\n // Listen for datalayer and contextual updates in json responses\n $(document).ajaxComplete(function (event, xhr, settings) {\n if (xhr.readyState === 4) {\n if (xhr.status === 200) {\n var contentType = xhr.getResponseHeader('content-type');\n if (contentType && contentType.indexOf('json')) {\n try {\n var rawResponse = xhr.responseText;\n var resp = JSON.parse(rawResponse);\n if (resp.GTMDataLayer) {\n enqueueDataLayerUpdate(resp.GTMDataLayer);\n }\n\n } catch (e) { //eslint-disable-line\n // JSON.parse failed is this possible?\n }\n }\n }\n }\n });\n};\n","if (!(\"nextElementSibling\" in document.documentElement)) {\n Object.defineProperty(Element.prototype, \"nextElementSibling\", {\n get: function () {\n var e = this.nextSibling;\n while (e && e.nodeType !== 1) {\n e = e.nextSibling;\n }\n return e;\n }\n });\n}\n","var $ = window.jQuery;\n\nexports.preprocessImpression = function (impression, element) {\n var position = $(element).closest('[data-gtm-current-position]').attr('data-gtm-current-position');\n var term;\n\n var dataElement = window.dataLayer.find(function (item) {\n return item.event === 'view_search_results';\n });\n\n if (position) {\n impression.index = parseInt(position, 10);\n }\n\n if (dataElement && dataElement.search_term) {\n term = JSON.parse('{\"' + decodeURI(dataElement.search_term).replace(/\"/g, '\\\\\"').replace(/&/g, '\",\"').replace(/=/g, '\":\"') + '\"}');\n\n var list = term.cgid;\n impression.item_list_id = list;\n impression.item_list_name = list.replace(/-/g, ' ').replace(/(^|\\s)\\S/g, function (name) {\n return name.toUpperCase();\n });\n }\n\n return impression;\n};\n","'use strict';\n\nvar base = require('../product/base');\nvar focusHelper = require('../components/focus');\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 */\nfunction appendToUrl(url, params) {\n var newUrl = url;\n newUrl += (newUrl.indexOf('?') !== -1 ? '&' : '?') + Object.keys(params).map(function (key) {\n return key + '=' + encodeURIComponent(params[key]);\n }).join('&');\n\n return newUrl;\n}\n\n/**\n * Checks whether the basket is valid. if invalid displays error message and disables\n * checkout button\n * @param {Object} data - AJAX response from the server\n */\nfunction validateBasket(data) {\n if (data.valid.error) {\n if (data.valid.message) {\n var errorHtml = '
' +\n '' + data.valid.message + '
';\n\n $('.cart-error').append(errorHtml);\n } else {\n $('.cart').empty().append('
' +\n '
' +\n '

' + data.resources.emptyCartMsg + '

' +\n '
' +\n '
'\n );\n $('.number-of-items').empty().append(data.resources.numberOfItems);\n $('.minicart-quantity').empty().append(data.numItems);\n $('.minicart-link').attr({\n 'aria-label': data.resources.minicartCountOfItems,\n title: data.resources.minicartCountOfItems\n });\n $('.minicart .popover').empty();\n $('.minicart .popover').removeClass('show');\n }\n\n $('.checkout-btn').addClass('disabled');\n } else {\n $('.checkout-btn').removeClass('disabled');\n }\n}\n\n/**\n * re-renders the order totals and the number of items in the cart\n * @param {Object} data - AJAX response from the server\n */\nfunction updateCartTotals(data) {\n $('.number-of-items').empty().append(data.resources.numberOfItems);\n $('.shipping-cost').empty().append(data.totals.totalShippingCost);\n $('.tax-total').empty().append(data.totals.totalTax);\n $('.grand-total').empty().append(data.totals.grandTotal);\n $('.sub-total').empty().append(data.totals.subTotal);\n $('.minicart-quantity').empty().append(data.numItems);\n $('.minicart-link').attr({\n 'aria-label': data.resources.minicartCountOfItems,\n title: data.resources.minicartCountOfItems\n });\n if (data.totals.orderLevelDiscountTotal.value > 0) {\n $('.order-discount').removeClass('hide-order-discount');\n $('.order-discount-total').empty()\n .append('- ' + data.totals.orderLevelDiscountTotal.formatted);\n } else {\n $('.order-discount').addClass('hide-order-discount');\n }\n\n if (data.totals.shippingLevelDiscountTotal.value > 0) {\n $('.shipping-discount').removeClass('hide-shipping-discount');\n $('.shipping-discount-total').empty().append('- ' +\n data.totals.shippingLevelDiscountTotal.formatted);\n } else {\n $('.shipping-discount').addClass('hide-shipping-discount');\n }\n\n data.items.forEach(function (item) {\n if (data.totals.orderLevelDiscountTotal.value > 0) {\n $('.coupons-and-promos').empty().append(data.totals.discountsHtml);\n }\n if (item.renderedPromotions) {\n $('.item-' + item.UUID).empty().append(item.renderedPromotions);\n } else {\n $('.item-' + item.UUID).empty();\n }\n $('.uuid-' + item.UUID + ' .unit-price').empty().append(item.renderedPrice);\n $('.line-item-price-' + item.UUID + ' .unit-price').empty().append(item.renderedPrice);\n $('.item-total-' + item.UUID).empty().append(item.priceTotal.renderedPrice);\n });\n}\n\n/**\n * re-renders the order totals and the number of items in the cart\n * @param {Object} message - Error message to display\n */\nfunction createErrorNotification(message) {\n var errorHtml = '
' +\n '' + message + '
';\n\n $('.cart-error').append(errorHtml);\n}\n\n/**\n * re-renders the approaching discount messages\n * @param {Object} approachingDiscounts - updated approaching discounts for the cart\n */\nfunction updateApproachingDiscounts(approachingDiscounts) {\n var html = '';\n $('.approaching-discounts').empty();\n if (approachingDiscounts.length > 0) {\n approachingDiscounts.forEach(function (item) {\n html += '
'\n + item.discountMsg + '
';\n });\n }\n $('.approaching-discounts').append(html);\n}\n\n/**\n * Updates the availability of a product line item\n * @param {Object} data - AJAX response from the server\n * @param {string} uuid - The uuid of the product line item to update\n */\nfunction updateAvailability(data, uuid) {\n var lineItem;\n var messages = '';\n\n for (var i = 0; i < data.items.length; i++) {\n if (data.items[i].UUID === uuid) {\n lineItem = data.items[i];\n break;\n }\n }\n\n if (lineItem != null) {\n $('.availability-' + lineItem.UUID).empty();\n\n if (lineItem.availability) {\n if (lineItem.availability.messages) {\n lineItem.availability.messages.forEach(function (message) {\n messages += '

' + message + '

';\n });\n }\n\n if (lineItem.availability.inStockDate) {\n messages += '

'\n + lineItem.availability.inStockDate\n + '

';\n }\n }\n\n $('.availability-' + lineItem.UUID).html(messages);\n }\n}\n\n/**\n * Finds an element in the array that matches search parameter\n * @param {array} array - array of items to search\n * @param {function} match - function that takes an element and returns a boolean indicating if the match is made\n * @returns {Object|null} - returns an element of the array that matched the query.\n */\nfunction findItem(array, match) { // eslint-disable-line no-unused-vars\n for (var i = 0, l = array.length; i < l; i++) {\n if (match.call(this, array[i])) {\n return array[i];\n }\n }\n return null;\n}\n\n/**\n * Updates details of a product line item\n * @param {Object} data - AJAX response from the server\n * @param {string} uuid - The uuid of the product line item to update\n */\nfunction updateProductDetails(data, uuid) {\n $('.card.product-info.uuid-' + uuid).replaceWith(data.renderedTemplate);\n}\n\n/**\n * Generates the modal window on the first call.\n * Customization: added aria-modal and aria-label attributes\n */\nfunction getModalHtmlElement() {\n if ($('#editProductModal').length !== 0) {\n $('#editProductModal').remove();\n }\n var htmlString = ''\n + '
'\n + ''\n + '
'\n + ''\n + '
'\n + '
'\n + ' '\n + '
'\n + '
'\n + '
'\n + '
'\n + '
'\n + '
';\n $('body').append(htmlString);\n}\n\n/**\n * Parses the html for a modal window\n * @param {string} html - representing the body and footer of the modal window\n *\n * @return {Object} - Object with properties body and footer.\n */\nfunction parseHtml(html) {\n var $html = $('
').append($.parseHTML(html));\n\n var body = $html.find('.product-quickview');\n var footer = $html.find('.modal-footer').children();\n\n return { body: body, footer: footer };\n}\n\n/**\n * replaces the content in the modal window for product variation to be edited.\n * @param {string} editProductUrl - url to be used to retrieve a new product model\n */\nfunction fillModalElement(editProductUrl) {\n $('.modal-body').spinner().start();\n $.ajax({\n url: editProductUrl,\n method: 'GET',\n dataType: 'json',\n success: function (data) {\n var parsedHtml = parseHtml(data.renderedTemplate);\n\n $('#editProductModal .modal-body').empty();\n $('#editProductModal .modal-body').html(parsedHtml.body);\n $('#editProductModal .modal-footer').html(parsedHtml.footer);\n $('#editProductModal .modal-header .close .sr-only').text(data.closeButtonText);\n $('#editProductModal .enter-message').text(data.enterDialogMessage);\n $('#editProductModal').modal('show');\n $('body').trigger('editproductmodal:ready');\n $.spinner().stop();\n },\n error: function () {\n $.spinner().stop();\n }\n });\n}\n\n/**\n * replace content of modal\n * @param {string} actionUrl - url to be used to remove product\n * @param {string} productID - pid\n * @param {string} productName - product name\n * @param {string} uuid - uuid\n */\nfunction confirmDelete(actionUrl, productID, productName, uuid) {\n var $deleteConfirmBtn = $('.cart-delete-confirmation-btn');\n var $productToRemoveSpan = $('.product-to-remove');\n\n $deleteConfirmBtn.data('pid', productID);\n $deleteConfirmBtn.data('action', actionUrl);\n $deleteConfirmBtn.data('uuid', uuid);\n\n $productToRemoveSpan.empty().append(productName);\n}\n\nmodule.exports = function () {\n $('body').on('click', '.remove-product', function (e) {\n e.preventDefault();\n\n var actionUrl = $(this).data('action');\n var productID = $(this).data('pid');\n var productName = $(this).data('name');\n var uuid = $(this).data('uuid');\n confirmDelete(actionUrl, productID, productName, uuid);\n });\n\n $('body').on('afterRemoveFromCart', function (e, data) {\n e.preventDefault();\n confirmDelete(data.actionUrl, data.productID, data.productName, data.uuid);\n });\n\n $('.optional-promo').click(function (e) {\n e.preventDefault();\n $('.promo-code-form').toggle();\n });\n\n $('body').on('click', '.cart-delete-confirmation-btn', function (e) {\n e.preventDefault();\n\n var productID = $(this).data('pid');\n var url = $(this).data('action');\n var uuid = $(this).data('uuid');\n var urlParams = {\n pid: productID,\n uuid: uuid\n };\n\n url = appendToUrl(url, urlParams);\n\n $('body > .modal-backdrop').remove();\n\n $.spinner().start();\n\n $('body').trigger('cart:beforeUpdate');\n\n $.ajax({\n url: url,\n type: 'get',\n dataType: 'json',\n success: function (data) {\n if (data.basket.items.length === 0) {\n $('.cart').empty().append('
' +\n '
' +\n '

' + data.basket.resources.emptyCartMsg + '

' +\n '
' +\n '
'\n );\n $('.number-of-items').empty().append(data.basket.resources.numberOfItems);\n $('.minicart-quantity').empty().append(data.basket.numItems);\n $('.minicart-link').attr({\n 'aria-label': data.basket.resources.minicartCountOfItems,\n title: data.basket.resources.minicartCountOfItems\n });\n $('.minicart .popover').empty();\n $('.minicart .popover').removeClass('show');\n $('body').removeClass('modal-open');\n $('html').removeClass('veiled');\n } else {\n if (data.toBeDeletedUUIDs && data.toBeDeletedUUIDs.length > 0) {\n for (var i = 0; i < data.toBeDeletedUUIDs.length; i++) {\n $('.uuid-' + data.toBeDeletedUUIDs[i]).remove();\n }\n }\n $('.uuid-' + uuid).remove();\n if (!data.basket.hasBonusProduct) {\n $('.bonus-product').remove();\n }\n $('.coupons-and-promos').empty().append(data.basket.totals.discountsHtml);\n updateCartTotals(data.basket);\n updateApproachingDiscounts(data.basket.approachingDiscounts);\n $('body').trigger('setShippingMethodSelection', data.basket);\n validateBasket(data.basket);\n }\n $('body').trigger('cart:update', data);\n $.spinner().stop();\n },\n error: function (err) {\n if (err.responseJSON.redirectUrl) {\n window.location.href = err.responseJSON.redirectUrl;\n } else {\n createErrorNotification(err.responseJSON.errorMessage);\n $.spinner().stop();\n }\n }\n });\n });\n\n $('body').on('change', '.quantity-form > .quantity', function () {\n var preSelectQty = $(this).data('pre-select-qty');\n var quantity = $(this).val();\n var productID = $(this).data('pid');\n var url = $(this).data('action');\n var uuid = $(this).data('uuid');\n\n var urlParams = {\n pid: productID,\n quantity: quantity,\n uuid: uuid\n };\n url = appendToUrl(url, urlParams);\n\n $(this).parents('.card').spinner().start();\n\n $('body').trigger('cart:beforeUpdate');\n\n $.ajax({\n url: url,\n type: 'get',\n context: this,\n dataType: 'json',\n success: function (data) {\n $('.quantity[data-uuid=\"' + uuid + '\"]').val(quantity);\n $('.coupons-and-promos').empty().append(data.totals.discountsHtml);\n updateCartTotals(data);\n updateApproachingDiscounts(data.approachingDiscounts);\n updateAvailability(data, uuid);\n validateBasket(data);\n $(this).data('pre-select-qty', quantity);\n\n $('body').trigger('cart:update', data);\n\n $.spinner().stop();\n if ($(this).parents('.product-info').hasClass('bonus-product-line-item') && $('.cart-page').length) {\n location.reload();\n }\n },\n error: function (err) {\n if (err.responseJSON.redirectUrl) {\n window.location.href = err.responseJSON.redirectUrl;\n } else {\n createErrorNotification(err.responseJSON.errorMessage);\n $(this).val(parseInt(preSelectQty, 10));\n $.spinner().stop();\n }\n }\n });\n });\n\n $('.shippingMethods').change(function () {\n var url = $(this).attr('data-actionUrl');\n var urlParams = {\n methodID: $(this).find(':selected').attr('data-shipping-id')\n };\n // url = appendToUrl(url, urlParams);\n\n $('.totals').spinner().start();\n $('body').trigger('cart:beforeShippingMethodSelected');\n $.ajax({\n url: url,\n type: 'post',\n dataType: 'json',\n data: urlParams,\n success: function (data) {\n if (data.error) {\n window.location.href = data.redirectUrl;\n } else {\n $('.coupons-and-promos').empty().append(data.totals.discountsHtml);\n updateCartTotals(data);\n updateApproachingDiscounts(data.approachingDiscounts);\n validateBasket(data);\n }\n\n $('body').trigger('cart:shippingMethodSelected', data);\n $.spinner().stop();\n },\n error: function (err) {\n if (err.redirectUrl) {\n window.location.href = err.redirectUrl;\n } else {\n createErrorNotification(err.responseJSON.errorMessage);\n $.spinner().stop();\n }\n }\n });\n });\n\n $('.promo-code-form').submit(function (e) {\n e.preventDefault();\n $.spinner().start();\n $('.coupon-missing-error').hide();\n $('.coupon-error-message').empty();\n if (!$('.coupon-code-field').val()) {\n // Customization: Added input focus on error\n $('.promo-code-form .form-control').addClass('is-invalid').focus();\n $('.promo-code-form .form-control').attr('aria-describedby', 'missingCouponCode');\n $('.coupon-missing-error').show();\n $.spinner().stop();\n return false;\n }\n var $form = $('.promo-code-form');\n $('.promo-code-form .form-control').removeClass('is-invalid');\n $('.coupon-error-message').empty();\n $('body').trigger('promotion:beforeUpdate');\n\n $.ajax({\n url: $form.attr('action'),\n type: 'GET',\n dataType: 'json',\n data: $form.serialize(),\n success: function (data) {\n if (data.error) {\n // Customization: Added input focus on error\n $('.promo-code-form .form-control').addClass('is-invalid').focus();\n $('.promo-code-form .form-control').attr('aria-describedby', 'invalidCouponCode');\n $('.coupon-error-message').empty().append(data.errorMessage);\n $('body').trigger('promotion:error', data);\n } else {\n $('.coupons-and-promos').empty().append(data.totals.discountsHtml);\n updateCartTotals(data);\n updateApproachingDiscounts(data.approachingDiscounts);\n validateBasket(data);\n $('body').trigger('promotion:success', data);\n }\n $('.coupon-code-field').val('');\n $.spinner().stop();\n },\n error: function (err) {\n $('body').trigger('promotion:error', err);\n if (err.responseJSON.redirectUrl) {\n window.location.href = err.responseJSON.redirectUrl;\n } else {\n createErrorNotification(err.errorMessage);\n $.spinner().stop();\n }\n }\n });\n return false;\n });\n\n $('body').on('click', '.remove-coupon', function (e) {\n e.preventDefault();\n\n var couponCode = $(this).data('code');\n var uuid = $(this).data('uuid');\n var $deleteConfirmBtn = $('.delete-coupon-confirmation-btn');\n var $productToRemoveSpan = $('.coupon-to-remove');\n\n $deleteConfirmBtn.data('uuid', uuid);\n $deleteConfirmBtn.data('code', couponCode);\n\n $productToRemoveSpan.empty().append(couponCode);\n });\n\n $('body').on('click', '.delete-coupon-confirmation-btn', function (e) {\n e.preventDefault();\n\n var url = $(this).data('action');\n var uuid = $(this).data('uuid');\n var couponCode = $(this).data('code');\n var urlParams = {\n code: couponCode,\n uuid: uuid\n };\n\n url = appendToUrl(url, urlParams);\n\n $('body > .modal-backdrop').remove();\n\n $.spinner().start();\n $('body').trigger('promotion:beforeUpdate');\n $.ajax({\n url: url,\n type: 'get',\n dataType: 'json',\n success: function (data) {\n $('.coupon-uuid-' + uuid).remove();\n updateCartTotals(data);\n updateApproachingDiscounts(data.approachingDiscounts);\n validateBasket(data);\n $.spinner().stop();\n $('body').trigger('promotion:success', data);\n },\n error: function (err) {\n $('body').trigger('promotion:error', err);\n if (err.responseJSON.redirectUrl) {\n window.location.href = err.responseJSON.redirectUrl;\n } else {\n createErrorNotification(err.responseJSON.errorMessage);\n $.spinner().stop();\n }\n }\n });\n });\n $('body').on('click', '.cart-page .bonus-product-button', function () {\n $.spinner().start();\n $(this).addClass('launched-modal');\n $.ajax({\n url: $(this).data('url'),\n method: 'GET',\n dataType: 'json',\n success: function (data) {\n base.methods.editBonusProducts(data);\n $.spinner().stop();\n },\n error: function () {\n $.spinner().stop();\n }\n });\n });\n\n $('body').on('hidden.bs.modal', '#chooseBonusProductModal', function () {\n $('#chooseBonusProductModal').remove();\n $('.modal-backdrop').remove();\n $('body').removeClass('modal-open');\n\n if ($('.cart-page').length) {\n $('.launched-modal .btn-outline-primary').trigger('focus');\n $('.launched-modal').removeClass('launched-modal');\n } else {\n $('.product-detail .add-to-cart').focus();\n }\n });\n\n $('body').on('click', '.cart-page .product-edit .edit, .cart-page .bundle-edit .edit', function (e) {\n e.preventDefault();\n\n var editProductUrl = $(this).attr('href');\n getModalHtmlElement();\n fillModalElement(editProductUrl);\n });\n\n $('body').on('shown.bs.modal', '#editProductModal', function () {\n $('#editProductModal').siblings().attr('aria-hidden', 'true');\n $('#editProductModal .close').focus();\n });\n\n $('body').on('hidden.bs.modal', '#editProductModal', function () {\n $('#editProductModal').siblings().attr('aria-hidden', 'false');\n });\n\n $('body').on('keydown', '#editProductModal', function (e) {\n var focusParams = {\n event: e,\n containerSelector: '#editProductModal',\n firstElementSelector: '.close',\n lastElementSelector: '.update-cart-product-global',\n nextToLastElementSelector: '.modal-footer .quantity-select'\n };\n focusHelper.setTabNextFocus(focusParams);\n });\n\n $('body').on('product:updateAddToCart', function (e, response) {\n // update global add to cart (single products, bundles)\n var dialog = $(response.$productContainer)\n .closest('.quick-view-dialog');\n\n $('.update-cart-product-global', dialog).attr('disabled',\n !$('.global-availability', dialog).data('ready-to-order')\n || !$('.global-availability', dialog).data('available')\n );\n });\n\n $('body').on('product:updateAvailability', function (e, response) {\n // bundle individual products\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 var dialog = $(response.$productContainer)\n .closest('.quick-view-dialog');\n\n if ($('.product-availability', dialog).length) {\n // bundle all products\n var allAvailable = $('.product-availability', dialog).toArray()\n .every(function (item) { return $(item).data('available'); });\n\n var allReady = $('.product-availability', dialog).toArray()\n .every(function (item) { return $(item).data('ready-to-order'); });\n\n $('.global-availability', dialog)\n .data('ready-to-order', allReady)\n .data('available', allAvailable);\n\n $('.global-availability .availability-msg', dialog).empty()\n .html(allReady ? response.message : response.resources.info_selectforstock);\n } else {\n // single product\n $('.global-availability', dialog)\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 $('body').on('product:afterAttributeSelect', function (e, response) {\n if ($('.modal.show .product-quickview .bundle-items').length) {\n $('.modal.show').find(response.container).data('pid', response.data.product.id);\n $('.modal.show').find(response.container).find('.product-id').text(response.data.product.id);\n } else {\n $('.modal.show .product-quickview').data('pid', response.data.product.id);\n }\n });\n\n $('body').on('change', '.quantity-select', function () {\n var selectedQuantity = $(this).val();\n $('.modal.show .update-cart-url').data('selected-quantity', selectedQuantity);\n });\n\n $('body').on('change', '.options-select', function () {\n var selectedOptionValueId = $(this).children('option:selected').data('value-id');\n $('.modal.show .update-cart-url').data('selected-option', selectedOptionValueId);\n });\n\n $('body').on('click', '.update-cart-product-global', function (e) {\n e.preventDefault();\n\n var updateProductUrl = $(this).closest('.cart-and-ipay').find('.update-cart-url').val();\n var selectedQuantity = $(this).closest('.cart-and-ipay').find('.update-cart-url').data('selected-quantity');\n var selectedOptionValueId = $(this).closest('.cart-and-ipay').find('.update-cart-url').data('selected-option');\n var uuid = $(this).closest('.cart-and-ipay').find('.update-cart-url').data('uuid');\n\n var form = {\n uuid: uuid,\n pid: base.getPidValue($(this)),\n quantity: selectedQuantity,\n selectedOptionValueId: selectedOptionValueId\n };\n\n $(this).parents('.card').spinner().start();\n\n $('body').trigger('cart:beforeUpdate');\n\n if (updateProductUrl) {\n $.ajax({\n url: updateProductUrl,\n type: 'post',\n context: this,\n data: form,\n dataType: 'json',\n success: function (data) {\n $('#editProductModal').modal('hide');\n\n $('.coupons-and-promos').empty().append(data.cartModel.totals.discountsHtml);\n updateCartTotals(data.cartModel);\n updateApproachingDiscounts(data.cartModel.approachingDiscounts);\n updateAvailability(data.cartModel, uuid);\n updateProductDetails(data, uuid);\n\n if (data.uuidToBeDeleted) {\n $('.uuid-' + data.uuidToBeDeleted).remove();\n }\n\n validateBasket(data.cartModel);\n\n $('body').trigger('cart:update', data);\n\n $.spinner().stop();\n },\n error: function (err) {\n if (err.responseJSON.redirectUrl) {\n window.location.href = err.responseJSON.redirectUrl;\n } else {\n createErrorNotification(err.responseJSON.errorMessage);\n $.spinner().stop();\n }\n }\n });\n }\n });\n\n base.selectAttribute();\n base.colorAttribute();\n base.removeBonusProduct();\n base.selectBonusProduct();\n base.enableBonusProductSelection();\n base.showMoreBonusProducts();\n base.addBonusProductsToCart();\n base.focusChooseBonusProductModal();\n base.trapChooseBonusProductModalFocus();\n base.onClosingChooseBonusProductModal();\n};\n","'use strict';\n\n/**\n * Validate whole form. Requires `this` to be set to form object\n * @param {jQuery.event} event - Event to be canceled if form is invalid.\n * @returns {boolean} - Flag to indicate if form is valid\n */\nfunction validateForm(event) {\n var valid = true;\n if (this.checkValidity && !this.checkValidity()) {\n // safari\n valid = false;\n if (event) {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n }\n $(this).find('input, select').each(function () {\n if (!this.validity.valid) {\n $(this).trigger('invalid', this.validity);\n }\n });\n }\n return valid;\n}\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 clearForm(form) {\n $(form).find('.form-control.is-invalid').removeClass('is-invalid');\n}\n\nmodule.exports = {\n invalid: function () {\n $('form input, form select').on('invalid', function (e) {\n e.preventDefault();\n this.setCustomValidity('');\n if (!this.validity.valid) {\n var validationMessage = this.validationMessage;\n $(this).addClass('is-invalid');\n if (this.validity.patternMismatch && $(this).data('pattern-mismatch')) {\n validationMessage = $(this).data('pattern-mismatch');\n }\n if ((this.validity.rangeOverflow || this.validity.rangeUnderflow)\n && $(this).data('range-error')) {\n validationMessage = $(this).data('range-error');\n }\n if ((this.validity.tooLong || this.validity.tooShort)\n && $(this).data('range-error')) {\n validationMessage = $(this).data('range-error');\n }\n if (this.validity.valueMissing && $(this).data('missing-error')) {\n validationMessage = $(this).data('missing-error');\n }\n $(this).parents('.form-group').find('.invalid-feedback')\n .text(validationMessage);\n }\n });\n },\n\n submit: function () {\n $('form').on('submit', function (e) {\n return validateForm.call(this, e);\n });\n },\n\n buttonClick: function () {\n $('form button[type=\"submit\"], form input[type=\"submit\"]').on('click', function () {\n // clear all errors when trying to submit the form\n clearForm($(this).parents('form'));\n });\n },\n\n functions: {\n validateForm: function (form, event) {\n validateForm.call($(form), event || null);\n },\n clearForm: clearForm\n }\n};\n","'use strict';\n\n/**\n * Get cookie value by cookie name from browser\n * @param {string} cookieName - name of the cookie\n * @returns {string} cookie value of the found cookie name\n */\nfunction getCookie(cookieName) {\n var name = cookieName + '=';\n var decodedCookie = decodeURIComponent(document.cookie);\n var cookieArray = decodedCookie.split(';');\n for (var i = 0; i < cookieArray.length; i++) {\n var cookieItem = cookieArray[i];\n while (cookieItem.charAt(0) === ' ') {\n cookieItem = cookieItem.substring(1);\n }\n if (cookieItem.indexOf(name) === 0) {\n return cookieItem.substring(name.length, cookieItem.length);\n }\n }\n return '';\n}\n\nmodule.exports = function () {\n if ($('.valid-cookie-warning').length > 0) {\n var previousSessionID = window.localStorage.getItem('previousSid');\n var currentSessionID = getCookie('sid');\n if (!previousSessionID && currentSessionID) {\n // When a user first time visit the home page,\n // set the previousSessionID to currentSessionID\n // and Show the cookie alert\n previousSessionID = currentSessionID;\n window.localStorage.setItem('previousSid', previousSessionID);\n $('.cookie-warning-messaging').show();\n } else if (previousSessionID && previousSessionID === currentSessionID) {\n // Hide the cookie alert if user is in the same session\n $('.cookie-warning-messaging').hide();\n } else {\n // Clear the previousSessionID from localStorage\n // when user session is changed or expired\n window.localStorage.removeItem('previousSid');\n }\n }\n};\n","'use strict';\n\nvar keyboardAccessibility = require('./keyboardAccessibility');\n\nmodule.exports = function () {\n $('.country-selector a').click(function (e) {\n e.preventDefault();\n var action = $('.page').data('action');\n var localeCode = $(this).data('locale');\n var localeCurrencyCode = $(this).data('currencycode');\n var queryString = $('.page').data('querystring');\n var url = $('.country-selector').data('url');\n\n $.ajax({\n url: url,\n type: 'get',\n dataType: 'json',\n data: {\n code: localeCode,\n queryString: queryString,\n CurrencyCode: localeCurrencyCode,\n action: action\n },\n success: function (response) {\n $.spinner().stop();\n if (response && response.redirectUrl) {\n window.location.href = response.redirectUrl;\n }\n },\n error: function () {\n $.spinner().stop();\n }\n });\n });\n\n keyboardAccessibility('.navbar-header .country-selector',\n {\n 40: function ($countryOptions) { // down\n if ($(this).is(':focus')) {\n $countryOptions.first().focus();\n } else {\n $(':focus').next().focus();\n }\n },\n 38: function ($countryOptions) { // up\n if ($countryOptions.first().is(':focus') || $(this).is(':focus')) {\n $(this).focus();\n $(this).removeClass('show');\n } else {\n $(':focus').prev().focus();\n }\n },\n 27: function () { // escape\n $(this).focus();\n $(this).removeClass('show').children('.dropdown-menu').removeClass('show');\n },\n 9: function () { // tab\n $(this).removeClass('show').children('.dropdown-menu').removeClass('show');\n }\n },\n function () {\n if (!($(this).hasClass('show'))) {\n $(this).addClass('show');\n }\n return $(this).find('.dropdown-country-selector').children('a');\n }\n );\n\n $('.navbar-header .country-selector').on('focusin', function () {\n $(this).addClass('show').children('.dropdown-menu').addClass('show');\n });\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\nvar scrollAnimate = require('./scrollAnimate');\n\n/**\n * appends params to a url\n * @param {string} data - data returned from the server's ajax call\n * @param {Object} button - button that was clicked for email sign-up\n */\nfunction displayMessage(data, button) {\n $.spinner().stop();\n var status;\n if (data.success) {\n status = 'alert-success';\n } else {\n status = 'alert-danger';\n }\n\n if ($('.email-signup-message').length === 0) {\n $('body').append(\n '
'\n );\n }\n $('.email-signup-message')\n .append('
' + data.msg + '
');\n\n setTimeout(function () {\n $('.email-signup-message').remove();\n button.removeAttr('disabled');\n }, 3000);\n}\n\nmodule.exports = function () {\n $('.back-to-top').click(function () {\n scrollAnimate();\n });\n\n $('.subscribe-email').on('click', function (e) {\n e.preventDefault();\n var url = $(this).data('href');\n var button = $(this);\n var emailId = $('input[name=hpEmailSignUp]').val();\n $.spinner().start();\n $(this).attr('disabled', true);\n $.ajax({\n url: url,\n type: 'post',\n dataType: 'json',\n data: {\n emailId: emailId\n },\n success: function (data) {\n displayMessage(data, button);\n },\n error: function (err) {\n displayMessage(err, button);\n }\n });\n });\n};\n","'use strict';\n\n// Customization: Added Enter key (13)\n\nmodule.exports = function (selector, keyFunctions, preFunction) {\n $(selector).on('keydown', function (e) {\n var key = e.which;\n var supportedKeyCodes = [37, 38, 39, 40, 27, 13];\n if (supportedKeyCodes.indexOf(key) >= 0) {\n e.preventDefault();\n }\n var returnedScope = preFunction.call(this);\n if (keyFunctions[key]) {\n keyFunctions[key].call(this, returnedScope);\n }\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\nmodule.exports = function () {\n $('.info-icon').on('mouseenter focusin', function () {\n $(this).find('.tooltip').removeClass('d-none');\n });\n\n $('.info-icon').on('mouseleave focusout', function () {\n $(this).find('.tooltip').addClass('d-none');\n });\n};\n","'use strict';\nvar focusHelper = require('../components/focus');\n\n/**\n * Retrieves the relevant pid value\n * @param {jquery} $el - DOM container for a given add to cart button\n * @return {string} - value to be used when adding product to cart\n */\nfunction getPidValue($el) {\n var pid;\n\n if ($('#quickViewModal').hasClass('show') && !$('.product-set').length) {\n pid = $($el).closest('.modal-content').find('.product-quickview').data('pid');\n } else if ($('.product-set-detail').length || $('.product-set').length) {\n pid = $($el).closest('.product-detail').find('.product-id').text();\n } else {\n pid = $('.product-detail:not(\".bundle-item\")').data('pid');\n }\n\n return pid;\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 */\nfunction getQuantitySelector($el) {\n var quantitySelected;\n if ($el && $('.set-items').length) {\n quantitySelected = $($el).closest('.product-detail').find('.quantity-select');\n } else if ($el && $('.product-bundle').length) {\n var quantitySelectedModal = $($el).closest('.modal-footer').find('.quantity-select');\n var quantitySelectedPDP = $($el).closest('.bundle-footer').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/**\n * Retrieves the value associated with the Quantity pull-down menu\n * @param {jquery} $el - DOM container for the relevant quantity\n * @return {string} - value found in the quantity input\n */\nfunction getQuantitySelected($el) {\n return getQuantitySelector($el).val();\n}\n\n/**\n * Process the attribute values for an attribute that has image swatches\n *\n * @param {Object} attr - Attribute\n * @param {string} attr.id - Attribute ID\n * @param {Object[]} attr.values - Array of attribute value objects\n * @param {string} attr.values.value - Attribute coded value\n * @param {string} attr.values.url - URL to de/select an attribute value of the product\n * @param {boolean} attr.values.isSelectable - Flag as to whether an attribute value can be\n * selected. If there is no variant that corresponds to a specific combination of attribute\n * values, an attribute may be disabled in the Product Detail Page\n * @param {jQuery} $productContainer - DOM container for a given product\n * @param {Object} msgs - object containing resource messages\n */\nfunction processSwatchValues(attr, $productContainer, msgs) {\n attr.values.forEach(function (attrValue) {\n var $attrValue = $productContainer.find('[data-attr=\"' + attr.id + '\"] [data-attr-value=\"' +\n attrValue.value + '\"]');\n var $swatchButton = $attrValue.parent();\n\n if (attrValue.selected) {\n $attrValue.addClass('selected');\n $attrValue.siblings('.selected-assistive-text').text(msgs.assistiveSelectedText);\n } else {\n $attrValue.removeClass('selected');\n $attrValue.siblings('.selected-assistive-text').empty();\n }\n\n if (attrValue.url) {\n $swatchButton.attr('data-url', attrValue.url);\n } else {\n $swatchButton.removeAttr('data-url');\n }\n\n // Disable if not selectable\n $attrValue.removeClass('selectable unselectable');\n\n $attrValue.addClass(attrValue.selectable ? 'selectable' : 'unselectable');\n });\n}\n\n/**\n * Process attribute values associated with an attribute that does not have image swatches\n *\n * @param {Object} attr - Attribute\n * @param {string} attr.id - Attribute ID\n * @param {Object[]} attr.values - Array of attribute value objects\n * @param {string} attr.values.value - Attribute coded value\n * @param {string} attr.values.url - URL to de/select an attribute value of the product\n * @param {boolean} attr.values.isSelectable - Flag as to whether an attribute value can be\n * selected. If there is no variant that corresponds to a specific combination of attribute\n * values, an attribute may be disabled in the Product Detail Page\n * @param {jQuery} $productContainer - DOM container for a given product\n */\nfunction processNonSwatchValues(attr, $productContainer) {\n var $attr = '[data-attr=\"' + attr.id + '\"]';\n var $defaultOption = $productContainer.find($attr + ' .select-' + attr.id + ' option:first');\n $defaultOption.attr('value', attr.resetUrl);\n\n attr.values.forEach(function (attrValue) {\n var $attrValue = $productContainer\n .find($attr + ' [data-attr-value=\"' + attrValue.value + '\"]');\n $attrValue.attr('value', attrValue.url)\n .removeAttr('disabled');\n\n if (!attrValue.selectable) {\n $attrValue.attr('disabled', true);\n }\n });\n}\n\n/**\n * Routes the handling of attribute processing depending on whether the attribute has image\n * swatches or not\n *\n * @param {Object} attrs - Attribute\n * @param {string} attr.id - Attribute ID\n * @param {jQuery} $productContainer - DOM element for a given product\n * @param {Object} msgs - object containing resource messages\n */\nfunction updateAttrs(attrs, $productContainer, msgs) {\n // Currently, the only attribute type that has image swatches is Color.\n var attrsWithSwatches = ['color'];\n\n attrs.forEach(function (attr) {\n if (attrsWithSwatches.indexOf(attr.id) > -1) {\n processSwatchValues(attr, $productContainer, msgs);\n } else {\n processNonSwatchValues(attr, $productContainer);\n }\n });\n}\n\n/**\n * Updates the availability status in the Product Detail Page\n *\n * @param {Object} response - Ajax response object after an\n * attribute value has been [de]selected\n * @param {jQuery} $productContainer - DOM element for a given product\n */\nfunction updateAvailability(response, $productContainer) {\n var availabilityValue = '';\n var availabilityMessages = response.product.availability.messages;\n if (!response.product.readyToOrder) {\n availabilityValue = '
  • ' + response.resources.info_selectforstock + '
  • ';\n } else {\n availabilityMessages.forEach(function (message) {\n availabilityValue += '
  • ' + message + '
  • ';\n });\n }\n\n $($productContainer).trigger('product:updateAvailability', {\n product: response.product,\n $productContainer: $productContainer,\n message: availabilityValue,\n resources: response.resources\n });\n}\n\n/**\n * Generates html for product attributes section\n *\n * @param {array} attributes - list of attributes\n * @return {string} - Compiled HTML\n */\nfunction 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 += '
    ' + attribute.label + ': '\n + attribute.value + '
    ';\n });\n }\n });\n\n return html;\n}\n\n/**\n * @typedef UpdatedOptionValue\n * @type Object\n * @property {string} id - Option value ID for look up\n * @property {string} url - Updated option value selection URL\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 */\nfunction updateOptions(optionsHtml, $productContainer) {\n\t// Update options\n $productContainer.find('.product-options').empty().html(optionsHtml);\n}\n\n/**\n * Dynamically creates Bootstrap carousel from response containing images\n * @param {Object[]} imgs - Array of large product images,along with related information\n * @param {jQuery} $productContainer - DOM element for a given product\n */\nfunction createCarousel(imgs, $productContainer) {\n var carousel = $productContainer.find('.carousel');\n $(carousel).carousel('dispose');\n var carouselId = $(carousel).attr('id');\n $(carousel).empty().append('
      ' + $(carousel).data('prev') + '' + $(carousel).data('next') + '');\n for (var i = 0; i < imgs.length; i++) {\n $('
      \"'
      ').appendTo($(carousel).find('.carousel-inner'));\n $('
    1. ').appendTo($(carousel).find('.carousel-indicators'));\n }\n $($(carousel).find('.carousel-item')).first().addClass('active');\n $($(carousel).find('.carousel-indicators > li')).first().addClass('active');\n if (imgs.length === 1) {\n $($(carousel).find('.carousel-indicators, a[class^=\"carousel-control-\"]')).detach();\n }\n $(carousel).carousel();\n $($(carousel).find('.carousel-indicators')).attr('aria-hidden', true);\n}\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 */\nfunction 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(response.product.variationAttributes, $productContainer, response.resources);\n isVaraint = response.product.productType === 'variant';\n if (isChoiceOfBonusProducts && isVaraint) {\n $productContainer.parent('.bonus-product-item')\n .data('pid', response.product.id);\n\n $productContainer.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.find('.promotions').empty().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, $productContainer: $productContainer\n });\n } else {\n // Enable \"Add to Cart\" button if all required attributes have been selected\n $('button.add-to-cart, button.add-to-cart-global, button.update-cart-product-global').trigger('product:updateAddToCart', {\n product: response.product, $productContainer: $productContainer\n }).trigger('product:statusUpdate', response.product);\n }\n\n // Update attributes\n $productContainer.find('.main-attributes').empty()\n .html(getAttributesHtml(response.product.attributes));\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 */\nfunction updateQuantities(quantities, $productContainer) {\n if ($productContainer.parent('.bonus-product-item').length <= 0) {\n var optionsHtml = quantities.map(function (quantity) {\n var selected = quantity.selected ? ' selected ' : '';\n return '';\n }).join('');\n getQuantitySelector($productContainer).empty().html(optionsHtml);\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 */\nfunction attributeSelect(selectedValueUrl, $productContainer) {\n if (selectedValueUrl) {\n $('body').trigger('product:beforeAttributeSelect',\n { url: selectedValueUrl, container: $productContainer });\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 $('body').trigger('product:afterAttributeSelect',\n { data: data, container: $productContainer });\n $.spinner().stop();\n },\n error: function () {\n $.spinner().stop();\n }\n });\n }\n}\n\n/**\n * Retrieves url to use when adding a product to the cart\n *\n * @return {string} - The provided URL to use when adding a product to the cart\n */\nfunction getAddToCartUrl() {\n return $('.add-to-cart-url').val();\n}\n\n/**\n * Parses the html for a modal window\n * @param {string} html - representing the body and footer of the modal window\n *\n * @return {Object} - Object with properties body and footer.\n */\nfunction parseHtml(html) {\n var $html = $('
      ').append($.parseHTML(html));\n\n var body = $html.find('.choice-of-bonus-product');\n var footer = $html.find('.modal-footer').children();\n\n return { body: body, footer: footer };\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').spinner().start();\n\n if ($('#chooseBonusProductModal').length !== 0) {\n $('#chooseBonusProductModal').remove();\n }\n var bonusUrl;\n if (data.bonusChoiceRuleBased) {\n bonusUrl = data.showProductsUrlRuleBased;\n } else {\n bonusUrl = data.showProductsUrlListBased;\n }\n\n var htmlString = ''\n + '
      '\n + ''\n + '
      '\n + ''\n + '
      '\n + '
      '\n + ' ' + data.labels.selectprods + ''\n + ' '\n + '
      '\n + '
      '\n + '
      '\n + '
      '\n + '
      '\n + '
      ';\n $('body').append(htmlString);\n $('.modal-body').spinner().start();\n\n $.ajax({\n url: bonusUrl,\n method: 'GET',\n dataType: 'json',\n success: function (response) {\n var parsedHtml = parseHtml(response.renderedTemplate);\n $('#chooseBonusProductModal .modal-body').empty();\n $('#chooseBonusProductModal .enter-message').text(response.enterDialogMessage);\n $('#chooseBonusProductModal .modal-header .close .sr-only').text(response.closeButtonText);\n $('#chooseBonusProductModal .modal-body').html(parsedHtml.body);\n $('#chooseBonusProductModal .modal-footer').html(parsedHtml.footer);\n $('#chooseBonusProductModal').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 var messageType = response.error ? 'alert-danger' : 'alert-success';\n // show add to cart toast\n if (response.newBonusDiscountLineItem\n && Object.keys(response.newBonusDiscountLineItem).length !== 0) {\n chooseBonusProducts(response.newBonusDiscountLineItem);\n } else {\n if ($('.add-to-cart-messages').length === 0) {\n $('body').append(\n '
      '\n );\n }\n\n $('.add-to-cart-messages').append(\n '
      '\n + response.message\n + '
      '\n );\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).find('.product-id').text(),\n quantity: parseInt($(this).find('label.quantity').data('quantity'), 10)\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 + '\"]')\n .data('value-id');\n return {\n optionId: $(this).data('option-id'),\n selectedValueId: selectedValueId\n };\n }).toArray();\n\n return JSON.stringify(options);\n}\n\n/**\n * Makes a call to the server to report the event of adding an item to the cart\n *\n * @param {string | boolean} url - a string representing the end point to hit so that the event can be recorded, or false\n */\nfunction miniCartReportingUrl(url) {\n if (url) {\n $.ajax({\n url: url,\n method: 'GET',\n success: function () {\n // reporting urls hit on the server\n },\n error: function () {\n // no reporting urls hit on the server\n }\n });\n }\n}\n\nmodule.exports = {\n attributeSelect: attributeSelect,\n methods: {\n editBonusProducts: function (data) {\n chooseBonusProducts(data);\n }\n },\n\n focusChooseBonusProductModal: function () {\n $('body').on('shown.bs.modal', '#chooseBonusProductModal', function () {\n $('#chooseBonusProductModal').siblings().attr('aria-hidden', 'true');\n $('#chooseBonusProductModal .close').focus();\n });\n },\n\n onClosingChooseBonusProductModal: function () {\n $('body').on('hidden.bs.modal', '#chooseBonusProductModal', function () {\n $('#chooseBonusProductModal').siblings().attr('aria-hidden', 'false');\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', function (e) {\n e.preventDefault();\n\n if ($(this).attr('disabled')) {\n return;\n }\n var $productContainer = $(this).closest('.set-item');\n if (!$productContainer.length) {\n $productContainer = $(this).closest('.product-detail');\n }\n\n attributeSelect($(this).attr('data-url'), $productContainer);\n });\n },\n\n selectAttribute: function () {\n $(document).on('change', 'select[class*=\"select-\"], .options-select', function (e) {\n e.preventDefault();\n\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 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).closest('.modal-content').find('.product-quickview');\n }\n\n if ($('.bundle-items', $productContainer).length === 0) {\n attributeSelect($(e.currentTarget).find('option:selected').data('url'),\n $productContainer);\n }\n });\n },\n\n addToCart: function () {\n $(document).on('click', 'button.add-to-cart, button.add-to-cart-global', function () {\n var addToCartUrl;\n var pid;\n var pidsObj;\n var setPids;\n\n if ($(this).hasClass('disabled')) {\n return;\n }\n\n $('body').trigger('product:beforeAddToCart', this);\n\n if ($('.set-items').length && $(this).hasClass('add-to-cart-global')) {\n setPids = [];\n\n $('.product-detail').each(function () {\n if (!$(this).hasClass('product-set-detail')) {\n setPids.push({\n pid: $(this).find('.product-id').text(),\n qty: $(this).find('.quantity-select').val(),\n options: getOptions($(this))\n });\n }\n });\n pidsObj = JSON.stringify(setPids);\n }\n\n pid = getPidValue($(this));\n\n var $productContainer = $(this).closest('.product-detail');\n if (!$productContainer.length) {\n $productContainer = $(this).closest('.quick-view-dialog').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 };\n\n if (!$('.bundle-item').length) {\n form.options = getOptions($productContainer);\n }\n\n $(this).trigger('updateAddToCartFormData', form);\n if (addToCartUrl) {\n $.ajax({\n url: addToCartUrl,\n method: 'POST',\n data: form,\n success: function (data) {\n handlePostCartAdd(data);\n $('body').trigger('product:afterAddToCart', data);\n $.spinner().stop();\n miniCartReportingUrl(data.reportingURL);\n },\n error: function () {\n $.spinner().stop();\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 = $(this).data('pid');\n var maxPids = $('.choose-bonus-product-dialog').data('total-qty');\n var submittedQty = parseInt($choiceOfBonusProduct.find('.bonus-quantity-select').val(), 10);\n var totalQty = 0;\n $.each($('#chooseBonusProductModal .selected-bonus-products .selected-pid'), function () {\n totalQty += $(this).data('qty');\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 + $choiceOfBonusProduct.find('.product-name').html()\n + '
      '\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',\n (!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 showMoreBonusProducts: function () {\n $(document).on('click', '.show-more-bonus-products', function () {\n var url = $(this).data('url');\n $('.modal-content').spinner().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').spinner().stop();\n },\n error: function () {\n $('.modal-content').spinner().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 =\n parseInt($(this)\n .data('qty'), 10);\n\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 = $(this).data('pid');\n option.selectedValueId = $(this).data('option-selected-value');\n }\n pidsObject.bonusProducts.push({\n pid: $(this).data('pid'),\n qty: qtyOption,\n options: [option]\n });\n pidsObject.totalQty = parseInt($('.pre-cart-products').html(), 10);\n }\n });\n queryString += JSON.stringify(pidsObject);\n queryString = queryString + '&uuid=' + $('.choose-bonus-product-dialog').data('uuid');\n queryString = queryString + '&pliuuid=' + $('.choose-bonus-product-dialog').data('pliuuid');\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(\n '
      '\n + data.errorMessage + '
      '\n );\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\n if ($('.add-to-cart-messages').length === 0) {\n $('body').append('
      ');\n }\n $('.minicart-quantity').html(data.totalQty);\n $('.add-to-cart-messages').append(\n '
      '\n + data.msgSuccess + '
      '\n );\n setTimeout(function () {\n $('.add-to-basket-alert').remove();\n if ($('.cart-page').length) {\n location.reload();\n }\n }, 1500);\n }\n },\n error: function () {\n $.spinner().stop();\n }\n });\n });\n },\n\n getPidValue: getPidValue,\n getQuantitySelected: getQuantitySelected,\n miniCartReportingUrl: miniCartReportingUrl\n};\n","require('bootstrap/js/src/util.js');\nrequire('bootstrap/js/src/alert.js');\n// require('bootstrap/js/src/button.js');\nrequire('bootstrap/js/src/carousel.js');\nrequire('bootstrap/js/src/collapse.js');\n// require('bootstrap/js/src/dropdown.js');\nrequire('bootstrap/js/src/modal.js');\nrequire('bootstrap/js/src/scrollspy.js');\nrequire('bootstrap/js/src/tab.js');\n// require('bootstrap/js/src/tooltip.js');\n// require('bootstrap/js/src/popover.js');\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","/*\n (accessible)\n _ _ _ _\n ___| (_) ___| | __ (_)___\n/ __| | |/ __| |/ / | / __|\n\\__ \\ | | (__| < _ | \\__ \\\n|___/_|_|\\___|_|\\_(_)/ |___/\n |__/\n\n Version: 1.8.1@accessible360.1\n Author: Jason Webb (Accessible360)\n Website: https://accessible360.com\n Docs: https://accessible360.github.io/accessible-slick\n Repo: https://github.com/Accessible360/accessible-slick\n Issues: https://github.com/Accessible360/accessible-slick/issues\n\n */\n/* global window, document, define, jQuery, setInterval, clearInterval */\n;(function(factory) {\n 'use strict';\n if (typeof define === 'function' && define.amd) {\n define(['jquery'], factory);\n } else if (typeof exports !== 'undefined') {\n module.exports = factory(require('jquery'));\n } else {\n factory(jQuery);\n }\n\n}(function($) {\n 'use strict';\n var Slick = window.Slick || {};\n\n Slick = (function() {\n\n var instanceUid = 0;\n\n function Slick(element, settings) {\n\n var _ = this, dataSettings;\n\n _.defaults = {\n adaptiveHeight: false,\n appendArrows: $(element),\n appendDots: $(element),\n arrows: true,\n arrowsPlacement: null,\n asNavFor: null,\n prevArrow: '',\n nextArrow: '',\n autoplay: false,\n autoplaySpeed: 3000,\n centerMode: false,\n centerPadding: '50px',\n cssEase: 'ease',\n customPaging: function(slider, i) {\n return $('');\n },\n dots: false,\n dotsClass: 'slick-dots',\n draggable: true,\n easing: 'linear',\n edgeFriction: 0.35,\n fade: false,\n infinite: true,\n initialSlide: 0,\n instructionsText: null,\n lazyLoad: 'ondemand',\n mobileFirst: false,\n playIcon: '',\n pauseIcon: '',\n pauseOnHover: true,\n pauseOnFocus: true,\n pauseOnDotsHover: false,\n regionLabel: 'carousel',\n respondTo: 'window',\n responsive: null,\n rows: 1,\n rtl: false,\n slide: '',\n slidesPerRow: 1,\n slidesToShow: 1,\n slidesToScroll: 1,\n speed: 500,\n swipe: true,\n swipeToSlide: false,\n touchMove: true,\n touchThreshold: 5,\n useAutoplayToggleButton: true,\n useCSS: true,\n useGroupRole: true,\n useTransform: true,\n variableWidth: false,\n vertical: false,\n verticalSwiping: false,\n waitForAnimate: true,\n zIndex: 1000\n };\n\n _.initials = {\n animating: false,\n dragging: false,\n autoPlayTimer: null,\n currentDirection: 0,\n currentLeft: null,\n currentSlide: 0,\n direction: 1,\n $dots: null,\n $instructionsText: null,\n listWidth: null,\n listHeight: null,\n loadIndex: 0,\n $nextArrow: null,\n $pauseButton: null,\n $pauseIcon: null,\n $playIcon: null,\n $prevArrow: null,\n scrolling: false,\n slideCount: null,\n slideWidth: null,\n $slideTrack: null,\n $slides: null,\n sliding: false,\n slideOffset: 0,\n swipeLeft: null,\n swiping: false,\n $list: null,\n touchObject: {},\n transformsEnabled: false,\n unslicked: false\n };\n\n $.extend(_, _.initials);\n\n _.activeBreakpoint = null;\n _.animType = null;\n _.animProp = null;\n _.breakpoints = [];\n _.breakpointSettings = [];\n _.cssTransitions = false;\n _.focussed = false;\n _.interrupted = false;\n _.hidden = 'hidden';\n _.paused = true;\n _.positionProp = null;\n _.respondTo = null;\n _.rowCount = 1;\n _.shouldClick = true;\n _.$slider = $(element);\n _.$slidesCache = null;\n _.transformType = null;\n _.transitionType = null;\n _.visibilityChange = 'visibilitychange';\n _.windowWidth = 0;\n _.windowTimer = null;\n\n dataSettings = $(element).data('slick') || {};\n\n _.options = $.extend({}, _.defaults, settings, dataSettings);\n\n _.currentSlide = _.options.initialSlide;\n\n _.originalSettings = _.options;\n\n if (typeof document.mozHidden !== 'undefined') {\n _.hidden = 'mozHidden';\n _.visibilityChange = 'mozvisibilitychange';\n } else if (typeof document.webkitHidden !== 'undefined') {\n _.hidden = 'webkitHidden';\n _.visibilityChange = 'webkitvisibilitychange';\n }\n\n _.autoPlay = $.proxy(_.autoPlay, _);\n _.autoPlayClear = $.proxy(_.autoPlayClear, _);\n _.autoPlayIterator = $.proxy(_.autoPlayIterator, _);\n _.autoPlayToggleHandler = $.proxy(_.autoPlayToggleHandler, _);\n _.changeSlide = $.proxy(_.changeSlide, _);\n _.clickHandler = $.proxy(_.clickHandler, _);\n _.selectHandler = $.proxy(_.selectHandler, _);\n _.setPosition = $.proxy(_.setPosition, _);\n _.swipeHandler = $.proxy(_.swipeHandler, _);\n _.dragHandler = $.proxy(_.dragHandler, _);\n\n _.instanceUid = instanceUid++;\n\n // A simple way to check for HTML strings\n // Strict HTML recognition (must start with <)\n // Extracted from jQuery v1.11 source\n _.htmlExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*)$/;\n\n\n _.registerBreakpoints();\n _.init(true);\n\n }\n\n return Slick;\n\n }());\n\n Slick.prototype.addSlide = Slick.prototype.slickAdd = function(markup, index, addBefore) {\n\n var _ = this;\n\n if (typeof(index) === 'boolean') {\n addBefore = index;\n index = null;\n } else if (index < 0 || (index >= _.slideCount)) {\n return false;\n }\n\n _.unload();\n\n if (typeof(index) === 'number') {\n if (index === 0 && _.$slides.length === 0) {\n $(markup).appendTo(_.$slideTrack);\n } else if (addBefore) {\n $(markup).insertBefore(_.$slides.eq(index));\n } else {\n $(markup).insertAfter(_.$slides.eq(index));\n }\n } else {\n if (addBefore === true) {\n $(markup).prependTo(_.$slideTrack);\n } else {\n $(markup).appendTo(_.$slideTrack);\n }\n }\n\n _.$slides = _.$slideTrack.children(this.options.slide);\n\n _.$slideTrack.children(this.options.slide).detach();\n\n _.$slideTrack.append(_.$slides);\n\n _.$slides.each(function(index, element) {\n $(element).attr('data-slick-index', index);\n $(element).attr('role', 'group');\n $(element).attr('aria-label', 'slide ' + index);\n });\n\n _.$slidesCache = _.$slides;\n\n _.reinit();\n\n };\n\n Slick.prototype.animateHeight = function() {\n var _ = this;\n if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {\n var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);\n _.$list.animate({\n height: targetHeight\n }, _.options.speed);\n }\n };\n\n Slick.prototype.animateSlide = function(targetLeft, callback) {\n\n var animProps = {},\n _ = this;\n\n _.animateHeight();\n\n if (_.options.rtl === true && _.options.vertical === false) {\n targetLeft = -targetLeft;\n }\n if (_.transformsEnabled === false) {\n if (_.options.vertical === false) {\n _.$slideTrack.animate({\n left: targetLeft\n }, _.options.speed, _.options.easing, callback);\n } else {\n _.$slideTrack.animate({\n top: targetLeft\n }, _.options.speed, _.options.easing, callback);\n }\n\n } else {\n\n if (_.cssTransitions === false) {\n if (_.options.rtl === true) {\n _.currentLeft = -(_.currentLeft);\n }\n $({\n animStart: _.currentLeft\n }).animate({\n animStart: targetLeft\n }, {\n duration: _.options.speed,\n easing: _.options.easing,\n step: function(now) {\n now = Math.ceil(now);\n if (_.options.vertical === false) {\n animProps[_.animType] = 'translate(' +\n now + 'px, 0px)';\n _.$slideTrack.css(animProps);\n } else {\n animProps[_.animType] = 'translate(0px,' +\n now + 'px)';\n _.$slideTrack.css(animProps);\n }\n },\n complete: function() {\n if (callback) {\n callback.call();\n }\n }\n });\n\n } else {\n\n _.applyTransition();\n targetLeft = Math.ceil(targetLeft);\n\n if (_.options.vertical === false) {\n animProps[_.animType] = 'translate3d(' + targetLeft + 'px, 0px, 0px)';\n } else {\n animProps[_.animType] = 'translate3d(0px,' + targetLeft + 'px, 0px)';\n }\n _.$slideTrack.css(animProps);\n\n if (callback) {\n setTimeout(function() {\n\n _.disableTransition();\n\n callback.call();\n }, _.options.speed);\n }\n\n }\n\n }\n\n };\n\n Slick.prototype.getNavTarget = function() {\n\n var _ = this,\n asNavFor = _.options.asNavFor;\n\n if ( asNavFor && asNavFor !== null ) {\n asNavFor = $(asNavFor).not(_.$slider);\n }\n\n return asNavFor;\n\n };\n\n Slick.prototype.asNavFor = function(index) {\n\n var _ = this,\n asNavFor = _.getNavTarget();\n\n if ( asNavFor !== null && typeof asNavFor === 'object' ) {\n asNavFor.each(function() {\n var target = $(this).slick('getSlick');\n if(!target.unslicked) {\n target.slideHandler(index, true);\n }\n });\n }\n\n };\n\n Slick.prototype.applyTransition = function(slide) {\n\n var _ = this,\n transition = {};\n\n if (_.options.fade === false) {\n transition[_.transitionType] = _.transformType + ' ' + _.options.speed + 'ms ' + _.options.cssEase;\n } else {\n transition[_.transitionType] = 'opacity ' + _.options.speed + 'ms ' + _.options.cssEase;\n }\n\n if (_.options.fade === false) {\n _.$slideTrack.css(transition);\n } else {\n _.$slides.eq(slide).css(transition);\n }\n\n };\n\n Slick.prototype.autoPlay = function() {\n\n var _ = this;\n\n _.autoPlayClear();\n\n if ( _.slideCount > _.options.slidesToShow ) {\n _.autoPlayTimer = setInterval( _.autoPlayIterator, _.options.autoplaySpeed );\n }\n\n };\n\n Slick.prototype.autoPlayClear = function() {\n\n var _ = this;\n\n if (_.autoPlayTimer) {\n clearInterval(_.autoPlayTimer);\n }\n\n };\n\n Slick.prototype.autoPlayIterator = function() {\n\n var _ = this,\n slideTo = _.currentSlide + _.options.slidesToScroll;\n\n if ( !_.paused && !_.interrupted && !_.focussed ) {\n\n if ( _.options.infinite === false ) {\n\n if ( _.direction === 1 && ( _.currentSlide + 1 ) === ( _.slideCount - 1 )) {\n _.direction = 0;\n }\n\n else if ( _.direction === 0 ) {\n\n slideTo = _.currentSlide - _.options.slidesToScroll;\n\n if ( _.currentSlide - 1 === 0 ) {\n _.direction = 1;\n }\n\n }\n\n }\n\n _.slideHandler( slideTo );\n\n }\n\n };\n\n Slick.prototype.autoPlayToggleHandler = function() {\n var _ = this;\n\n if(_.paused) {\n _.$playIcon.css('display', 'none');\n _.$pauseIcon.css('display', 'inline');\n\n _.$pauseButton.find('.slick-play-text').attr('style', 'display: none');\n _.$pauseButton.find('.slick-pause-text').removeAttr('style');\n\n _.slickPlay();\n } else {\n _.$playIcon.css('display', 'inline');\n _.$pauseIcon.css('display', 'none');\n\n _.$pauseButton.find('.slick-play-text').removeAttr('style');\n _.$pauseButton.find('.slick-pause-text').attr('style', 'display: none');\n\n _.slickPause();\n }\n };\n\n Slick.prototype.buildArrows = function() {\n\n var _ = this;\n\n if (_.options.arrows === true ) {\n\n _.$prevArrow = $(_.options.prevArrow).addClass('slick-arrow');\n _.$nextArrow = $(_.options.nextArrow).addClass('slick-arrow');\n\n if( _.slideCount > _.options.slidesToShow ) {\n\n if (_.htmlExpr.test(_.options.prevArrow)) {\n if(_.options.arrowsPlacement != null) {\n switch(_.options.arrowsPlacement) {\n case 'beforeSlides':\n case 'split':\n console.log('test');\n _.$prevArrow.prependTo(_.options.appendArrows);\n break;\n\n case 'afterSlides':\n _.$prevArrow.appendTo(_.options.appendArrows);\n break;\n }\n\n } else {\n _.$prevArrow.prependTo(_.options.appendArrows);\n }\n }\n\n if (_.htmlExpr.test(_.options.nextArrow)) {\n if(_.options.arrowsPlacement != null) {\n switch(_.options.arrowsPlacement) {\n case 'beforeSlides':\n console.log('test2');\n _.$prevArrow.after(_.$nextArrow);\n break;\n\n case 'afterSlides':\n case 'split':\n _.$nextArrow.appendTo(_.options.appendArrows);\n }\n } else {\n _.$nextArrow.appendTo(_.options.appendArrows);\n }\n }\n\n if (_.options.infinite !== true) {\n _.$prevArrow\n .addClass('slick-disabled')\n .prop('disabled', true);\n }\n\n } else {\n\n _.$prevArrow.add( _.$nextArrow )\n\n .addClass('slick-hidden')\n .prop('disabled', true);\n }\n\n }\n\n };\n\n Slick.prototype.buildDots = function() {\n\n var _ = this,\n i, dot;\n\n if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {\n\n _.$slider.addClass('slick-dotted');\n\n dot = $('