{ "version": 3, "sources": [ "../../../../../Foundation/JavascriptCommon/code/scripts/common/accordion.js", "../../../../../Foundation/JavascriptCommon/code/scripts/common/shuffle.js", "../../../../../Foundation/JavascriptCommon/code/scripts/common/urlUtils.js", "ProductTile/productTileComponent.js", "../../../../../Foundation/JavascriptCommon/code/scripts/common/formUtils.js", "ProductsIndex/filterFacetsPosition.js", "ProductsIndex/main.js" ], "names": [], "mappings": "AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC5DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC/GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "ProductsIndex.js", "sourcesContent": [ "define('common/accordion',[\r\n],\r\n function () {\r\n\r\n function init(selector) {\r\n $(selector + \" .custom-accordion-title,\" + selector + \" .custom-accordion-icon\").off(\"click\").on(\"click\", accordionClick);\r\n // auto expand custom-accordion-item if needed\r\n $(selector + \" .custom-accordion,\" + selector + \".custom-accordion\").each(function (index, element) {\r\n var expandItemId = $(element).data(\"expandItemId\");\r\n if (expandItemId) expandAccordionItem(selector, expandItemId);\r\n });\r\n }\r\n\r\n function accordionClick(event, clickedElement) {\r\n if (!clickedElement) clickedElement = this;\r\n // toggle accordion opened/closed\r\n $(clickedElement).toggleClass(\"open\");\r\n $(clickedElement).siblings(\".custom-accordion-content\").toggleClass(\"open\");\r\n $(clickedElement).siblings(\".custom-accordion-title\").toggleClass(\"open\");\r\n // dispatch appropriate event for other modules to use\r\n if ($(clickedElement).hasClass(\"open\")) dispatchEvent(clickedElement, \"accordionOpened\");\r\n else dispatchEvent(clickedElement, \"accordionClosed\");\r\n }\r\n\r\n function expandAccordionItem(selector, id) {\r\n var clickedElement = selector + \" .custom-accordion-item[data-item-id='\" + id + \"']\" + \" .custom-accordion-title\";\r\n if ($(clickedElement).length) {\r\n accordionClick(null, clickedElement);\r\n // scroll the accordion item into view if needed\r\n var pageTop = $(window).scrollTop();\r\n var pageBottom = pageTop + $(window).height();\r\n var elementTop = $(clickedElement).offset().top;\r\n var elementBottom = elementTop + $(clickedElement).height();\r\n if (elementTop < pageTop || elementBottom > pageBottom) {\r\n $(\"html,body\").animate({ scrollTop: $(clickedElement).offset().top - 80 });\r\n }\r\n }\r\n }\r\n\r\n function dispatchEvent(clickedElement, eventName) {\r\n var accordionItemElement = $(clickedElement).closest(\".custom-accordion-item\");\r\n var eventData = $(accordionItemElement).data(\"itemId\");\r\n var event;\r\n var trueTypeOf = function (obj) {\r\n return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();\r\n };\r\n if (trueTypeOf(window.CustomEvent) === 'function') {\r\n event = new CustomEvent(eventName, { bubbles: true, detail: eventData });\r\n } else {\r\n event = document.createEvent('CustomEvent');\r\n event.initCustomEvent(eventName, true, false, eventData);\r\n }\r\n $(accordionItemElement)[0].dispatchEvent(event);\r\n }\r\n\r\n return {\r\n init : init\r\n };\r\n });\r\n\n", "define('common/shuffle',[\r\n],\r\n function () {\r\n\r\n var Shuffle = window.Shuffle;\r\n\r\n function init(selector, itemSelector) {\r\n var element = document.querySelector(selector);\r\n var shuffleInstance = new Shuffle(element, {\r\n itemSelector: itemSelector,\r\n speed: 250\r\n });\r\n window.addEventListener(\"resize\", function () {\r\n setEqualHeightForShuffleItems(shuffleInstance);\r\n shuffleInstance.update();\r\n });\r\n return shuffleInstance;\r\n }\r\n\r\n function changeContent(shuffleInstance, html, displayCount) {\r\n if (html !== \"NO_HTML\") {\r\n var newElements = $($.parseHTML(html)).filter(shuffleInstance.options.itemSelector).toArray();\r\n var currentElements = shuffleInstance.items.map(function (i) { return i.element; });\r\n\r\n if (currentElements.length) {\r\n shuffleInstance.remove(currentElements);\r\n }\r\n\r\n if (newElements.length) {\r\n newElements.forEach(function (element) {\r\n shuffleInstance.element.appendChild(element);\r\n });\r\n shuffleInstance.add(newElements);\r\n }\r\n }\r\n\r\n sort(shuffleInstance);\r\n filter(shuffleInstance, displayCount);\r\n setEqualHeightForShuffleItems(shuffleInstance);\r\n shuffleInstance.update();\r\n }\r\n\r\n function sort(shuffleInstance) {\r\n shuffleInstance.sort({\r\n by: function (element) {\r\n return Number(element.getAttribute(\"data-sort\"));\r\n }\r\n });\r\n }\r\n\r\n function filter(shuffleInstance, displayCount) {\r\n shuffleInstance.filter(function (element) {\r\n return Number(element.getAttribute(\"data-sort\") <= displayCount);\r\n });\r\n }\r\n\r\n function setEqualHeightForShuffleItems(shuffleInstance) {\r\n // get elements from shuffle items\r\n var elements = shuffleInstance.items.map(function (i) { return i.element; });\r\n if (elements.length) {\r\n //puts the height of all elements in an array\r\n var heights = elements.map(function (element) { return $(element).children().prop(\"scrollHeight\"); });\r\n //gets the highest value out of the array\r\n var maxHeight = heights.reduce(function (a, b) { return Math.max(a, b); });\r\n //sets height of all the elements to be the same as the highest one\r\n elements.forEach(function (element) { $(element).height(maxHeight); });\r\n }\r\n }\r\n\r\n return {\r\n init: init,\r\n changeContent: changeContent,\r\n filter: filter\r\n };\r\n });\r\n\n", "define('common/urlUtils',[\r\n],\r\n function () {\r\n\r\n // Takes the url and parses the query string parameters out of it.\r\n // Returns the parameters and their string values as object { paramName1: value1, paramName2: value2, ...},\r\n // or an empty object in case there are no parameters in url.\r\n function parseQueryParamsFromUrl(url) {\r\n url = url ? url : window.location.search; // default url parameter if not set\r\n // take just the query search part of url (lose the leading question mark)\r\n var query = decomposeUrl(url).search;\r\n if (query.indexOf(\"?\") >= 0) query = query.substring(query.indexOf(\"?\") + 1);\r\n var urlParams = {},\r\n match,\r\n search = /([^&=]+)=?([^&]*)/g,\r\n decode = function (s) { return decodeURI(decodeURIComponent(s)); };\r\n\r\n while (match = search.exec(query))\r\n urlParams[decode(match[1])] = decode(match[2]);\r\n\r\n return urlParams;\r\n }\r\n\r\n // Takes the url, decomposes it into three components: path, search, hash,\r\n // and returns those three components in an object.\r\n // When searching for hash string which is directly after path (without search parameters) we're ignoring '#/'.\r\n // That is not a hash, that is Angular routing and it's actually part of the path.\r\n function decomposeUrl(url) {\r\n var path = '';\r\n var search = '';\r\n var hash = '';\r\n if (url.indexOf('?') >= 0) {\r\n // there is search string already in the url\r\n path = url.substring(0, url.indexOf('?'));\r\n search = url.substring(url.indexOf('?'));\r\n if (search.indexOf('#') >= 0) {\r\n // there is also a hash string in the url\r\n hash = search.substring(search.indexOf('#'));\r\n search = search.substring(0, search.indexOf('#'));\r\n }\r\n } else if (url.indexOf('#') >= 0 && url.indexOf('#') != url.indexOf('#/')) {\r\n // no search string, but there is hash string\r\n path = url.substring(0, url.indexOf('#'));\r\n hash = url.substring(url.indexOf('#'));\r\n } else {\r\n // no search string, no hash string\r\n path = url ? url : '';\r\n }\r\n return {\r\n path: path, // path also includes the protocol and hostname (if they existed in the given url)\r\n search: search,\r\n hash: hash\r\n }\r\n }\r\n\r\n // Adds a new query string parameter into the given url.\r\n // Returns the newly constructed url.\r\n function putParamIntoUrl(paramName, paramValue, url) {\r\n // first we'll split the url into 3 components\r\n var urlComp = decomposeUrl(url);\r\n // add the new query string parameter into search string\r\n urlComp.search = (urlComp.search ? urlComp.search + '&' : '?') + paramName + '=' + encodeURIComponent(paramValue);\r\n // return the new url\r\n return urlComp.path + urlComp.search + urlComp.hash;\r\n }\r\n\r\n // Reads the specified query string parameter from a given url.\r\n // Returns the value of that parameter (a string value). \r\n function getParamFromUrl(paramName, url) {\r\n return parseQueryParamsFromUrl(url)[paramName];\r\n }\r\n\r\n // Modifies the given DOM element's href property, or the current page's URL (if\r\n // no domElement has been given) by adding new query string parameter with the\r\n // given value. \r\n function pushParamIntoLink(paramName, paramValue, domElement) {\r\n var url;\r\n if (domElement) url = $(domElement).attr('href'); // url from DOM element\r\n else url = window.location.href; // current page url\r\n\r\n var params = parseQueryParamsFromUrl(url);\r\n\r\n // making sure that we find the parameter no matter how it's written (case insensitive)\r\n for (var p in params) {\r\n if (p.toLowerCase() === paramName.toLowerCase()) {\r\n paramName = p;\r\n break;\r\n }\r\n }\r\n\r\n params[paramName] = paramValue; // update (or add) the parameter\r\n var newSearchString = $.param(params); // and construct a new search string.\r\n\r\n var urlComp = decomposeUrl(url);\r\n if (domElement) {\r\n // set new href property on DOM element\r\n var newHref = urlComp.path + (newSearchString ? ('?' + newSearchString) : '') + urlComp.hash;\r\n $(domElement).attr('href', newHref);\r\n } else {\r\n if (history && history.pushState) { // because some older browsers (IE 9 or older) don't support this\r\n // for other pages put new URL to browser's address bar using window.history\r\n history.replaceState(\r\n null,\r\n null,\r\n urlComp.path +\r\n (newSearchString ? ('?' + newSearchString) : '') +\r\n urlComp.hash\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Reads the query string parameter from the domElement's href property, or from\r\n // the current page's URL (if no domElement has been given). Removes the parameter\r\n // from the URL and puts new URL into the domElement's href property, or into the\r\n // browser's address bar.\r\n // Returns the value of that parameter (a string value).\r\n function popParamFromLink(paramName, domElement) {\r\n var url;\r\n if (domElement) url = $(domElement).attr('href'); // url from DOM element\r\n else url = window.location.href; // current page url\r\n\r\n var params = parseQueryParamsFromUrl(url);\r\n var retVal;\r\n\r\n // making sure that we find the parameter no matter how it's written (case insensitive)\r\n for (var p in params) {\r\n if (p.toLowerCase() === paramName.toLowerCase()) {\r\n paramName = p;\r\n break;\r\n }\r\n }\r\n\r\n if (params[paramName]) {\r\n // the requested parameter exists in the url\r\n retVal = params[paramName]; // Its value will be returned from the function.\r\n delete params[paramName]; // Remove the parameter from the array,\r\n var newSearchString = $.param(params); // and construct a new search string.\r\n var urlComp = decomposeUrl(url);\r\n if (domElement) {\r\n // set new href property on DOM element\r\n var newHref = urlComp.path + (newSearchString ? ('?' + newSearchString) : '') + urlComp.hash;\r\n $(domElement).attr('href', newHref);\r\n } else {\r\n if (history && history.pushState) { // because some older browsers (IE 9 or older) don't support this\r\n // for other pages put new URL to browser's address bar using window.history\r\n history.replaceState(\r\n null,\r\n null,\r\n urlComp.path +\r\n (newSearchString ? ('?' + newSearchString) : '') +\r\n urlComp.hash\r\n );\r\n }\r\n }\r\n }\r\n return retVal;\r\n }\r\n\r\n\r\n return {\r\n parseQueryParamsFromUrl: parseQueryParamsFromUrl,\r\n decomposeUrl: decomposeUrl,\r\n putParamIntoUrl: putParamIntoUrl,\r\n getParamFromUrl: getParamFromUrl,\r\n pushParamIntoLink: pushParamIntoLink,\r\n popParamFromLink: popParamFromLink\r\n }\r\n });\r\n\n", "define('ProductTile/productTileComponent',[\r\n \"common/urlUtils\"\r\n],\r\nfunction (urlUtils) {\r\n\r\n function initClickHandlers() {\r\n $(\".product-tile .variant-selector .color-selector .selector\").off(\"click\").on(\"click\", colorSelectorClicked);\r\n $(\".product-tile .variant-selector .list-selector\").off(\"change\").on(\"change\", listSelectorChanged);\r\n }\r\n\r\n const selectorType = {\r\n color: 1,\r\n list: 2\r\n };\r\n\r\n function colorSelectorClicked(event) {\r\n $(this).siblings().removeClass(\"active\"); // deactivate all other selectors\r\n if ($(this).hasClass(\"active\")) {\r\n // It was already active. Deactivate it now.\r\n $(this).removeClass(\"active\");\r\n setVariant(this, { variantSku: \"\"}); // set to the default variant (no particular variant selected)\r\n }\r\n else {\r\n // activate the clicked selector\r\n $(this).addClass(\"active\");\r\n setVariant(this, $(this).data()); // set to the variant data written in that selector\r\n }\r\n }\r\n\r\n function listSelectorChanged(event) {\r\n\r\n setVariant(this, $(this.selectedOptions[0]).data());\r\n //selectVariant(this, selectorType.list);\r\n }\r\n\r\n function setVariant(clickedElement, variantData) {\r\n var imageElement = $(clickedElement).closest(\".product-tile\").find(\"img\");\r\n if (!$(imageElement).data(\"originalSrc\")) {\r\n // store original image url, in case we need to put it back\r\n $(imageElement).data(\"originalSrc\", $(imageElement).attr(\"src\"));\r\n }\r\n var currentImageUrl = $(imageElement).attr(\"src\");\r\n var newImageUrl = $(imageElement).data(\"originalSrc\"); // this is the default image\r\n\r\n var linkElement = $(clickedElement).closest(\".product-tile\").find(\"a\");\r\n\r\n if (variantData.variantSku) {\r\n if (variantData.imageUrl) newImageUrl = variantData.imageUrl;\r\n urlUtils.pushParamIntoLink(\"v\", variantData.variantSku, linkElement); // add variant query parameter into the link\r\n } else {\r\n urlUtils.popParamFromLink(\"v\", linkElement); // remove variant query parameter from link\r\n }\r\n\r\n if (newImageUrl !== currentImageUrl) {\r\n $(imageElement)\r\n .addClass(\"opacity-05\") // dim the image\r\n .one(\"load\", function () {\r\n $(this).removeClass(\"opacity-05\"); // set the load event to un-dim the image\r\n })\r\n .attr(\"src\", newImageUrl) // change the image source\r\n .each(function () {\r\n // Workaround for situations where the load event doesn't get triggerred because the image is taken from cache, or the\r\n // image changes so quickly that our \"onload\" event didn't have a chance to be set up yet.\r\n setTimeout(() => { $(imageElement).removeClass(\"opacity-05\"); }, 2000); // just in case \"onload\" didn't do it already, we'll clear the opacity class after 2 seconds\r\n });\r\n }\r\n\r\n $(linkElement).data(\"variantSku\", variantData.variantSku); // this will be used by the GTM click event\r\n }\r\n\r\n function selectVariant(clickedElement, selectorType) {\r\n\r\n var imageElement = $(clickedElement).closest(\".product-tile\").find(\"img\");\r\n if (!$(imageElement).data(\"originalSrc\")) {\r\n // store original image url, in case we need to put it back\r\n $(imageElement).data(\"originalSrc\", $(imageElement).attr(\"src\"));\r\n }\r\n\r\n var newImageUrl = $(imageElement).data(\"originalSrc\"); // this is the default image\r\n\r\n if (selectorType === selectorType.color) {\r\n $(clickedElement).siblings().removeClass(\"active\"); // deactivate all other selectors\r\n }\r\n\r\n var linkElement = $(clickedElement).closest(\".product-tile\").find(\"a\");\r\n\r\n if ($(clickedElement).hasClass(\"active\")) {\r\n // It was already active. Deactivate it now.\r\n $(clickedElement).removeClass(\"active\");\r\n // remove the variant query parameter from the link\r\n urlUtils.popParamFromLink(\"v\", linkElement);\r\n }\r\n else\r\n {\r\n // activate the clicked selector\r\n $(clickedElement).addClass(\"active\");\r\n // and apply its image, if it has one assigned\r\n if ($(clickedElement).data(\"imageUrl\")) newImageUrl = $(clickedElement).data(\"imageUrl\");\r\n // add the selected variant query parameter into the link\r\n var variantSku = $(clickedElement).data(\"variantSku\");\r\n if (variantSku) urlUtils.pushParamIntoLink(\"v\", variantSku, linkElement);\r\n }\r\n\r\n $(imageElement).attr(\"src\", newImageUrl);\r\n }\r\n\r\n return {\r\n initClickHandlers: initClickHandlers\r\n };\r\n\r\n});\n", "define('common/formUtils',[\r\n],\r\n function () {\r\n\r\n // Clears and deactivates all invalid feedback text on form fields\r\n function clearInvalidFeedback(formId) {\r\n if (!formId.startsWith(\"#\")) formId = \"#\" + formId;\r\n $(formId + \" .is-invalid\").removeClass(\"is-invalid\");\r\n $(formId + \" .invalid-feedback\").empty();\r\n }\r\n\r\n // Fills in and activates invalid feedback text on form fields\r\n function displayInvalidFeedback(invalidFields, formId) {\r\n if (!formId.startsWith(\"#\")) formId = \"#\" + formId;\r\n if (invalidFields) {\r\n invalidFields.forEach(function (fieldMessage) {\r\n var field = $(formId + \" [name='\" + fieldMessage.FieldName + \"']\");\r\n field.addClass(\"is-invalid\");\r\n field.siblings(\".invalid-feedback\").append(fieldMessage.MessageText);\r\n });\r\n }\r\n }\r\n\r\n // Collects the data from all form fields and returns them as object,\r\n // using \"name\" attribute values from form fields as object property names.\r\n function collectFormData(formId) {\r\n if (!formId.startsWith(\"#\")) formId = \"#\" + formId;\r\n // the serializeArray() jQuery method doesn't take the values from disabled fields, so first I'll\r\n // temporarily enable all disabled fields, and then disable them again\r\n var disabledFields = $(formId).find(\":input:disabled\").prop(\"disabled\", false);\r\n var serializedData = $(formId).serializeArray();\r\n disabledFields.prop(\"disabled\", true);\r\n var formData = {};\r\n serializedData.forEach(function (data) {\r\n formData[data.name] = data.value;\r\n });\r\n // serializeArray does not return anything for unchecked checkboxes, so we'll add them now with value false\r\n $(formId + \" input[type='checkbox']:not(:checked)\").each(function (index, element) {\r\n formData[element.name] = false;\r\n });\r\n // serializeArray returns \"on\" for checked checkboxes, so we'll set them to true now\r\n $(formId + \" input[type='checkbox']:checked\").each(function (index, element) {\r\n formData[element.name] = true;\r\n });\r\n return formData;\r\n }\r\n\r\n // Goes through all input elements on the form and fills them with data from the\r\n // given object, matching \"name\" attribute of the input element with object property name.\r\n function populateFormWithData(formId, data) {\r\n if (!formId.startsWith(\"#\")) formId = \"#\" + formId;\r\n $(formId + \" :input\").each(function (index, element) { \r\n if (element.type === \"radio\" ||\r\n element.type === \"checkbox\")\r\n {\r\n if (data[element.name] !== undefined)\r\n $(element).prop(\"checked\", $(element).val().toString() === data[element.name].toString());\r\n }\r\n else if (element.type === \"text\" ||\r\n element.type === \"email\" ||\r\n element.type === \"tel\" ||\r\n element.type === \"password\" ||\r\n element.type === \"textarea\" ||\r\n element.type === \"select-one\")\r\n {\r\n if (data[element.name] !== undefined)\r\n $(element).val(data[element.name]);\r\n else\r\n $(element).val(null);\r\n }\r\n });\r\n }\r\n\r\n function disableFields(formId) {\r\n if (!formId.startsWith(\"#\")) formId = \"#\" + formId;\r\n $(formId + \" :input\").prop(\"disabled\", true);\r\n }\r\n\r\n function enableFields(formId) {\r\n if (!formId.startsWith(\"#\")) formId = \"#\" + formId;\r\n $(formId + \" :input\").prop(\"disabled\", false);\r\n }\r\n\r\n function initializeFloatingLabels(formId) {\r\n if (!formId.startsWith(\"#\")) formId = \"#\" + formId;\r\n $(formId + \" .floating-label-container\").each(function (index, element) {\r\n var inputElement = $(element).find(\":input\")[0];\r\n if (inputElement.value) $(element).addClass(\"active\");\r\n else $(element).removeClass(\"active\");\r\n });\r\n }\r\n\r\n //adds the form token to the object for use with [ValidateAntiforgeryToken] attribute\r\n function useToken(data) { \r\n var token = $('input[name=\"__RequestVerificationToken\"]').val();\r\n data.__RequestVerificationToken = token;\r\n }\r\n\r\n return {\r\n clearInvalidFeedback: clearInvalidFeedback,\r\n displayInvalidFeedback: displayInvalidFeedback,\r\n collectFormData: collectFormData,\r\n populateFormWithData: populateFormWithData,\r\n disableFields: disableFields,\r\n enableFields: enableFields,\r\n initializeFloatingLabels: initializeFloatingLabels,\r\n useToken: useToken\r\n };\r\n });\r\n\n", "define('ProductsIndex/filterFacetsPosition',[\r\n],\r\nfunction () {\r\n\r\n // On desktop screen size product filter facets (checkboxes for filtering by product options)\r\n // are on the left size, below the left side navigation.\r\n // On mobile screen sizes they need to be directly above product index (the area where product\r\n // tiles are displayed), and below the banner image and text. But the row and column layout of\r\n // the pagte is such that it places the filters above the banner image and text, which is not\r\n // good.\r\n // We use this module to fix that. We have placed the placeholder div at the beginning of the\r\n // products index layout (where the filters need to be in mobile view), and we're dynamically\r\n // moving the filters between that position and their natural position in the left column of\r\n // the page, depending on the current screen size.\r\n\r\n function init() {\r\n $(window).off(\"resize.filterFacetsPosition\").on(\"resize.filterFacetsPosition\", windowResized);\r\n windowResized();\r\n }\r\n\r\n var views = {\r\n desktop: 1,\r\n mobile: 2\r\n };\r\n\r\n var currentView = views.desktop;\r\n var mobileBreakpoint = 768;\r\n\r\n function windowResized(event) {\r\n var width = $(window).width();\r\n\r\n if (width < mobileBreakpoint && currentView === views.desktop) {\r\n // MOVE ELEMENTS FROM DESKTOP TO MOBILE POSITION\r\n $(\"#products-filter-desktop\").children().appendTo(\"#products-filter-mobile\");\r\n currentView = views.mobile;\r\n } else if (width >= mobileBreakpoint && currentView === views.mobile) {\r\n // MOVE ELEMENTS FROM MOBILE TO DESKTOP POSITION\r\n $(\"#products-filter-mobile\").children().appendTo(\"#products-filter-desktop\");\r\n currentView = views.desktop;\r\n }\r\n }\r\n\r\n return {\r\n init: init\r\n };\r\n});\n", "require([\r\n \"common/accordion\",\r\n \"common/shuffle\",\r\n \"ProductTile/productTileComponent\",\r\n \"common/formUtils\",\r\n \"ProductsIndex/filterFacetsPosition\",\r\n \"common/urlUtils\"\r\n],\r\nfunction (accordion, shuffle, productTileComponent, formUtils, filterFacetsPosition, urlUtils) {\r\n\r\n var lastSearch;\r\n var scrollDebounce = true;\r\n\r\n function initClickHandlers() {\r\n $(\".facet-checkbox\").off(\"click\").on(\"click\", executeSearch);\r\n $(\".facet-clear\").off(\"click\").on(\"click\", clearFacet);\r\n accordion.init(\".products-filter\");\r\n //$(\"#products-index-load-more-button\").off(\"click\").on(\"click\", loadMore);\r\n $(\".facet-breadcrumb .close-button\").off(\"click\").on(\"click\", clearFacetCheckbox);\r\n productTileComponent.initClickHandlers();\r\n }\r\n\r\n function executeSearch(event, categoryFilterChanged, initialSearch) {\r\n\r\n $(\"#products-index-message\").removeClass(\"error\").empty();\r\n\r\n if (initialSearch) {\r\n showResults(initialProductsIndexData.Data);\r\n initialProductsIndexData = null; // just cleaning up, since we don't need this any more\r\n $(\".products-index-item\").removeClass(\"d-none\"); // we don't need the \"d-none\" class any more because now the Shuffle has taken over displaying and hiding the product tiles\r\n return; // for the initial display of products we don't need the AJAX part that follows\r\n }\r\n\r\n var postData = {\r\n categoryId: $(\"#products-index\").data(\"categoryId\"),\r\n alsoInCategoryId: currentCategoryFilter,\r\n generateListOfCategories: generateCategoryFilters,\r\n selectedFacetValues: [],\r\n openFacets: []\r\n };\r\n\r\n lastSearch = postData;\r\n\r\n currentDisplayCountLimit = pageSize;\r\n\r\n if (categoryFilterChanged) {\r\n // if category filter was changed then we don't want to keep selected facets\r\n }\r\n else {\r\n // go through all selected facets and send those to back end search engine\r\n postData.selectedFacetValues = $(\".facet-checkbox:checked\").map(function () {\r\n return {\r\n facet: this.name,\r\n value: this.value,\r\n valueId: this.id,\r\n facetDisplayName: this.title\r\n };\r\n }).get();\r\n\r\n postData.openFacets = $(\".facet:has('.custom-accordion-content.open')\").map(function () {\r\n return this.attributes[\"data-facet-name\"].value;\r\n }).get();\r\n }\r\n formUtils.useToken(postData);\r\n\r\n spinner(\"show\");\r\n $.ajax({\r\n type: \"POST\",\r\n url: \"/customapi/Product/Search\",\r\n dataType: \"json\",\r\n data: postData,\r\n success: function (data) {\r\n if (lastSearch !== postData) {\r\n return;\r\n }\r\n\r\n if (data.status === \"OK\") {\r\n showResults(data);\r\n } else {\r\n // Something's not right.\r\n // Display the error messages (if any) and stay on the page.\r\n $(\"#products-index-message\").addClass(\"error\").html(data.message);\r\n }\r\n },\r\n error: function (jq, status, errorThrown) {\r\n if (lastSearch !== postData) {\r\n return;\r\n }\r\n\r\n $(\"#products-index-message\").addClass(\"error\").html(status + \". \" + errorThrown);\r\n },\r\n complete: function () {\r\n if (lastSearch !== postData) {\r\n return;\r\n }\r\n\r\n spinner(\"hide\");\r\n generateCategoryFilters = false; // we only need this the first time we execute search\r\n }\r\n });\r\n\r\n }\r\n\r\n function showResults(data) {\r\n setScrollLoading(); \r\n $(\"#products-filter-facets\").empty().html(data.facets);\r\n // put selected facets into query string\r\n putSelectedFacetsIntoQueryString();\r\n // Display the products.\r\n shuffle.changeContent(shuffleInstance, data.products, currentDisplayCountLimit);\r\n // Display the breadcrumb facets.\r\n $(\"#products-filter-breadcrumbs\").empty().html(data.facetsBreadcrumbs);\r\n initClickHandlers();\r\n if (generateCategoryFilters) {\r\n displayCategoryFilters(data.categories);\r\n }\r\n // Is there a message?\r\n if (data.message) {\r\n $(\"#products-index-message\").html(data.message);\r\n } \r\n }\r\n\r\n function clearFacet(event) {\r\n $(this).closest(\".facet\").find(\".facet-checkbox\").prop(\"checked\", false);\r\n executeSearch();\r\n }\r\n\r\n function clearFacetCheckbox(event) {\r\n var facetName = $(this).data(\"name\");\r\n var facetValue = $(this).data(\"value\");\r\n $(\".facet-checkbox[name='\" + facetName + \"'][value='\" + facetValue + \"']\").prop(\"checked\", false);\r\n $(this).closest(\".facet-breadcrumb\").addClass(\"d-none\"); // hide the breadcrumb element immediately, so we don't have to wait for the search results\r\n executeSearch();\r\n }\r\n\r\n function putSelectedFacetsIntoQueryString() {\r\n var valueGuids = [];\r\n $(\".facet-checkbox:checked\").each(function (i, element) {\r\n valueGuids.push($(element).data(\"valueGuid\"));\r\n });\r\n if (valueGuids.length) {\r\n urlUtils.pushParamIntoLink(\"filters\", valueGuids.join('|'));\r\n }\r\n else\r\n urlUtils.popParamFromLink(\"filters\");\r\n }\r\n\r\n function displayCategoryFilters(generatedHtml) {\r\n $(\".category-navigation .filter\").html(generatedHtml);\r\n $(\".category-navigation .filter .filter-link\").off(\"click\").on(\"click\", categoryFilterClicked);\r\n }\r\n\r\n function categoryFilterClicked(event) {\r\n if ($(this).hasClass(\"current\")) return; // This category is already selected. Nothing to do.\r\n $(\".category-navigation .filter .filter-link.current\").removeClass(\"current\");\r\n $(this).addClass(\"current\");\r\n currentCategoryFilter = $(this).data(\"categoryId\");\r\n executeSearch(null, true);\r\n }\r\n\r\n function spinner(what) {\r\n if (what === \"show\") { \r\n $(\"#products-index-spinner\").removeClass(\"d-none\");\r\n if(generateCategoryFilters) $(\".category-navigation .spinner-wrapper\").removeClass(\"d-none\");\r\n }\r\n else {\r\n $(\"#products-index-spinner\").addClass(\"d-none\");\r\n if (generateCategoryFilters) $(\".category-navigation .spinner-wrapper\").addClass(\"d-none\");\r\n }\r\n }\r\n\r\n var pageSize = $(window).width() < 1024\r\n ? Number($(\"#products-index\").data(\"productsPerPageMobile\"))\r\n : Number($(\"#products-index\").data(\"productsPerPageDesktop\"));\r\n var currentDisplayCountLimit = pageSize;\r\n\r\n function setScrollLoading() {\r\n scrollDebounce = true;\r\n $(window).on(\"scroll\", function () {\r\n if (scrollDebounce) {\r\n scrollDebounce = false;\r\n var productsIndexDiv = $(\"#products-index\");\r\n var offset = productsIndexDiv.offset();\r\n var top = offset.top;\r\n var bottom = top + productsIndexDiv.height(); \r\n if (window.scrollY + window.innerHeight >= bottom) {\r\n var total = $(\"#products-index .products-index-item\").length;\r\n if (currentDisplayCountLimit >= total) return;\r\n currentDisplayCountLimit += pageSize;\r\n if (currentDisplayCountLimit > total) currentDisplayCountLimit = total;\r\n shuffle.filter(shuffleInstance, currentDisplayCountLimit);\r\n }\r\n\r\n setTimeout(function () { scrollDebounce = true; }, 200);\r\n }\r\n });\r\n }\r\n\r\n setScrollLoading();\r\n filterFacetsPosition.init();\r\n initClickHandlers();\r\n var generateCategoryFilters = $(\"#products-index\").data(\"isCollectionCategory\");\r\n var currentCategoryFilter = \"0\";\r\n\r\n var shuffleInstance = shuffle.init(\"#products-index\", \".products-index-item\");\r\n\r\n executeSearch(null, null, true); // execute initial search\r\n\r\n});\ndefine(\"ProductsIndex/main\", function(){});\n\n" ] }