{"version":3,"file":"jquery.plugins.min.js","sources":["jquery.plugins.js"],"sourcesContent":["(function ($, _) {\r\n function ajaxFailHandler(errResp) {\r\n var responseJson = JSON.parse(errResp.responseText);\r\n var message = responseJson.Message ? responseJson.Message : errResp.statusText;\r\n window.PubSub.publish('notification.error', message);\r\n };\r\n\r\n //#region Jquery extensions\r\n /* Check that value in textbox higher or equal to minimum quantity */\r\n $.minQuantityCheck = function (txbsel, minqty, msgcontsel, msg) {\r\n var t = $(txbsel);\r\n var c = $(msgcontsel);\r\n t.keyup(function () {\r\n c.find('span.MinQtyError').remove();\r\n c.find('span').filter(function () { return $(this).text() == msg; }).remove();\r\n\r\n if (t.length > 0 && t.val().length > 0 && parseFloat(t.val().replace(',', '.')) < parseFloat(minqty)) {\r\n c.append('' + msg + '');\r\n }\r\n\r\n //Retrigger set equal hights\r\n window.SetEqualHeights();\r\n });\r\n };\r\n\r\n /* Bring postal code lookup */\r\n $.getPostalCodeInfo = function (postalCode, callback) {\r\n if (!postalCode || postalCode.length !== 4 || $.isNumeric(postalCode) === false) {\r\n if (callback) {\r\n callback({ result: \"Ugyldig postnummer\", valid: false });\r\n }\r\n\r\n return;\r\n }\r\n\r\n if (postalCode.length === 4) {\r\n var url = \"//fraktguide.bring.no/fraktguide/api/postalCode.json?country=no&pnr=\" + postalCode + \"&callback=?\";\r\n $.getJSON(url, callback);\r\n }\r\n };\r\n\r\n /* Dimension details loader */\r\n $.dimLoader = function (options) {\r\n var o = $.extend({\r\n itemId: 0,\r\n imgWidth: 120,\r\n imgMod: 'crop=none',\r\n drp1: '',\r\n drp2: '',\r\n drp3: '',\r\n prodNo: '',\r\n stock: '',\r\n price: '',\r\n orig: '',\r\n disc: '',\r\n image: '',\r\n error: '',\r\n buyRow: '',\r\n priceFrom: '',\r\n loadImg: window.R + 'Startup/Pics/wait3.gif',\r\n //usePrice: 1, <-- PriceField SHOULD NOT BE HARDCODED (UMWC-319)\r\n errHandler: null,\r\n okHandler: null\r\n }, options || {});\r\n\r\n var loadImg = '\"loading...\"';\r\n var d1 = $(o.drp1),\r\n d2 = $(o.drp2),\r\n d3 = $(o.drp3),\r\n drp = d1.add(d2).add(d3),\r\n prodNo = $(o.prodNo),\r\n stock = $(o.stock),\r\n price = $(o.price),\r\n orig = $(o.orig),\r\n disc = $(o.disc),\r\n image = $(o.image),\r\n error = $(o.error),\r\n buyRow = $(o.buyRow);\r\n\r\n if (drp.length > 0) {\r\n //Hookup change event\r\n drp.change(function () {\r\n //Set loading image\r\n prodNo.add(stock).add(price).add(orig).add(disc).html(loadImg);\r\n\r\n //Check if all dims are selected\r\n var allSel = drp.filter(function () { return jQuery(\"option:selected\", this).val() !== \"0\"; }).length === drp.length;\r\n\r\n //Fetch dim details\r\n $.publicFetch({\r\n handler: \"ProductData\",\r\n data: {\r\n a: \"GetDimDetails\",\r\n ItemID: o.itemId,\r\n Dim1: d1.length > 0 ? d1.find(\"option:selected\").val() : \"0\",\r\n Dim2: d2.length > 0 ? d2.find(\"option:selected\").val() : \"0\",\r\n Dim3: d3.length > 0 ? d3.find(\"option:selected\").val() : \"0\",\r\n ImageWidth: o.imgWidth,\r\n ImgMod: o.imgMod,\r\n usePrice: o.usePrice\r\n },\r\n success: function (d) {\r\n //Allow buy\r\n buyRow.css(\"display\", d.AllowBuy === true || allSel === false ? \"\" : \"none\");\r\n //Product number\r\n prodNo.text(d.ProdNo);\r\n //Stock text\r\n stock.text(d.StockText);\r\n stock.css(\"color\", d.StockColor);\r\n //Price\r\n price.text((allSel === false ? o.priceFrom : \"\") + d.Price);\r\n //Original price\r\n orig.text(d.OriginalPrice);\r\n //Discount price\r\n disc.text(d.Discount);\r\n //Image\r\n if (d.ImageURL.length > 0) {\r\n //Set image url\r\n image.attr(\"src\", d.ImageURL);\r\n // Set link to image src\r\n if (d.ImageLBURL) {\r\n image.closest('a.ImageLink').attr('href', d.ImageLBURL).attr('title', d.ImageText ? d.ImageText : d.ProdNo);\r\n }\r\n }\r\n\r\n if (o.okHandler && $.isFunction(o.okHandler)) {\r\n o.okHandler.call(this, d);\r\n }\r\n\r\n if (typeof (window.PubSub) !== 'undefined') {\r\n window.PubSub.publish('product.dimproduct.update', d);\r\n }\r\n },\r\n error: function (err) {\r\n if (error.hasClass('ErrMsg')) { error.text(err.Message); }\r\n else {\r\n if (error.find('.ErrMsg').length > 0) { error.find('.ErrMsg').text(err.Message); }\r\n else { error.append('' + err.Message + ''); }\r\n }\r\n\r\n prodNo.add(stock).add(price).add(orig).add(disc).html(\"\");\r\n\r\n if (o.errHandler && $.isFunction(o.errHandler)) {\r\n o.errHandler.call(this, err);\r\n }\r\n }\r\n });\r\n });\r\n }\r\n };\r\n $.loadDimProdInfo = function (options) {\r\n var o = $.extend({\r\n itemId: 0,\r\n imgWidth: 120,\r\n imgMod: 'crop=none',\r\n dim1Val: '',\r\n dim2Val: '',\r\n dim3Val: '',\r\n prodNo: '',\r\n stock: '',\r\n price: '',\r\n orig: '',\r\n disc: '',\r\n image: '',\r\n error: '',\r\n buyRow: '',\r\n origRow: '',\r\n discRow: '',\r\n priceFrom: '',\r\n loadImg: window.R + 'Startup/Pics/wait3.gif',\r\n //usePrice: 1, <-- PriceField SHOULD NOT BE HARDCODED (UMWC-319)\r\n loadDimProdImg: true,\r\n additionalReqParams: {},\r\n dimImageShouldDifferFromMain: false,\r\n mainProdImageId: 0,\r\n errHandler: null,\r\n okHandler: null,\r\n priceVisible: true\r\n }, options || {});\r\n\r\n var loadImg = '\"loading...\"',\r\n prodNo = $(o.prodNo),\r\n stock = $(o.stock),\r\n price = $(o.price),\r\n orig = $(o.orig),\r\n disc = $(o.disc),\r\n image = $(o.image),\r\n error = $(o.error),\r\n buyRow = $(o.buyRow),\r\n origRow = $(o.origRow),\r\n discRow = $(o.discRow);\r\n\r\n //Set loading image\r\n prodNo.html(loadImg);\r\n\r\n var reqParams = $.extend(o.additionalReqParams, {\r\n a: \"GetDimDetails\",\r\n ItemID: o.itemId,\r\n Dim1: o.dim1Val ? o.dim1Val : \"0\",\r\n Dim2: o.dim2Val ? o.dim2Val : \"0\",\r\n Dim3: o.dim3Val ? o.dim3Val : \"0\",\r\n ImageWidth: o.imgWidth,\r\n ImgMod: o.imgMod,\r\n usePrice: o.usePrice,\r\n priceVisible: o.priceVisible\r\n });\r\n\r\n //Fetch dim details\r\n $.publicFetch({\r\n handler: \"ProductData\",\r\n data: reqParams,\r\n success: function (d) {\r\n //Allow buy\r\n buyRow.css(\"display\", d.AllowBuy === true ? \"\" : \"none\");\r\n //Product number\r\n prodNo.text(d.ProdNo);\r\n //Stock text\r\n stock.text(d.StockText);\r\n stock.css(\"color\", d.StockColor);\r\n //Price\r\n var $priceText = price.find('.notranslate, .PriceValue');\r\n if ($priceText.length > 0) {\r\n $priceText.html(d.Price);\r\n } else {\r\n // Try to keep VAT text if found\r\n price.contents().filter(function () { return this.className != 'PriceVatTxt'; }).remove();\r\n price.prepend(document.createTextNode(d.Price + ' '));\r\n }\r\n price.find('.notranslate.PriceValue.ExclVat').html(d.PriceExclVat);\r\n price.find('.notranslate.PriceValue.InclVat').html(d.PriceInclVat);\r\n\r\n if (d.HasDiscount) {\r\n origRow.show();\r\n discRow.show();\r\n //Original price\r\n var $origPriceText = orig.find('.notranslate, .OriginalPriceValue');\r\n if ($origPriceText.length > 0) {\r\n $origPriceText.text(d.OriginalPrice);\r\n } else {\r\n // Try to keep VAT text if found\r\n orig.contents().filter(function() { return this.className != 'PriceVatTxt'; }).remove();\r\n orig.prepend(document.createTextNode(d.OriginalPrice + ' '));\r\n }\r\n //Discount price\r\n var $discountText = disc.find('.notranslate, .DiscountValue');\r\n if ($discountText.length > 0) {\r\n $discountText.text(d.Discount);\r\n } else {\r\n // Try to keep VAT text if found\r\n disc.contents().filter(function() { return this.className != 'PriceVatTxt'; }).remove();\r\n disc.prepend(document.createTextNode(d.Discount + ' '));\r\n }\r\n } else {\r\n origRow.hide();\r\n discRow.hide();\r\n }\r\n //Image\r\n if (d.ImageURL.length > 0 && o.loadDimProdImg && !(o.dimImageShouldDifferFromMain && d.ImageID == o.mainProdImageId)) {\r\n //Set image url\r\n image.attr(\"src\", d.ImageURL);\r\n if (d.ImageMaxWidth) {\r\n image.css('max-width', d.ImageMaxWidth + 'px');\r\n }\r\n // Set link to image src\r\n if (d.ImageLBURL) {\r\n image.closest('a.ImageLink').attr('href', d.ImageLBURL).attr('title', d.ImageText ? d.ImageText : d.ProdNo);\r\n }\r\n }\r\n // Replacement product\r\n if (d.ReplacementProductInfo) {\r\n if (o.context) {\r\n o.context.find('.ReplacementProductRow').empty().html(d.ReplacementProductInfo).show();\r\n }\r\n\r\n window.PubSub.publish('notification.warning', d.ReplacementProductInfo);\r\n } else {\r\n if (o.context) {\r\n o.context.find('.ReplacementProductRow').empty().hide();\r\n }\r\n }\r\n\r\n if (o.okHandler && $.isFunction(o.okHandler)) {\r\n o.okHandler.call(this, d);\r\n }\r\n\r\n if (typeof (window.PubSub) !== 'undefined') {\r\n window.PubSub.publish('product.dimproduct.update', d);\r\n }\r\n },\r\n error: function (err) {\r\n if (error.hasClass('ErrMsg')) { error.text(err.Message); }\r\n else {\r\n if (error.find('.ErrMsg').length > 0) { error.find('.ErrMsg').text(err.Message); }\r\n else { error.append('' + err.Message + ''); }\r\n }\r\n\r\n prodNo.add(stock).add(price).add(orig).add(disc).html(\"\");\r\n if (o.errHandler && $.isFunction(o.errHandler)) {\r\n o.errHandler.call(this, err);\r\n }\r\n }\r\n });\r\n };\r\n\r\n /* Auto-grow input */\r\n $.fn.autoGrowInput = function (o) {\r\n o = $.extend({\r\n maxWidth: 1000,\r\n minWidth: 0,\r\n comfortZone: 70\r\n }, o);\r\n\r\n this.filter('input:text').each(function () {\r\n var minWidth = o.minWidth || $(this).width(),\r\n val = '',\r\n input = $(this),\r\n testSubject = $('
').css({\r\n position: 'absolute',\r\n top: -9999,\r\n left: -9999,\r\n width: 'auto',\r\n fontSize: input.css('fontSize'),\r\n fontFamily: input.css('fontFamily'),\r\n fontWeight: input.css('fontWeight'),\r\n letterSpacing: input.css('letterSpacing'),\r\n whiteSpace: 'nowrap'\r\n }),\r\n check = function () {\r\n if (val === (val = input.val())) { return; }\r\n\r\n // Enter new content into testSubject\r\n var escaped = val.replace(/&/g, '&').replace(/\\s/g, ' ').replace(//g, '>');\r\n testSubject.html(escaped);\r\n\r\n // Calculate new width + whether to change\r\n var testerWidth = testSubject.width(),\r\n newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,\r\n currentWidth = input.width(),\r\n isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth) || (newWidth > minWidth && newWidth < o.maxWidth);\r\n\r\n // Animate width\r\n if (isValidWidthChange) {\r\n input.width(newWidth);\r\n }\r\n };\r\n\r\n testSubject.insertAfter(input);\r\n\r\n $(this).bind('keyup keydown blur update', check);\r\n });\r\n\r\n return this;\r\n };\r\n\r\n /* Public AJAX fetch */\r\n $.publicFetch = function (options) {\r\n //Build options\r\n options = $.extend({\r\n handler: \"\",\r\n data: {},\r\n success: undefined,\r\n error: undefined,\r\n complete: undefined,\r\n type: 'GET'\r\n }, options || {});\r\n\r\n //Shorthand\r\n var o = options;\r\n\r\n //Append page and item id\r\n o.data.BasePageID = BasePageID;\r\n o.data.BaseItemID = BaseItemID;\r\n\r\n //Ajax\r\n if (o.handler.length > 0) {\r\n return $.ajax({\r\n url: window.R + \"Handlers/Public/\" + o.handler + \".ashx\",\r\n data: o.data,\r\n success: function(data) {\r\n if (o.success !== undefined) {\r\n o.success(data);\r\n }\r\n },\r\n error: function(err, type) {\r\n //Parse error message\r\n var msg;\r\n try {\r\n msg = $.parseJSON(err.responseText);\r\n } catch (ex) {\r\n msg = { Message: err.responseText };\r\n }\r\n\r\n //Call error callback\r\n if (o.error !== undefined) {\r\n o.error(msg || {}, type);\r\n }\r\n },\r\n complete: options.complete,\r\n type: options.type\r\n });\r\n } else {\r\n throw 'A handler was not defined in the options when calling publicFetch';\r\n }\r\n };\r\n\r\n /* Cookie */\r\n $.cookie = function (key, value, options) {\r\n // key and value given, set cookie...\r\n if (arguments.length > 1 && (value === null || typeof value !== \"object\")) {\r\n options = $.extend({}, options);\r\n\r\n if (value === null) {\r\n options.expires = -1;\r\n }\r\n\r\n if (typeof options.expires === 'number') {\r\n var days = options.expires, t = options.expires = new Date();\r\n t.setDate(t.getDate() + days);\r\n }\r\n\r\n return (document.cookie = [\r\n encodeURIComponent(key), '=',\r\n options.raw ? String(value) : encodeURIComponent(String(value)),\r\n options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE\r\n options.path ? '; path=' + options.path : '',\r\n options.domain ? '; domain=' + options.domain : '',\r\n options.secure ? '; secure' : ''\r\n ].join(''));\r\n }\r\n\r\n // key and possibly options given, get cookie...\r\n options = value || {};\r\n var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;\r\n return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;\r\n };\r\n\r\n /* check and uncheck */\r\n $.fn.extend({\r\n check: function () {\r\n return this.filter(\":radio, :checkbox\").attr(\"checked\", true);\r\n },\r\n uncheck: function () {\r\n return this.filter(\":radio, :checkbox\").removeAttr(\"checked\");\r\n }\r\n });\r\n\r\n /* inheritance */\r\n $.inherit = (function () {\r\n function intermediate() { }\r\n\r\n return function (child, parent) {\r\n intermediate.prototype = parent.prototype;\r\n child.prototype = new intermediate;\r\n child.prototype.constructor = child;\r\n child.superproto = parent.prototype;\r\n return child;\r\n };\r\n })();\r\n\r\n /* Dimension view builders */\r\n function baseDimBuilder(dimIndex, viewProductContext, sortBy, groupBy, onClickHandler, onChangeHandler) {\r\n this.$controlElem = null;\r\n this.data = null;\r\n this.itemClass = null;\r\n this.dimNameContainerClass = \"DimensionTxt\";\r\n this.dimInfo = $.extend({}, viewProductContext); // copy context\r\n this.options = viewProductContext.options;\r\n this.dimensionIndex = dimIndex;\r\n this.sortBy = sortBy;\r\n this.canChangeMainImage = false;\r\n this.groupBy = groupBy ? new Function('elem', groupBy) : function (dimElem) {\r\n return dimElem.val.replace(/[^0-9]/g, '');\r\n };\r\n this.onClickHandler = onClickHandler;\r\n this.onChangeHandler = onChangeHandler;\r\n // Workaround for the backward compatibility\r\n if (!viewProductContext.dimViewsInfo && viewProductContext.dimTypeMap) {\r\n // Old logic\r\n var oldStructureDimTypeMap = viewProductContext.dimTypeMap[this.dimensionIndex];\r\n if (oldStructureDimTypeMap != null) {\r\n this.dimInfo.dimTypeInfo = {\r\n DimTypeId: oldStructureDimTypeMap.dimTypeId,\r\n DimTypeName: oldStructureDimTypeMap.dimTypeName,\r\n DimViewType: this.getControlViewType(),\r\n SortBy: sortBy,\r\n GroupBy: groupBy,\r\n PositionInDimArray: dimIndex\r\n };\r\n }\r\n }\r\n else {\r\n this.dimInfo.dimTypeInfo = _.find(viewProductContext.dimViewsInfo, function (dimViewInfo) {\r\n return dimViewInfo.PositionInDimArray === dimIndex;\r\n });\r\n }\r\n\r\n this.dimControlId = 'dimControl_' + this.dimInfo.dimTypeInfo.DimTypeId + '_' + new Date().getTime();\r\n\r\n this.sessionStorageObject = new SessionStorageObject(this.getControlViewType());\r\n\r\n this.isNotyShown = false;\r\n\r\n this.init();\r\n }\r\n baseDimBuilder.prototype = (function () {\r\n // the prototype itself\r\n return {\r\n constructor: baseDimBuilder,\r\n getSelectedValue: function () {\r\n if (this.itemClass) {\r\n var selectedElem = $('.' + this.itemClass + '.selected', this.$controlElem);\r\n return selectedElem.length === 1 ? selectedElem.attr('data-dimId') : 0;\r\n }\r\n throw \"getSelectedValue method is not implemented \" + this.getControlViewType();\r\n },\r\n setSelectedValue: function (selValue, fireOnChangeEvent, isPreselect) {\r\n if (this.itemClass) {\r\n if (!selValue) return;\r\n var itemToSelect = $('.' + this.itemClass + '[data-dimId=\"' + selValue + '\"]:not(.disabled' + (isPreselect ? ',.selected' : '') + ')', this.$controlElem);\r\n if (itemToSelect.length === 1) {\r\n // Clear previous selection\r\n var prevSelected = $('.' + this.itemClass + '.selected', this.$controlElem);\r\n prevSelected.removeClass('selected');\r\n // Select current item if it is not the same as previous (for deselect emulating)\r\n if (!prevSelected.is(itemToSelect)) {\r\n itemToSelect.addClass('selected');\r\n }\r\n\r\n if (fireOnChangeEvent) {\r\n this.handleEvent(this.onChangeHandler, this.getSelectedValue(), this);\r\n }\r\n }\r\n } else {\r\n throw \"setSelectedValue method is not implemented \" + this.getControlViewType();\r\n }\r\n },\r\n getControlViewType: function () {\r\n return \"baseDimBuilder\";\r\n },\r\n getDimensionsCount: function (activeOnly) {\r\n if (this.itemClass) {\r\n var selector = '.' + this.itemClass + (activeOnly ? ':not(.disabled)' : '');\r\n return $(selector, this.$controlElem).length;\r\n }\r\n throw \"getDimensionsCount method is not implemented \" + this.getControlViewType();\r\n },\r\n filter: function (availableDimIdsArray) {\r\n var self = this;\r\n if (this.itemClass) {\r\n $('.' + this.itemClass + '[data-dimId]', this.$controlElem).each(function () {\r\n var $item = $(this);\r\n var val = parseInt($item.attr('data-dimId'));\r\n if (!val) return;\r\n if (_.contains(availableDimIdsArray, val)) {\r\n $item.toggleClass('disabled', false);\r\n var baseTitle = self.sessionStorageObject.getValue(val + '_baseTitle');\r\n if (baseTitle) {\r\n $item[0].title = baseTitle;\r\n }\r\n } else {\r\n $item.toggleClass('disabled', true);\r\n }\r\n });\r\n }\r\n },\r\n setShowOnly: function(showOnlyDict) {\r\n var self = this;\r\n if (this.itemClass) {\r\n $('.' + this.itemClass + '[data-dimId]', this.$controlElem).each(function() {\r\n var $item = $(this);\r\n var val = parseInt($item.attr('data-dimId'));\r\n if (!val) return;\r\n if (val in showOnlyDict) {\r\n var showOnlyReason = showOnlyDict[val].showOnlyReason;\r\n if (showOnlyReason) {\r\n var originalItemTitle = self.sessionStorageObject.getValue(val + '_baseTitle');\r\n if (!originalItemTitle) {\r\n originalItemTitle = $item[0].title;\r\n self.sessionStorageObject.setValue(val + '_baseTitle', originalItemTitle);\r\n }\r\n $item[0].title = originalItemTitle + ' (' + showOnlyReason + ')';\r\n }\r\n }\r\n });\r\n }\r\n },\r\n resetShowOnly: function () {\r\n var self = this;\r\n if (this.itemClass) {\r\n $('.' + this.itemClass + '[data-dimId]', this.$controlElem).each(function () {\r\n var $item = $(this);\r\n var val = parseInt($item.attr('data-dimId'));\r\n if (!val) return;\r\n\r\n var originalDimName = self.sessionStorageObject.getValue(val + '_baseTitle');\r\n if (originalDimName) {\r\n $item[0].title = originalDimName;\r\n }\r\n });\r\n }\r\n },\r\n handleEvent: function (customHandler, args, ctx) {\r\n if (customHandler && $.isFunction(customHandler)) {\r\n var eventArgs = [];\r\n for (var i = 0; i < args.length; i++) {\r\n eventArgs.push(args[i]);\r\n }\r\n if (!ctx) ctx = this;\r\n customHandler.apply(ctx, [this, eventArgs]);\r\n }\r\n },\r\n _prepareData: function () {\r\n var dimInfo = this.dimInfo;\r\n if (dimInfo && !$.isEmptyObject(dimInfo)) {\r\n // Prepare data for dimension control\r\n var controlContext = this;\r\n var data = {};\r\n for (var prop in dimInfo.dimProds) {\r\n if (dimInfo.dimProds.hasOwnProperty(prop)) {\r\n var val = dimInfo.dimProds[prop];\r\n var dimId = val.dims[controlContext.dimensionIndex];\r\n var isSingleDimensionProd = val.dims.length === 1;\r\n if (!data[dimId]) {\r\n data[dimId] = { id: dimId, val: dimInfo.dimMap[dimId] };\r\n if (isSingleDimensionProd) {\r\n data[dimId].price = val.price;\r\n data[dimId].qty = val.qty;\r\n data[dimId].isShowOnly = val.isShowOnly;\r\n data[dimId].showOnlyReason = val.showOnlyReason;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Filter dimensions by url params (if exist). Incident#00060771\r\n var urlDimensionsParam = $.trim($.getQueryStringParam(window.location.search, dimInfo.dimTypeInfo.DimTypeName));\r\n if (urlDimensionsParam) {\r\n var urlDims = urlDimensionsParam.split(',');\r\n data = _.filter(data, function (dim) {\r\n return _.contains(urlDims, dim.val);\r\n });\r\n }\r\n\r\n if (!_.isEmpty(data)) {\r\n // Sort if needed\r\n controlContext.data = controlContext.sortBy ? _.sortBy(data, controlContext.sortBy == 'val' ? 'val' : new Function('elem', controlContext.sortBy)) : data;\r\n }\r\n }\r\n },\r\n init: function () {\r\n throw \"init method is not implemented in \" + this.getControlViewType();\r\n },\r\n showDimIsNotSelectedTooltip: function () {\r\n var tooltipElem = $('.' + this.dimNameContainerClass, this.$controlElem);\r\n if (!tooltipElem.data('qtip')) {\r\n // Initialize qtip\r\n var tooltipOptions = {\r\n content: {\r\n text: this.options.selectDimMsg + ' ' + this.dimInfo.dimTypeInfo.DimTypeName + ''\r\n },\r\n show: {\r\n event: 'click',\r\n effect: function () {\r\n $(this).fadeIn(400);\r\n }\r\n },\r\n hide: {\r\n target: $('.' + this.itemClass, this.$controlElem),\r\n event: 'click',\r\n effect: function () {\r\n $(this).fadeOut(400);\r\n },\r\n inactive: 3000\r\n },\r\n position: {\r\n my: 'left bottom',\r\n at: 'right center'\r\n },\r\n style: {\r\n classes: 'DimensionIsNotSelectedTooltip'\r\n }\r\n };\r\n tooltipElem.qtip(tooltipOptions);\r\n }\r\n\r\n // Show tooltip\r\n tooltipElem.qtip(\"show\");\r\n },\r\n showDimIsNotSelectedNoty: function () {\r\n if (!this.isNotyShown) {\r\n var self = this;\r\n var notyContract = {\r\n text: this.options.selectDimMsg + ' ' + this.dimInfo.dimTypeInfo.DimTypeName + '',\r\n callback: {\r\n onClose: function() {\r\n self.isNotyShown = false;\r\n }\r\n }\r\n };\r\n window.PubSub.publish('notification.warning', notyContract);\r\n this.isNotyShown = true;\r\n }\r\n },\r\n hasSelectedRelatedDimensionImage: function() { return false; },\r\n changeMainImageToRelatedDimensionImage: function () {}\r\n };\r\n })();\r\n $.baseDimBuilder = baseDimBuilder;\r\n\r\n /* Custom fields */\r\n function customFieldsRenderer(customFieldsContainer, cssPrefix, customFields, defaultRequiredMessage, invalidFormatMessage) {\r\n var customFieldObjects = [];\r\n\r\n return {\r\n render: function() {\r\n if (customFieldsContainer && customFields && customFields.length > 0) {\r\n\r\n var visibleCustomFields = customFields.filter(function (field) {\r\n return field.isVisible;\r\n });\r\n\r\n $('.js-custom-field-container', customFieldsContainer).each(function () {\r\n var $customFieldContainer = $(this);\r\n if ($customFieldContainer && $customFieldContainer.data(\"display-type\") === 'editable') {\r\n var editableCustomFields = visibleCustomFields.filter(function (field) {\r\n return field.displayType === 'editable';\r\n });\r\n\r\n if (editableCustomFields.length > 0) {\r\n var id = $customFieldContainer.data(\"id\");\r\n if (id) {\r\n var customField = customFields.find(function (x) { return x.customFieldID === id; });\r\n if (customField) {\r\n var customFieldObject;\r\n var enablePlaceholder = $customFieldContainer.data(\"enable-placeholder\");\r\n switch (customField.editorType) {\r\n case \"int\":\r\n customFieldObject = new wholeNumber(customField, $customFieldContainer, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage);\r\n customFieldObjects.push(customFieldObject);\r\n break;\r\n case \"textstring\":\r\n customFieldObject = new textString(customField, $customFieldContainer, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage);\r\n customFieldObjects.push(customFieldObject);\r\n break;\r\n case \"checkbox\":\r\n customFieldObject = new checkboxCustomField(customField, $customFieldContainer, cssPrefix, defaultRequiredMessage, invalidFormatMessage);\r\n customFieldObjects.push(customFieldObject);\r\n break;\r\n default:\r\n break;\r\n }\r\n\r\n if (customFieldObject)\r\n customFieldObject.render(customField, cssPrefix);\r\n }\r\n }\r\n\r\n }\r\n }\r\n });\r\n }\r\n },\r\n validate: function () {\r\n return customFieldObjects.every(function (customFieldObject) { return customFieldObject.validate()});\r\n }\r\n };\r\n }\r\n\r\n function customFieldBase(customField, container, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage) {\r\n this.customField = customField;\r\n this.container = container;\r\n this.cssPrefix = cssPrefix;\r\n this.defaultRequiredMessage = defaultRequiredMessage;\r\n this.invalidFormatMessage = invalidFormatMessage;\r\n this.customFieldMethods = customFieldHelper(customField, enablePlaceholder);\r\n }\r\n customFieldBase.prototype.render = function () {};\r\n customFieldBase.prototype.validate = function () { return true; };\r\n\r\n function customFieldTextInput(customField, container, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage) {\r\n customFieldBase.call(this, customField, container, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage);\r\n this.input = null;\r\n }\r\n\r\n customFieldTextInput.prototype = Object.create(customFieldBase.prototype);\r\n customFieldTextInput.prototype.render = function () {\r\n this.input = this.customFieldMethods.createInputControl(this.cssPrefix);\r\n if (this.input) {\r\n $(this.input).addClass('form-control');\r\n\r\n if (this.customField.isRequired) {\r\n $(this.input).attr('data-rule-required', 'true');\r\n if (this.customField.requiredRegex)\r\n $(this.input).attr('data-rule-pattern', this.customField.requiredRegex);\r\n $(this.input).attr('data-msg-required',\r\n this.customField.requiredErrorMessage\r\n ? this.customField.requiredErrorMessage\r\n : this.defaultRequiredMessage);\r\n if (this.customField.requiredRegex && this.invalidFormatMessage)\r\n $(this.input).attr('data-msg-pattern', this.invalidFormatMessage);\r\n }\r\n }\r\n this.container.append(this.input);\r\n };\r\n customFieldTextInput.prototype.validate = function () {\r\n $(this.input).keypress(function () {\r\n validate(this);\r\n });\r\n\r\n function validate(input) {\r\n var result = $('form').validate().element(input);\r\n\r\n if (!result)\r\n $(input).parent().addClass('has-error');\r\n else\r\n $(input).parent().removeClass('has-error');\r\n\r\n return result;\r\n }\r\n return validate(this.input);\r\n };\r\n\r\n\r\n function wholeNumber(customField, container, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage) {\r\n customFieldTextInput.call(this, customField, container, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage);\r\n }\r\n\r\n wholeNumber.prototype = Object.create(customFieldBase.prototype);\r\n wholeNumber.prototype.render = function () {\r\n customFieldTextInput.prototype.render.call(this);\r\n if (this.input) {\r\n $(this.input).numeric(false);\r\n $(this.input).addClass('integer');\r\n if (!this.customField.requiredRegex)\r\n $(this.input).attr('data-rule-pattern', '\\\\d+');\r\n }\r\n };\r\n wholeNumber.prototype.validate = function () {\r\n if (!this.input)\r\n throw 'Whole number input control is not rendered!';\r\n\r\n return customFieldTextInput.prototype.validate.call(this);\r\n };\r\n\r\n function textString(customField, container, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage) {\r\n customFieldTextInput.call(this, customField, container, cssPrefix, enablePlaceholder, defaultRequiredMessage, invalidFormatMessage);\r\n }\r\n\r\n textString.prototype = Object.create(customFieldBase.prototype);\r\n textString.prototype.render = function () {\r\n customFieldTextInput.prototype.render.call(this);\r\n };\r\n textString.prototype.validate = function () {\r\n if (!this.input)\r\n throw 'Text string input control is not rendered!';\r\n\r\n return customFieldTextInput.prototype.validate.call(this);\r\n };\r\n\r\n function checkboxCustomField(customField, container, cssPrefix, defaultRequiredMessage, invalidFormatMessage) {\r\n customFieldBase.call(this, customField, container, cssPrefix, false, defaultRequiredMessage, invalidFormatMessage);\r\n this.input = null;\r\n }\r\n\r\n checkboxCustomField.prototype = Object.create(customFieldBase.prototype);\r\n checkboxCustomField.prototype.render = function () {\r\n this.input = this.customFieldMethods.createCheckboxControl(this.cssPrefix);\r\n if (this.input) {\r\n $(this.input).numeric(false);\r\n\r\n if (this.customField.isRequired) {\r\n $(this.input).attr('data-rule-required', 'true');\r\n\r\n $(this.input).attr('data-msg-required',\r\n this.customField.requiredErrorMessage\r\n ? this.customField.requiredErrorMessage\r\n : this.defaultRequiredMessage);\r\n }\r\n }\r\n this.container.append(this.input);\r\n };\r\n\r\n function customFieldHelper(customField, enablePlaceholder) {\r\n var html = new htmlHelper();\r\n\r\n function isNullOrWhitespace(inputStr) {\r\n if (typeof inputStr === 'undefined' || inputStr === null) return true;\r\n return inputStr.replace(/\\s/g, '').length < 1;\r\n }\r\n\r\n function getInternalCustomFieldId(cssPrefix, customField) {\r\n return !isNullOrWhitespace(customField.alias) ? cssPrefix + '_cf_' + customField.alias + '_' + customField.customFieldID : cssPrefix + '_cf_' + customField.customFieldID;\r\n }\r\n\r\n return {\r\n createInputControl: function(cssPrefix) {\r\n var id = getInternalCustomFieldId(cssPrefix, customField);\r\n var attributes = { \"data-customfieldid\": customField.customFieldID };\r\n var defaultCustomFieldCssClass = \"js-custom-field\";\r\n\r\n var inputStyleString = '';\r\n if (customField.heightInPx > 0)\r\n inputStyleString += 'height:' + customField.heightInPx + 'px;';\r\n\r\n if (customField.widthInPx > 0)\r\n inputStyleString += 'width:' + customField.widthInPx + 'px;';\r\n\r\n if (inputStyleString !== '')\r\n attributes[\"style\"] = inputStyleString;\r\n\r\n if (customField.maxLength > 0)\r\n attributes[\"maxlength\"] = customField.maxLength;\r\n\r\n if (enablePlaceholder)\r\n attributes[\"placeholder\"] = customField.label;\r\n\r\n attributes[\"autocomplete\"] = \"off\";\r\n\r\n var inputControl = html.input(id, \"text\", defaultCustomFieldCssClass, customField.guiFriendlyValue, attributes);\r\n return inputControl;\r\n },\r\n createCheckboxControl: function(cssPrefix) {\r\n var id = getInternalCustomFieldId(cssPrefix, customField);\r\n var attributes = { \"data-customfieldid\": customField.customFieldID };\r\n var defaultCustomFieldCssClass = \"js-custom-field\";\r\n\r\n var inputStyleString = '';\r\n if (customField.heightInPx > 0)\r\n inputStyleString += 'height:' + customField.heightInPx + 'px;';\r\n\r\n if (customField.widthInPx > 0)\r\n inputStyleString += 'width:' + customField.widthInPx + 'px;';\r\n\r\n if (inputStyleString !== '')\r\n attributes[\"style\"] = inputStyleString;\r\n\r\n var initialValue = customField.isRequired || customField.value.ValueBit === true;\r\n if (initialValue)\r\n attributes['checked'] = 'checked';\r\n\r\n if (customField.isRequired)\r\n attributes['disabled'] = 'disabled';\r\n\r\n var inputControl = html.input(id, \"checkbox\", defaultCustomFieldCssClass, initialValue, attributes);\r\n return inputControl;\r\n }\r\n };\r\n }\r\n\r\n function htmlHelper() {\r\n return {\r\n input: function(id, type, classes, value, attributes) {\r\n var input = document.createElement('input');\r\n $(input).attr('id', id);\r\n $(input).attr('type', type);\r\n $(input).attr('class', classes);\r\n $(input).attr(attributes);\r\n $(input).val(value);\r\n return input;\r\n }\r\n };\r\n }\r\n\r\n $.customFieldsRenderer = customFieldsRenderer;\r\n\r\n /* jQuery deparam function to convert parameterized (querystring) to object. */\r\n $.deparam = function (params, coerce) {\r\n var obj = {},\r\n coerce_types = { 'true': !0, 'false': !1, 'null': null };\r\n\r\n // Iterate over all name=value pairs.\r\n $.each(params.replace(/\\+/g, ' ').split('&'), function (j, v) {\r\n var param = v.split('='),\r\n key = decodeURIComponent(param[0]),\r\n val,\r\n cur = obj,\r\n i = 0,\r\n // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it\r\n // into its component parts.\r\n keys = key.split(']['),\r\n keys_last = keys.length - 1;\r\n\r\n // If the first keys part contains [ and the last ends with ], then []\r\n // are correctly balanced.\r\n if (/\\[/.test(keys[0]) && /\\]$/.test(keys[keys_last])) {\r\n // Remove the trailing ] from the last keys part.\r\n keys[keys_last] = keys[keys_last].replace(/\\]$/, '');\r\n\r\n // Split first keys part into two parts on the [ and add them back onto\r\n // the beginning of the keys array.\r\n keys = keys.shift().split('[').concat(keys);\r\n\r\n keys_last = keys.length - 1;\r\n } else {\r\n // Basic 'foo' style key.\r\n keys_last = 0;\r\n }\r\n\r\n // Are we dealing with a name=value pair, or just a name?\r\n if (param.length === 2) {\r\n val = decodeURIComponent(param[1]);\r\n\r\n // Coerce values.\r\n if (coerce) {\r\n val = val && !isNaN(val) ? +val // number\r\n : val === 'undefined' ? undefined // undefined\r\n : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null\r\n : val; // string\r\n }\r\n\r\n if (keys_last) {\r\n // Complex key, build deep object structure based on a few rules:\r\n // * The 'cur' pointer starts at the object top-level.\r\n // * [] = array push (n is set to array length), [n] = array if n is\r\n // numeric, otherwise object.\r\n // * If at the last keys part, set the value.\r\n // * For each keys part, if the current level is undefined create an\r\n // object or array based on the type of the next keys part.\r\n // * Move the 'cur' pointer to the next level.\r\n // * Rinse & repeat.\r\n for (; i <= keys_last; i++) {\r\n key = keys[i] === '' ? cur.length : keys[i];\r\n cur = cur[key] = i < keys_last\r\n ? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : [])\r\n : val;\r\n }\r\n\r\n } else {\r\n // Simple key, even simpler rules, since only scalars and shallow\r\n // arrays are allowed.\r\n\r\n if ($.isArray(obj[key])) {\r\n // val is already an array, so push on the next value.\r\n obj[key].push(val);\r\n\r\n } else if (obj[key] !== undefined) {\r\n // val isn't an array, but since a second value has been specified,\r\n // convert val into an array.\r\n obj[key] = [obj[key], val];\r\n\r\n } else {\r\n // val is a scalar.\r\n obj[key] = val;\r\n }\r\n }\r\n\r\n } else if (key) {\r\n // No value was defined, so set something meaningful.\r\n obj[key] = coerce\r\n ? undefined\r\n : '';\r\n }\r\n });\r\n\r\n return obj;\r\n };\r\n\r\n /* Buy feedback popup */\r\n var $buyFeedbackCont = null;\r\n $.showBuyFeedbackPopup = function (popupTemplate, feedbackData) {\r\n // Populate template\r\n var popupHtml = _.template(popupTemplate, feedbackData);\r\n\r\n var $popupDialog = $(popupHtml).dialog({\r\n autoOpen: true,\r\n modal: true,\r\n resizable: false,\r\n title: feedbackData.labels.additionalText,\r\n width: '640px',\r\n dialogClass: 'popup-after-buy',\r\n draggable: true,\r\n appendTo: 'body',\r\n close: function() {\r\n $popupDialog.dialog('destroy').remove();\r\n $buyFeedbackCont = null;\r\n window.PublicEStore.unsubscribe(removeSubscriptionToken);\r\n window.PublicEStore.unsubscribe(emptySubscriptionToken);\r\n window.PublicEStore.unsubscribe(addSubscriptionToken);\r\n },\r\n open: function(event, ui){\r\n var thisOne = $(this);\r\n var wholePopUp = thisOne.closest('.ui-dialog');\r\n thisOne.find('.js-PopUpContinue').bind('click', function(){\r\n thisOne.dialog('close');\r\n });\r\n wholePopUp.next('.ui-widget-overlay').bind('click',function(){\r\n thisOne.dialog('close');\r\n });\r\n }\r\n });\r\n\r\n $buyFeedbackCont = $('#orderProductSummary');\r\n\r\n // Setup popup area\r\n $buyFeedbackCont.find('.BuyBtn').click(function (evt) {\r\n evt.stopPropagation();\r\n\r\n var $prodCont = $(this).closest('.js-bfp-rel-item');\r\n var addToCartContract = {\r\n productId: $prodCont.data('productid'),\r\n quantity: $prodCont.find('.QuantityTxb,.QuantityDrp').val()\r\n };\r\n\r\n function addToCartCallback(dataContract) {\r\n _.each(dataContract.result.items,\r\n function(prod) {\r\n if (prod.status.toLowerCase() !== 'ok') {\r\n window.PubSub.publish('notification.error', prod.message);\r\n }\r\n });\r\n }\r\n\r\n $.when(window.PublicEStore.addToCart([addToCartContract])).then(addToCartCallback, ajaxFailHandler);\r\n });\r\n\r\n function updateOrderTotals(infoContract) {\r\n $buyFeedbackCont.find('.js-total-prod-count').text(infoContract.productCount);\r\n $buyFeedbackCont.find('.js-total-price').text(infoContract.totalPrice.toMoney());\r\n }\r\n\r\n function getAndUpdateOrderTotals() {\r\n $.when(window.PublicEStore.getCartInfo(null, true)).then(function(cartInfoContract) {\r\n updateOrderTotals(cartInfoContract.result.cartInfo);\r\n },\r\n ajaxFailHandler);\r\n }\r\n\r\n var $relProdsCont = $buyFeedbackCont.find('.js-bfp-rel-item');\r\n\r\n function removeFromCartCallback(topic, dataContract) {\r\n _.each(dataContract.result.items, function (prod) {\r\n if (prod.status.toLowerCase() === 'ok') {\r\n $relProdsCont.filter('[data-productid=\"' + prod.productID + '\"]').find('.js-add-to-cart').hide();\r\n }\r\n });\r\n getAndUpdateOrderTotals();\r\n }\r\n\r\n function emptyCartCallback(topic, dataContract) {\r\n if (dataContract.status.toLowerCase() === 'ok') {\r\n $relProdsCont.find('.js-add-to-cart').hide();\r\n }\r\n getAndUpdateOrderTotals();\r\n }\r\n\r\n function addToCartEventCallback(topic, contract) {\r\n updateOrderTotals(contract.result.detailedCartInfo.summary);\r\n _.each(contract.result.items, function (prod) {\r\n if (prod.status.toLowerCase() === 'ok') {\r\n // Update total product's count for the current temp order line\r\n var prodContainer = $relProdsCont.filter('[data-productId=\"' + prod.productID + '\"]');\r\n var orderLineQuantityContainer = prodContainer.find('.js-prod-count');\r\n orderLineQuantityContainer.show();\r\n orderLineQuantityContainer.text(prod.totalQuantityInTempOrderLine);\r\n\r\n // Animate action\r\n var addToCartIconContainer = prodContainer.find('.js-add-to-cart');\r\n if (addToCartIconContainer.length > 0) {\r\n addToCartIconContainer.show();\r\n prodContainer.effect('transfer', { to: addToCartIconContainer }, 500, function () {\r\n addToCartIconContainer.effect('bounce', null, 500);\r\n });\r\n }\r\n }\r\n });\r\n }\r\n\r\n var removeSubscriptionToken = window.PublicEStore.subscribe('estore.callback.shopcart.removefromcart', removeFromCartCallback);\r\n var emptySubscriptionToken = window.PublicEStore.subscribe('estore.callback.shopcart.emptycart', emptyCartCallback);\r\n var addSubscriptionToken = window.PublicEStore.subscribe('estore.callback.shopcart.addtocart', addToCartEventCallback);\r\n };\r\n\r\n /* Quantity discounts */\r\n $.loadListQuantityDiscounts = function () {\r\n function getProductLists() {\r\n var lists = [];\r\n\r\n //Add 162 and 167\r\n $('div.UC162, div.UC167').each(function () {\r\n var list = $(this);\r\n list.controlId = parseInt(list.attr('id').replace('UC', ''));\r\n list.items = [];\r\n\r\n $('div.ProdItemContainer', list).each(function () {\r\n var item = $(this);\r\n item.itemId = parseInt($('input[type=\"hidden\"]', item).first().val());\r\n item.image = $('img.Image', item);\r\n item.priceText = $('span.PriceTxt', item);\r\n item.price = $('span.Price', item);\r\n item.original = $('span.OriginalPrice', item);\r\n item.discount = $('span.DiscountPrice', item);\r\n\r\n list.items.push(item);\r\n });\r\n\r\n lists.push(list);\r\n });\r\n\r\n //Add 101\r\n $('table.UC101MainContainer').each(function () {\r\n var list = $(this);\r\n list.controlId = parseInt($('td.ListContainer > table', list).first().attr('id').replace('UC', ''));\r\n list.items = [];\r\n\r\n $('td.ProdItemContainer, td.ProdItemContainerAlt', list).each(function () {\r\n var item = $(this);\r\n item.image = $('img.Image', item);\r\n item.itemId = parseInt(item.image.attr('id').replace('img', ''));\r\n item.priceText = $('span.PriceTxt', item);\r\n item.price = $('span.Price span', item);\r\n item.original = $('span.OriginalPrice span', item);\r\n item.discount = $('span.DiscountPrice span', item);\r\n\r\n list.items.push(item);\r\n });\r\n\r\n lists.push(list);\r\n });\r\n\r\n //Add 130\r\n $('table.UC130MainContainer').each(function () {\r\n var list = $(this);\r\n list.controlId = parseInt(list.attr('id').replace('UC', ''));\r\n list.items = [];\r\n\r\n $('td.ProdItemContainer, td.ProdItemContainerAlt', list).each(function () {\r\n var item = $(this);\r\n item.image = $('img.Image', item);\r\n item.itemId = parseInt(item.image.attr('id').replace('img', ''));\r\n item.priceText = $('span.PriceTxt', item);\r\n item.price = $('span.Price span', item);\r\n item.original = $('span.OriginalPrice span', item);\r\n item.discount = $('span.DiscountPrice span', item);\r\n\r\n list.items.push(item);\r\n });\r\n\r\n lists.push(list);\r\n });\r\n\r\n return lists;\r\n };\r\n\r\n //Get product lists on the page\r\n var productLists = getProductLists();\r\n\r\n //Build a list of itemid's\r\n var itemIds = [];\r\n _.each(productLists, function (v) {\r\n itemIds = _.union(itemIds, _.pluck(v.items, 'itemId'));\r\n });\r\n\r\n if (!itemIds || itemIds.length === 0) {\r\n return;\r\n }\r\n\r\n $.publicFetch({\r\n handler: \"EStoreData\",\r\n data: { a: 'CountQuantityDiscountsMulti', itemIds: itemIds.join(',') },\r\n success: function (data) {\r\n if (!data || data.length === 0) {\r\n return;\r\n }\r\n\r\n _.each(productLists, function (list) {\r\n _.each(list.items, function (item) {\r\n var qtyItem = _.find(data, function (val) { return val.itemId === item.itemId; });\r\n if (qtyItem && qtyItem.count > 0) {\r\n item.image.parent().prepend('');\r\n }\r\n });\r\n });\r\n }\r\n });\r\n };\r\n\r\n /* Locale cookies */\r\n $.setLocaleCookie = function (locale) {\r\n $.cookie('PreferredLocale', locale, { expires: 365, path: window.R });\r\n window.PubSub.publish('cookie.local-cookie-set', locale);\r\n };\r\n\r\n /* Currency cookies */\r\n $.setCurrencyCookie = function (currency) {\r\n $.cookie('PreferredCurrency', currency, { expires: 365, path: window.R });\r\n window.PubSub.publish('cookie.currency-cookie-set', currency);\r\n };\r\n $.getCurrencyCookie = function () {\r\n return $.cookie('PreferredCurrency');\r\n };\r\n\r\n /* Query string getter and setter */\r\n $.setQueryStringParam = function (uri, key, value) {\r\n var re = new RegExp(\"([?|&])\" + key + \"=.*?(&|$)\", \"i\");\r\n var separator = uri.indexOf('?') !== -1 ? \"&\" : \"?\";\r\n if (uri.match(re)) {\r\n return uri.replace(re, '$1' + key + \"=\" + value + '$2');\r\n } else {\r\n return uri + separator + key + \"=\" + value;\r\n }\r\n };\r\n $.getQueryStringParam = function (uri, key) {\r\n var regExp = new RegExp('[\\\\?&]' + key + '=([^&#]*)', 'i');\r\n var decoded;\r\n\r\n try {\r\n decoded = decodeURIComponent(uri);\r\n } catch (err) {\r\n console.error(err);\r\n return '';\r\n }\r\n\r\n var val = regExp.exec(decoded);\r\n return val ? decodeURIComponent(val[1].replace(/\\+/g, ' ')) : '';\r\n };\r\n $.removeQueryStringParam = function (uri, key) {\r\n var urlparts = uri.split('?');\r\n if (urlparts.length >= 2) {\r\n var prefix = encodeURIComponent(key) + '=';\r\n var pars = urlparts[1].split(/[&;]/g);\r\n\r\n // reverse iteration as may be destructive\r\n for (var i = pars.length; i-- > 0;) {\r\n if (pars[i].lastIndexOf(prefix, 0) !== -1) {\r\n pars.splice(i, 1);\r\n }\r\n }\r\n\r\n uri = urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');\r\n return uri;\r\n } else {\r\n return uri;\r\n }\r\n }\r\n $.getUrlParamsObj = function (uri) {\r\n var search = uri.substring(1);\r\n return search\r\n ? JSON.parse('{\"' + search.replace(/&/g, '\",\"').replace(/=/g, '\":\"') + '\"}', function (key, value) { return key === '' ? value : decodeURIComponent(value) })\r\n : {};\r\n };\r\n\r\n /* Scroll to element */\r\n $.fn.scrollToThis = function (time, verticalOffset) {\r\n time = typeof (time) != 'undefined' ? time : 800;\r\n verticalOffset = typeof (verticalOffset) != 'undefined' ? verticalOffset : 0;\r\n var element = $(this);\r\n var offset = element.offset();\r\n var offsetTop = offset.top + verticalOffset;\r\n $('html, body').stop().animate({\r\n scrollTop: offsetTop\r\n }, time);\r\n };\r\n\r\n /* To currency formatter */\r\n window.toCurrency = function (prices, currencyCode) {\r\n prices = _.isArray(prices) ? prices : [prices];\r\n // If prices are passed as strings, ensure the decimal separator will be '.' and not ','\r\n var processedPrices = _.map(prices, function (price) {\r\n if (typeof (price) === 'string') {\r\n return price.replace(',', '.');\r\n } else {\r\n return price;\r\n }\r\n });\r\n\r\n var params = { prices: JSON.stringify(processedPrices) };\r\n if (currencyCode) {\r\n params.currency = currencyCode;\r\n }\r\n\r\n return $.get(window.R + 'handlers/public/currencyformatter.ashx', params);\r\n }\r\n\r\n //#endregion Jquery extensions\r\n\r\n //#region Global functions\r\n /* Set equal heights */\r\n window.SetEqualHeights = function () {\r\n //Define context (Controls)\r\n var context = $(\".UC101MainContainer, .UC132MainContainer, .UC130MainContainer, .UC134MainContainer, .UC120MainContainer, .UC111MainContainer, .UC137MainContainer, .UC124MainContainer, .UC162, .UC167, .ListDocuments\");\r\n\r\n //Declare row containers\r\n var cont = context.find(\".ListContainer > table > tbody > tr, .SubListContainer > table > tbody > tr, .DataItemsRow, .SliderDataItemsRow, .SliderContainer\").not('.DisableAutoHeight');\r\n\r\n //Declare column containers, innermost containers first!\r\n var cols = new Array(\".ItemTitleCont\", \".Teaser\", \".Content\", \".ItemTitleContainer\", '.PriceContainer', \".TitleAndTeaserContainer\", '.ProductNumberCont', \".TeaserContainer\", \".DescriptionContainer\", \".ProdDetailsContainer\", \".ContentContainer\", \".RatingContainer\", '.MakeOrderContainer', '.PricesContainer', '.PriceAndBuy', '.DetailsContainer', '.OuterDetailsCont', '.ItemContainer');\r\n //For each row container\r\n cont.each(function () {\r\n //For each columns container\r\n for (var x = 0; x < cols.length; x++) {\r\n //Declare items, a new array for heights and an index counter\r\n var items = $(this).find(cols[x]), its = new Array(), cr = 0;\r\n\r\n items.css('height', 'auto');\r\n\r\n //Check item count\r\n if (items.length > 1) {\r\n //Get all heights\r\n items.each(function () {\r\n var invisibleParents;\r\n\r\n if ($(this).is(':hidden')) {\r\n // Unhide all invisible parent nodes for a moment in order to calculate element's height\r\n invisibleParents = $(this).parents().filter(function () { return $(this).css(\"display\") == \"none\"; }).css('visibility', 'hidden').show();\r\n }\r\n\r\n its[cr++] = $(this).innerHeight();\r\n\r\n if (invisibleParents)\r\n invisibleParents.css('visibility', 'visible').hide();\r\n });\r\n\r\n //Set heights to max\r\n items.css('height', Math.max.apply(Math, its) + 'px');\r\n }\r\n }\r\n });\r\n }\r\n\r\n /* Local storage */\r\n window.saveToLocalStorage = function(key, value) {\r\n if (key && ('localStorage' in window) && window['localStorage'] !== null) {\r\n window.localStorage.setItem(key, value);\r\n }\r\n };\r\n window.getFromLocalStorage = function(key) {\r\n return ('localStorage' in window) && window['localStorage'] !== null ? window.localStorage.getItem(key) : null;\r\n };\r\n window.removeFromLocalStorage = function(key) {\r\n if (('localStorage' in window) && window['localStorage'] !== null) {\r\n window.localStorage.removeItem(key);\r\n }\r\n };\r\n window.getAllFromLocalStorage = function() {\r\n var keys = [];\r\n\r\n for (var i = 0, len = localStorage.length; i < len; ++i) {\r\n keys.push(localStorage.key(i));\r\n }\r\n\r\n return keys;\r\n };\r\n window.getAllByPrefixFromLocalStorage = function(prefix) {\r\n var prefixedKeys = [];\r\n\r\n if (!prefix) {return prefixedKeys};\r\n\r\n for (var i = 0, len = localStorage.length; i < len; ++i) {\r\n var key = localStorage.key(i);\r\n\r\n if (key && key.indexOf(prefix) === 0) {\r\n prefixedKeys.push(key);\r\n }\r\n }\r\n\r\n return prefixedKeys;\r\n };\r\n window.removeByPrefixFromLocalStorage = function(prefix) {\r\n var prefixedKeys = window.getAllByPrefixFromLocalStorage(prefix);\r\n prefixedKeys.forEach(function(key) {\r\n window.removeFromLocalStorage(key);\r\n });\r\n };\r\n\r\n /* Popups */\r\n window.popup = function (options) {\r\n var onClose = function () {\r\n var $this = $(this);\r\n\r\n if (options.canBeClosedByUser) {\r\n var $popup = $this.find('.js-popup');\r\n if (!$popup || !$popup.length) {\r\n $popup = $this[0].$message.find('.js-popup');\r\n }\r\n\r\n var popupId = $popup.data('popupid');\r\n\r\n var $dontShowCheckbox = $popup.find('.js-dont-show-popup');\r\n var dontShowExplicit = $dontShowCheckbox.length > 0 && $dontShowCheckbox.is(':checked');\r\n\r\n $.ajax({\r\n url: window.R + 'handlers/public/userdata.ashx',\r\n type: 'POST',\r\n data: {\r\n action: 'StorePopupDisplaySettings',\r\n popupId: popupId,\r\n dontShowExplicit: dontShowExplicit\r\n },\r\n dataType: 'json',\r\n })\r\n .done(function() {\r\n console.log('Popup \\'' +\r\n popupId +\r\n '\\' display registered' +\r\n (dontShowExplicit ? ' (don\\'t show any more based on user selection)' : ''));\r\n });\r\n }\r\n\r\n if (options.type === 'ModalBox') {\r\n $this.dialog('destroy').remove(); // https://stackoverflow.com/questions/4740500/jquery-dialog-dialog-fields-added-multiple-times-to-the-dom\r\n }\r\n };\r\n\r\n var fnOpenPopup;\r\n switch (options.type) {\r\n case 'ModalBox':\r\n fnOpenPopup = (function () {\r\n var dialogOptions = {\r\n title: options.title,\r\n resizable: false,\r\n draggable: false,\r\n modal: true,\r\n autoOpen: true,\r\n width: options.width || 700,\r\n close: onClose,\r\n // For jQueryUI >= 1.12\r\n classes: {\r\n 'ui-dialog': ['umw-popup-modal', options.classes].join(' '),\r\n 'ui-dialog-titlebar': 'umw-popup-modal-titlebar',\r\n 'ui-dialog-title': 'umw-popup-modal-title',\r\n 'ui-dialog-titlebar-close': 'umw-popup-modal-close',\r\n 'ui-dialog-content': 'umw-popup-modal-body'\r\n },\r\n // For jQueryUI < 1.12\r\n dialogClass: ['umw-popup-modal', options.classes].join(' ')\r\n };\r\n\r\n if (!options.canBeClosedByUser) {\r\n dialogOptions.closeOnEscape = false;\r\n dialogOptions.open = function(event, ui) {\r\n $('.ui-dialog-titlebar-close', ui.dialog | ui).hide();\r\n };\r\n }\r\n\r\n $(options.content).dialog(dialogOptions);\r\n reportPopupShown();\r\n });\r\n break;\r\n case 'Notification':\r\n fnOpenPopup = (function () {\r\n // https://ned.im/noty/v2/options.html\r\n var notyOptions = {\r\n layout: 'bottomRight',\r\n type: 'notification',\r\n force: true,\r\n closeWith: options.canBeClosedByUser ? ['button'] : [],\r\n text: options.content,\r\n template: '

',\r\n callback: {\r\n onShow: function () {\r\n if (options.title) {\r\n this.$bar.find('.noty_title').text(options.title);\r\n }\r\n\r\n this.$bar.addClass(['umw-popup-noty', options.classes].join(' '));\r\n },\r\n onClose: onClose\r\n }\r\n };\r\n\r\n window.noty(notyOptions);\r\n reportPopupShown();\r\n });\r\n break;\r\n default:\r\n return;\r\n }\r\n\r\n if (options.delay)\r\n window.setTimeout(fnOpenPopup, options.delay);\r\n else\r\n fnOpenPopup();\r\n\r\n function reportPopupShown() {\r\n window.PubSub.publish('popup.shown', { popupId: options.popupId });\r\n }\r\n };\r\n\r\n //#endregion Global functions\r\n\r\n var setupTooltips = function () {\r\n $('.Tooltip').tooltip();\r\n };\r\n\r\n var setupFancyboxes = function () {\r\n if (typeof $.fancybox === 'object' && $.fancybox !== null) {\r\n if (window.globalSettings.language === 3) {\r\n $.fancybox.defaults.i18n['no'] = {\r\n CLOSE: 'Lukk',\r\n NEXT: 'Neste',\r\n PREV: 'Siste',\r\n ERROR: 'Det forespurte innholdet kan ikke lastes.
Vennligst prøv igjen senere.',\r\n PLAY_START: 'Start bildefremvisning',\r\n PLAY_STOP: 'Pause bildefremvisning',\r\n FULL_SCREEN: 'Fullskjerm',\r\n THUMBS: 'Miniatyrbilder',\r\n DOWNLOAD: 'Last ned',\r\n SHARE: 'Del',\r\n ZOOM: 'Zoom'\r\n };\r\n\r\n $.fancybox.defaults.lang = 'no';\r\n }\r\n\r\n // Initialize fancybox for old controls\r\n $().fancybox({\r\n selector: \"a[rel^='lightbox'], a[rel^='fancybox']\",\r\n loop: true,\r\n buttons: [\r\n 'slideShow',\r\n 'close'\r\n ],\r\n caption: function() {\r\n var $elem = $(this);\r\n var caption = ($elem.data('caption') || $elem.attr('data-fancybox-description') || $elem.attr('fancyboxtext') || $elem.attr('title') || $elem.attr('alt') || '').trim();\r\n return caption;\r\n }\r\n });\r\n }\r\n };\r\n\r\n var setupDateTimeSelectors = function () {\r\n //Setup date selectors\r\n if ($.datepicker) {\r\n $('input.dateselector').datepicker({ onClose: function () { $(this).blur(); } });\r\n }\r\n\r\n //Setup date and time selectors\r\n if ($.fn.datetimepicker) {\r\n $('input.datetimeselector').datetimepicker({ onClose: function () { $(this).blur(); } });\r\n }\r\n };\r\n\r\n var setupSearchControls = function () {\r\n var onSearchKeyPress = function (e) {\r\n if (e.which === 13) {\r\n e.preventDefault();\r\n var term = $.trim($(this).val());\r\n if (term) {\r\n window.location = window.searchUrl + encodeURIComponent(term);\r\n }\r\n }\r\n };\r\n\r\n $('.smartsearch').autocomplete({\r\n minLength: 3,\r\n source: function (request, response) {\r\n var term = request.term;\r\n $.get(window.R + 'handlers/public/productdata.ashx', {\r\n action: 'search',\r\n term: term\r\n })\r\n .done(function (searchResults) {\r\n var items;\r\n if (searchResults && searchResults.length > 0) {\r\n items = _.map(searchResults, function (current) {\r\n return {\r\n 'label': current.Title + ' (' + current.ProductNo1 + ')',\r\n 'value': current.ProductUrl\r\n };\r\n });\r\n } else {\r\n var noItemsMsg = window.globalSettings.language === 3 ? 'Ingen elementer' : 'No items';\r\n items = [{ 'label': noItemsMsg, 'value': '#' }];\r\n }\r\n\r\n response(items);\r\n })\r\n .fail(ajaxFailHandler);\r\n },\r\n focus: function (evt) {\r\n evt.preventDefault();\r\n },\r\n select: function (evt, ui) {\r\n evt.preventDefault();\r\n\r\n if (ui.item.value !== '#') {\r\n window.location = ui.item.value;\r\n }\r\n }\r\n }).on('keypress', onSearchKeyPress);\r\n };\r\n\r\n var setupNumericLimiters = function () {\r\n if ($.fn.numeric) {\r\n $('input.integer').numeric(false);\r\n $('input.decimal').numeric({ decimal: ',' });\r\n }\r\n };\r\n\r\n var setupValidation = function () {\r\n $.validator.addMethod(\"pattern\", function (value, element, param) {\r\n if (!param.test) {\r\n param = new RegExp(param);\r\n }\r\n return this.optional(element) || param.test(value);\r\n }, \"Invalid format.\");\r\n\r\n var ignore = \":hidden\";\r\n\r\n var val = $(\"form\").validate({\r\n onsubmit: false,\r\n ignore: ignore\r\n });\r\n\r\n $('button[data-validates], input[type=\"submit\"][data-validates]').click(function (e) {\r\n if (!itemsValid($('#' + $(e.currentTarget).data('validates')).find(':input').not(ignore))) {\r\n e.preventDefault();\r\n }\r\n });\r\n\r\n $('button[data-validation-group], input[type=\"submit\"][data-validation-group]').click(function (e) {\r\n var group = $(e.currentTarget).data('validation-group');\r\n if (!itemsValid($(':input[data-validation-group=\"' + group + '\"]').not(ignore))) {\r\n e.preventDefault();\r\n }\r\n });\r\n\r\n function itemsValid(items) {\r\n val.resetForm();\r\n\r\n var isValid = true;\r\n\r\n items.each(function (i, item) {\r\n if (!$(item).valid())\r\n isValid = false;\r\n });\r\n\r\n return isValid;\r\n }\r\n };\r\n\r\n var setupNotifications = function () {\r\n var pubSub = window.PubSub;\r\n var showNotification = function (topic, contract) {\r\n var topicParts = topic.split('.');\r\n var notificationType = topicParts.length > 1 ? topicParts[topicParts.length - 1] : 'information';\r\n\r\n var defaultOptions = {\r\n layout: 'topCenter',\r\n type: notificationType,\r\n maxVisible: 15,\r\n force: true,\r\n timeout: 5000\r\n };\r\n\r\n var notyCallback = typeof (contract) === 'object' && contract && contract.notyCallback && typeof (contract.notyCallback) === 'function' ? contract.notyCallback : null;\r\n\r\n var notyOptions = typeof (contract) === 'object' && contract ? $.extend(true, defaultOptions, contract) : $.extend(defaultOptions, { text: contract });\r\n\r\n if (root.siteScripts) {\r\n notyOptions = root.siteScripts.converters.apply('NotyOptionsConverters', notyOptions);\r\n }\r\n\r\n var notyMsg = window.noty(notyOptions);\r\n\r\n if (notyCallback) {\r\n notyCallback(notyMsg);\r\n }\r\n }\r\n\r\n if (pubSub) {\r\n // Listen to the messages on global notifications channel\r\n pubSub.subscribe('notification', showNotification);\r\n\r\n if (window.notifyMessages) {\r\n _.each(window.notifyMessages, function (message) {\r\n pubSub.publish('notification', message);\r\n });\r\n }\r\n }\r\n };\r\n\r\n var setupOrderConditionWarningNotifications = function () {\r\n if (window.PublicEStore) {\r\n window.PublicEStore.subscribe('estore.callback.shopcart.addtocart', function (topic, contract) {\r\n try {\r\n if (typeof contract === 'object' && contract && contract.result) {\r\n for (var i = 0; i < contract.result.items.length; i++) {\r\n var item = contract.result.items[i];\r\n if (item.orderConditionWarnings && item.orderConditionWarnings.length) {\r\n window.PubSub.publish('notification.warning', item.orderConditionWarnings.join('
'));\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n console.error(err);\r\n }\r\n\r\n });\r\n }\r\n };\r\n\r\n var setupProductsColoring = function () {\r\n if (window.globalSettings.showShoppingHistory) {\r\n var fetchShoppingHistory = function () {\r\n var successCallback = function (shoppingHistoryDataContract) {\r\n var shoppingHistory = shoppingHistoryDataContract.result;\r\n\r\n $('.ProdItemContainer, .ProdItem, .SearchItemContainer').each(function () {\r\n var $currentProductContainer = $(this);\r\n var currentItemId = parseInt($currentProductContainer.data('itemid'));\r\n if (currentItemId > 0) {\r\n var isProductInCart = _.contains(shoppingHistory.inCart, currentItemId);\r\n $currentProductContainer.toggleClass('in-cart', isProductInCart);\r\n\r\n var isProductInShoppingList = _.contains(shoppingHistory.inShoppingLists, currentItemId);\r\n $currentProductContainer.toggleClass('in-shoppinglist', isProductInShoppingList);\r\n\r\n var isProductInOrders = _.contains(shoppingHistory.inOrders, currentItemId);\r\n $currentProductContainer.toggleClass('in-order', isProductInOrders);\r\n }\r\n });\r\n }\r\n\r\n var failCallback = function (errorContract) {\r\n console.error('Shopping history: Failed to fetch customer shopping history from server: %s', errorContract.message);\r\n };\r\n\r\n $.when(window.PublicEStore.getCustomerShoppingHistory()).then(successCallback, failCallback);\r\n };\r\n\r\n var shoppingHistoryChanged = function (topic) {\r\n var interestedActions = ['addtocart', 'removefromcart', 'emptycart', 'addtoshoppinglist', 'removefromshoppinglist', 'addtowishlist', 'removefromwishlist'];\r\n var topicParts = (topic || '').split('.');\r\n if (topicParts.length > 0) {\r\n var action = topicParts[topicParts.length - 1].toLowerCase();\r\n if (_.contains(interestedActions, action)) {\r\n // Re-fetch history\r\n fetchShoppingHistory();\r\n }\r\n } else {\r\n console.error('Shopping history: Failed to parse estore action channel');\r\n }\r\n };\r\n\r\n fetchShoppingHistory();\r\n // Listen to estore changes\r\n window.PublicEStore.subscribe('estore.callback', shoppingHistoryChanged);\r\n // Listen to force re-color\r\n window.PubSub.subscribe('frontend.productlist.refresh', fetchShoppingHistory);\r\n }\r\n };\r\n\r\n var processBuyFeedbackPopup = function () {\r\n if (window.globalSettings.showBuyFeedbackPopup) {\r\n // Check if the product was bought on the server-side (not through the MPEF)\r\n var buyFeedbackContext = window.buyFeedbackContext;\r\n if (!$.isEmptyObject(buyFeedbackContext) && buyFeedbackContext.tempOrderLineId && !$buyFeedbackCont) {\r\n window.PublicEStore.getBuyFeedbackData(buyFeedbackContext);\r\n }\r\n\r\n // Subscribe to addtocart events and show buy feedback popup\r\n window.PublicEStore.subscribe('estore.callback.shopcart.addtocart', function (topic, contract) {\r\n if (!$buyFeedbackCont) {\r\n var addedItems = [];\r\n if (contract && contract.result && contract.result.items && contract.result.items.length > 0) {\r\n addedItems = contract.result.items\r\n .filter(function(item) {\r\n return item.status.toLowerCase() === 'ok' && item.isUpdate === false;\r\n })\r\n .map(function(item) {\r\n return { tempOrderLineId: item.tempOrderLineID, itemId: item.itemID };\r\n });\r\n }\r\n\r\n if (addedItems.length > 0) {\r\n window.PublicEStore.getBuyFeedbackData(addedItems);\r\n }\r\n }\r\n });\r\n\r\n window.PublicEStore.subscribe('estore.callback.shopcart.getbuyfeedbackdata', function (topic, contract) {\r\n if (typeof contract === 'object' && contract && contract.result) {\r\n $.showBuyFeedbackPopup(contract.result.popupTemplate, contract.result.popupData);\r\n }\r\n });\r\n }\r\n };\r\n\r\n var isFreeShippingPopupCanBeShown = function() {\r\n var lastPopupTime = window.getFromLocalStorage(\"LastFreeShipingPopupTime\");\r\n var now = new Date().getTime();\r\n\r\n if (!lastPopupTime || ((now - lastPopupTime) / 1000) > 30) { // check in seconds\r\n window.saveToLocalStorage(\"LastFreeShipingPopupTime\", now);\r\n return true;\r\n }\r\n\r\n return false;\r\n };\r\n\r\n var processFreeShipingOfferPopup = function() {\r\n // Subscribe to addtocart events and show free shipping offer popup\r\n if (window.globalSettings.showFreeShipingOfferPopup) {\r\n window.PublicEStore.subscribe('estore.callback.shopcart.addtocart',\r\n function(topic, contract) {\r\n var $freeShipingOfferPopupTemplate = $('.js-FreeShipingPopupContainer').html();\r\n if (!$freeShipingOfferPopupTemplate) {\r\n $freeShipingOfferPopupTemplate = '
{%= description %}
';\r\n }\r\n $.ajax({\r\n url: window.R + 'handlers/public/estoredata.ashx',\r\n type: 'GET',\r\n data: {\r\n action: 'GetFreeShippingPopupDetails',\r\n amount: contract.result.totalPrice\r\n },\r\n dataType: 'json'\r\n })\r\n .done(function(details) {\r\n if (details.showPopup && isFreeShippingPopupCanBeShown()) {\r\n details.freeShipingDelta = Math.round(details.freeShipingDelta * 100) / 100;\r\n var templateSettings = {\r\n interpolate: /\\{%=(.+?)%\\}/g,\r\n escape: /\\{%-(.+?)%\\}/g,\r\n evaluate: /\\{%(.+?)%\\}/g\r\n };\r\n var popupHtml =\r\n _.template($freeShipingOfferPopupTemplate, details, templateSettings);\r\n var popupDialog = $(popupHtml).dialog({\r\n modal: true,\r\n resizable: false,\r\n title: details.title,\r\n width: 500,\r\n dialogClass: 'free-shipping-popup',\r\n appendTo: 'form',\r\n close: function() {\r\n popupDialog.dialog('destroy').remove();\r\n }\r\n });\r\n }\r\n })\r\n .fail(ajaxFailHandler);\r\n });\r\n }\r\n };\r\n\r\n var processFreeShippingMessage = function () {\r\n var $progressCont = $('.js-free-shipping-progress-bar');\r\n var $progressLine = $('.js-free-shipping-progress-bar-line');\r\n var $messageCont = $('.js-free-shipping-message');\r\n\r\n var settings = window.globalSettings.freeShippingMessageSettings;\r\n\r\n if (settings && ($progressCont.length || $progressLine.length || $messageCont.length)) {\r\n window.PublicEStore.subscribe('estore.callback.shopcart', function(topic, contract) { updateValues(contract.result ? contract.result.totalPrice : 0); });\r\n updateValues(0);\r\n }\r\n\r\n function updateValues(amount) {\r\n $.ajax({\r\n url: window.R + 'handlers/public/estoredata.ashx',\r\n type: 'GET',\r\n data: {\r\n action: 'GetFreeShippingStatus',\r\n amount: amount\r\n },\r\n dataType: 'json'\r\n })\r\n .done(function (result) {\r\n try {\r\n if (result && result.showNotification) {\r\n if ($messageCont.length) {\r\n var freeShippingMessage;\r\n if (result.freeShippingRemainder > 0) {\r\n freeShippingMessage =\r\n settings.freeShippingMessage.replace('{0}', result.freeShippingRemainderStr);\r\n } else {\r\n freeShippingMessage = settings.freeShippingReacedMessage;\r\n }\r\n $messageCont.html(freeShippingMessage);\r\n $messageCont.show();\r\n }\r\n $progressLine.attr('aria-valuenow', result.progress * 100);\r\n $progressLine.css('width', result.progress * 100 + '%');\r\n $progressCont.show();\r\n } else {\r\n $progressCont.hide();\r\n $messageCont.hide();\r\n }\r\n } catch (e) {\r\n $progressCont.hide();\r\n $messageCont.hide();\r\n }\r\n })\r\n .fail(function (errorResp) {\r\n $progressCont.hide();\r\n $messageCont.hide();\r\n });\r\n }\r\n };\r\n\r\n var processUserDetailsConfirmationPopup = function () {\r\n if (window.globalSettings.showConfirmUserDetailsPopup) {\r\n var $popupDialog = $();\r\n var saveContactDetails = function () {\r\n if ($popupDialog.length) {\r\n var validator = $popupDialog.validate();\r\n\r\n validator.resetForm();\r\n var isFormValid = validator.form();\r\n if (isFormValid) {\r\n $popupDialog.block({ message: null });\r\n $.ajax({\r\n url: window.R + 'handlers/public/userdata.ashx',\r\n type: 'POST',\r\n data: {\r\n action: 'UpdateUserContactDetails',\r\n mobile: $popupDialog.find('#userDetailsConfirmationPopup_MobilePhone').val(),\r\n phone: $popupDialog.find('#userDetailsConfirmationPopup_HomePhone').val(),\r\n email: $popupDialog.find('#userDetailsConfirmationPopup_Email').val(),\r\n address: $popupDialog.find('#userDetailsConfirmationPopup_Address').val(),\r\n postalCode: ($popupDialog.find('#userDetailsConfirmationPopup_PostalCode').val() || '').trim(),\r\n postalArea: $popupDialog.find('#userDetailsConfirmationPopup_PostalArea').val()\r\n },\r\n dataType: 'json',\r\n })\r\n .done(function (response) {\r\n if (response.reload) {\r\n window.location.reload(true);\r\n } else {\r\n window.PubSub.publish('notification.success', response.message);\r\n $popupDialog.dialog('close');\r\n }\r\n })\r\n .fail(ajaxFailHandler)\r\n .always(function () { $popupDialog.unblock(); });\r\n }\r\n }\r\n };\r\n\r\n var popupTemplateOverride = $('.UserDetailsConfirmationPopupContent').html();\r\n $.ajax({\r\n url: window.R + 'handlers/public/userdata.ashx',\r\n type: 'GET',\r\n data: {\r\n action: 'GetConfirmationPopupDetails',\r\n includeTemplate: !popupTemplateOverride\r\n },\r\n dataType: 'json',\r\n })\r\n .done(function (details) {\r\n var labels = details.labels;\r\n var popupTemplate = popupTemplateOverride || details.template;\r\n var popupHtml = _.template(popupTemplate, details);\r\n $popupDialog = $(popupHtml).dialog({\r\n modal: true,\r\n resizable: false,\r\n title: labels.title,\r\n width: 500,\r\n dialogClass: 'UserDetailsConfirmationPopup',\r\n appendTo: 'form',\r\n buttons: [\r\n {\r\n text: labels.confirmAndClose,\r\n icons: {\r\n primary: 'ui-icon-check'\r\n },\r\n click: function () {\r\n saveContactDetails();\r\n }\r\n }\r\n ]\r\n });\r\n })\r\n .fail(ajaxFailHandler);\r\n }\r\n };\r\n\r\n var attachLocalStorageSavingForForms = function() {\r\n var inputs = $('input[data-store],textarea[data-store]');\r\n $.each(inputs, function() {\r\n var t = $(this);\r\n var store = t.attr('data-store');\r\n if (store) {\r\n var key = store + '-' + t.attr('id');\r\n var currentValue = t.val();\r\n if (!currentValue || currentValue.length === 0) {\r\n var lsValue = window.getFromLocalStorage(key);\r\n if (lsValue) {\r\n t.val(lsValue);\r\n }\r\n }\r\n\r\n t.keyup(function () {\r\n var val = t.val();\r\n if (val && val.length > 0) {\r\n window.saveToLocalStorage(key, t.val());\r\n } else {\r\n window.removeFromLocalStorage(key);\r\n }\r\n });\r\n }\r\n });\r\n };\r\n\r\n var setupPersonalDataDownload = function() {\r\n var $personalDataCont = $('.js-personal-data-cont');\r\n if (!$personalDataCont.length) {\r\n return;\r\n }\r\n\r\n var downloadClicked = false;\r\n\r\n var $frame = $personalDataCont.find('#downloadPersonalDataFrame');\r\n $frame.load(function() {\r\n //note: load event is invoked when an error is returned from server\r\n //some browsers raise frame.load event on page load - need to check if download link was clicked\r\n if (!downloadClicked) {\r\n return;\r\n }\r\n\r\n // ReSharper disable once UseOfImplicitGlobalInFunctionScope\r\n var errTxt = TopFormText.downloadPersonalDataError;\r\n var frameContent = $frame[0].contentWindow || $frame[0].contentDocument;\r\n var frameDoc = frameContent.document || frameContent;\r\n\r\n if (frameDoc &&\r\n frameDoc.body !== null &&\r\n frameDoc.body.innerText !== null &&\r\n frameDoc.body.innerText.length) {\r\n try {\r\n var contentObj = JSON.parse(frameDoc.body.innerText);\r\n if (contentObj && contentObj.Message) {\r\n errTxt = contentObj.Message;\r\n }\r\n } catch (e) {\r\n console.error(e);\r\n }\r\n }\r\n\r\n window.PubSub.publish('notification.error', errTxt);\r\n });\r\n\r\n $('.js-lnk-personal-data').click(function(e) {\r\n e.preventDefault();\r\n downloadClicked = true;\r\n var format = $(this).data('format');\r\n\r\n if (format) {\r\n var form = document.createElement('form');\r\n form.action = window.R + 'handlers/public/userdata.ashx';\r\n form.method = 'GET';\r\n form.target = 'downloadPersonalDataFrame';\r\n\r\n var input = document.createElement('textarea');\r\n input.name = 'action';\r\n input.value = 'DownloadPersonalData';\r\n form.appendChild(input);\r\n\r\n input = document.createElement('textarea');\r\n input.name = 'format';\r\n input.value = format;\r\n form.appendChild(input);\r\n\r\n form.style.display = 'none';\r\n document.body.appendChild(form);\r\n form.submit();\r\n\r\n $(form).remove();\r\n } else {\r\n // ReSharper disable once UseOfImplicitGlobalInFunctionScope\r\n window.PubSub.publish('notification.error', TopFormText.formatNotSpecified);\r\n }\r\n });\r\n };\r\n\r\n $(function () {\r\n window.SetEqualHeights();\r\n\r\n setupFancyboxes();\r\n\r\n setupTooltips();\r\n\r\n setupDateTimeSelectors();\r\n\r\n setupSearchControls();\r\n\r\n setupNumericLimiters();\r\n\r\n setupValidation();\r\n\r\n setupNotifications();\r\n\r\n setupOrderConditionWarningNotifications();\r\n\r\n setupProductsColoring();\r\n\r\n processBuyFeedbackPopup();\r\n\r\n processUserDetailsConfirmationPopup();\r\n\r\n attachLocalStorageSavingForForms();\r\n\r\n processFreeShipingOfferPopup();\r\n\r\n processFreeShippingMessage();\r\n\r\n setupPersonalDataDownload();\r\n\r\n // Fix IE: teaser-picture in popup appears behind the Youtube-video.\r\n $('iframe').each(function () {\r\n var url = $(this).attr(\"src\");\r\n var m = '?';\r\n var c = 0;\r\n var adds;\r\n if (url && url.length) {\r\n for (var i = 0; i < url.length; i++) {\r\n if (m == url.substr(i, m.length)) c++;\r\n }\r\n\r\n if (c > 0) {\r\n adds = '&';\r\n } else {\r\n adds = '?';\r\n }\r\n\r\n if (url.indexOf(\"youtube\") >= 0) {\r\n $(this).attr(\"src\", url + adds + \"wmode=transparent\");\r\n }\r\n }\r\n });\r\n\r\n //Fix double main title problem on list pages\r\n var articles = $('#UC137_tMain, #UC152_tMain, #UC171_documentViewMainContainer');\r\n if (articles.length) {\r\n var nextElement = articles.next('div');\r\n if (nextElement.hasClass('UC162') || nextElement.hasClass('UC167')) {\r\n nextElement.find('.MainTitle').hide();\r\n }\r\n }\r\n\r\n // Workaround for console in IE\r\n if (!window.console) {\r\n window.console = {\r\n log: function () { },\r\n info: function () { },\r\n warn: function () { },\r\n error: function () { }\r\n };\r\n }\r\n });\r\n})(jQuery, _);\r\n\r\n/* jQuery numeric */\r\n(function(d){d.fn.numeric=function(a,c){\"boolean\"===typeof a&&(a={decimal:a});a=a||{};\"undefined\"==typeof a.negative&&(a.negative=!0);var g=!1===a.decimal?\"\":a.decimal||\".\",b=!0===a.negative?!0:!1;return this.data(\"numeric.decimal\",g).data(\"numeric.negative\",b).data(\"numeric.callback\",\"function\"==typeof c?c:function(){}).keypress(d.fn.numeric.keypress).keyup(d.fn.numeric.keyup).blur(d.fn.numeric.blur)};d.fn.numeric.keypress=function(a){var c=d.data(this,\"numeric.decimal\"),g=d.data(this,\"numeric.negative\"),\r\nb=a.charCode?a.charCode:a.keyCode?a.keyCode:0;if(13==b&&\"input\"==this.nodeName.toLowerCase())return!0;if(13==b)return!1;var f=!1;if(a.ctrlKey&&97==b||a.ctrlKey&&65==b||a.ctrlKey&&120==b||a.ctrlKey&&88==b||a.ctrlKey&&99==b||a.ctrlKey&&67==b||a.ctrlKey&&122==b||a.ctrlKey&&90==b||a.ctrlKey&&118==b||a.ctrlKey&&86==b||a.shiftKey&&45==b)return!0;if(48>b||57b;e--)i=a.charAt(e),i==g&&(a=a.substring(0,e)+a.substring(e+1));this.value=a;d.fn.setSelection(this,c)}};d.fn.numeric.blur=function(){var a=\r\nd.data(this,\"numeric.decimal\"),c=d.data(this,\"numeric.callback\"),g=this.value;\"\"!=g&&(RegExp(\"^\\\\d+$|\\\\d*\"+a+\"\\\\d+\").exec(g)||c.apply(this))};d.fn.removeNumeric=function(){return this.data(\"numeric.decimal\",null).data(\"numeric.negative\",null).data(\"numeric.callback\",null).unbind(\"keypress\",d.fn.numeric.keypress).unbind(\"blur\",d.fn.numeric.blur)};d.fn.getSelectionStart=function(a){if(a.createTextRange){var c=document.selection.createRange().duplicate();c.moveEnd(\"character\",a.value.length);return\"\"==\r\nc.text?a.value.length:a.value.lastIndexOf(c.text)}return a.selectionStart};d.fn.setSelection=function(a,c){\"number\"==typeof c&&(c=[c,c]);if(c&&c.constructor==Array&&2==c.length)if(a.createTextRange){var d=a.createTextRange();d.collapse(!0);d.moveStart(\"character\",c[0]);d.moveEnd(\"character\",c[1]);d.select()}else a.setSelectionRange&&(a.focus(),a.setSelectionRange(c[0],c[1]))}})(jQuery);\r\n\r\n/* Add to shopping list popup */\r\n(function($, _, root) {\r\n 'use strict';\r\n var $addToCollectionDialog = null;\r\n var template = '
\">
\" class=\"btn btn-link\"><%- labels.myShoppingLists %>
\"/>
';\r\n var systemUrls, labels;\r\n var isContextLoaded = false;\r\n var isAnonymous;\r\n\r\n root.showAddToCollectionPopup = function (products) {\r\n if (typeof (products) === 'undefined') {\r\n root.PubSub.publish('notification.warning', labels.noProductsFound);\r\n } else {\r\n if (!isContextLoaded) {\r\n $.when(getContext())\r\n .done(function(ctx) {\r\n systemUrls = ctx.urls;\r\n labels = ctx.labels;\r\n isContextLoaded = true;\r\n isAnonymous = ctx.isAnonymous;\r\n\r\n var $shoppingListSelector;\r\n var $newShoppingListInput;\r\n\r\n if (isAnonymous === true) {\r\n showLoginRequiredWarning();\r\n } else {\r\n var dialogHtml = _.template(template, ctx);\r\n $addToCollectionDialog = $(dialogHtml).dialog({\r\n resizable: false,\r\n modal: true,\r\n autoOpen: false,\r\n width: 400,\r\n buttons: [\r\n {\r\n 'class': 'btn btn-default',\r\n text: labels.close,\r\n click: function() {\r\n $(this).dialog('close');\r\n }\r\n }\r\n ]\r\n });\r\n\r\n $shoppingListSelector = $addToCollectionDialog.find('.js-existing-shoppinglist-selector');\r\n $shoppingListSelector.keyup(function(e) {\r\n if (e.keyCode == 13) {\r\n _handleAddProductToExistingShoppingList();\r\n }\r\n });\r\n $newShoppingListInput = $addToCollectionDialog.find('.js-new-shoppinglist-name');\r\n $newShoppingListInput.keyup(function(e) {\r\n if (e.keyCode == 13) {\r\n _handleAddProductToNewShoppingList();\r\n }\r\n });\r\n\r\n var $addButton = $addToCollectionDialog.find(\"[data-action='addtoexistingshoppinglist']\");\r\n if (ctx.shoppingLists.length <= 0) {\r\n $addButton.prop('disabled', true);\r\n $addButton.prop('title', labels.emptyShoppingLists);\r\n }\r\n\r\n $addToCollectionDialog.find('.js-action-button').click(function(evt) {\r\n evt.preventDefault();\r\n\r\n var $clickTarget = $(evt.target);\r\n var action = $clickTarget.data('action');\r\n\r\n switch (action) {\r\n case 'addtoexistingshoppinglist':\r\n _handleAddProductToExistingShoppingList();\r\n break;\r\n case 'addtonewshoppinglist':\r\n _handleAddProductToNewShoppingList();\r\n break;\r\n }\r\n });\r\n\r\n $addToCollectionDialog.data('products', products);\r\n $addToCollectionDialog.dialog('open');\r\n }\r\n\r\n function _handleAddProductToExistingShoppingList() {\r\n var productsToAdd = $addToCollectionDialog.data('products');\r\n var selectedShoppingListId = $shoppingListSelector.val();\r\n\r\n blockUI();\r\n $.when(root.PublicEStore.addToShoppingList(selectedShoppingListId, productsToAdd))\r\n .always(unblockUI)\r\n .done(function() {\r\n root.PubSub.publish('notification.success', labels.productAddedToShoppingList);\r\n $addToCollectionDialog.dialog('close');\r\n })\r\n .fail(errorHandler);\r\n }\r\n\r\n function _handleAddProductToNewShoppingList() {\r\n var productsToAdd = $addToCollectionDialog.data('products');\r\n\r\n var newShoppingListName = $newShoppingListInput.val();\r\n if (newShoppingListName) {\r\n blockUI();\r\n $.when(root.PublicEStore.addShoppingList(newShoppingListName, '', productsToAdd))\r\n .always(unblockUI)\r\n .done(function(dataContract) {\r\n var newShoppingList = dataContract.result;\r\n // Add to selector and select\r\n var $newShoppingListOption = $('