PageSourceSearch

https://puppycake.com/store/controls/variants/variants.js?639207666553564302

js puppycake.com collected 2026-09-26 07:36:31 UTC 93,611 bytes, 2,346 lines download raw bytes

1if (!window.variantController) {
2
3  window.variantController =
4  {
5    registry: [],
6    customIdLookup: {},
7    addToCartLinkLookup: {},
8    addToCartButtonLookup: {},
9    wishlistButtonLookup: {},
10    addToQuoteButtonLookup: {},
11    addToCartButtonIds: [],
12    massAddToCartButtonIds: [],
13    addToCartLinkIds: [],
14    employeeDDIdsLookup: [],
15    registerVariants: function (itemId, customId, priceId, priceDollarsId, priceCentsId, itemNrId, qtyDiscountsId, qtyDiscountPricesId,
16      productStatusId, productTimeFrameId, variantGTINId, qtyTextboxId, useVariantInventory, qtyDiscountsAcrossVariants,
17      addToCartButtonId, addToCartLinkId, selectedVariantsId, pkgVariantsId, childPriceId, bindQtyToParent,
18      bindQtyCheckboxId, personalizationIdsId, personalizationStringsId, checkThisOnlyOnButtonClick, rewardPointsId,
19      rewardPointsToPurchaseId, qtyInStockId, priceAreaId, salePriceId, salePriceAreaId, wasPriceId, wasPriceAreaId,
20      wishlistButtonId, massAddToCartButtonId, useQtyOf1IfNoQty, retailPriceId, retailPriceAreaId, youSaveId, groupAddToCartButtonId,
21      weightId, lengthId, widthId, heightId, availabilityId, subscriptionId, isDDLSwatchCombined, jsaonDDLMetaData, isFitmentEnabled, imageId, lazyLoad, productPhotoHandling, externalImageOverrideUrl, zoomOverrideUrl, employeeDDId, customFieldId, addToQuoteButtonId, variantAdditionalInfoId) {
22      this.registry.push(new VariantAjaxManager(itemId, customId, priceId, priceDollarsId, priceCentsId, itemNrId, qtyDiscountsId, qtyDiscountPricesId, productStatusId, productTimeFrameId, variantGTINId, qtyTextboxId, useVariantInventory, qtyDiscountsAcrossVariants, addToCartButtonId, addToCartLinkId, selectedVariantsId, pkgVariantsId, childPriceId, bindQtyToParent, bindQtyCheckboxId, personalizationIdsId, personalizationStringsId, rewardPointsId, rewardPointsToPurchaseId, qtyInStockId, priceAreaId, salePriceId, salePriceAreaId, wasPriceId, wasPriceAreaId, useQtyOf1IfNoQty, retailPriceId, retailPriceAreaId, youSaveId, weightId, lengthId, widthId, heightId, availabilityId, subscriptionId, isDDLSwatchCombined, jsaonDDLMetaData, isFitmentEnabled, imageId, lazyLoad, productPhotoHandling, externalImageOverrideUrl, zoomOverrideUrl, employeeDDId, customFieldId, addToQuoteButtonId, variantAdditionalInfoId));
23
24      this.customIdLookup[customId] = this.registry[this.registry.length - 1];
25      this.bindAddToCartButton(addToCartButtonId, checkThisOnlyOnButtonClick);
26      this.bindAddToCartLink(addToCartLinkId);
27      this.bindWishListButton(wishlistButtonId);
28      this.bindAddToQuoteButton(addToQuoteButtonId);
29      this.bindMassAddToCartButton(massAddToCartButtonId);
30      this.bindAddToCartButton(groupAddToCartButtonId, checkThisOnlyOnButtonClick);
31      this.bindEmployeeDD(employeeDDId, customFieldId);
32
33      if (addToCartLinkId != null && addToCartLinkId.length > 0)
34        this.addToCartLinkLookup[addToCartLinkId] = this.registry[this.registry.length - 1];
35
36      if (checkThisOnlyOnButtonClick && addToCartButtonId != null && addToCartButtonId.length > 0)
37        this.addToCartButtonLookup[addToCartButtonId] = this.registry[this.registry.length - 1];
38
39      if (wishlistButtonId != null && wishlistButtonId.length > 0)
40        this.wishlistButtonLookup[wishlistButtonId] = this.registry[this.registry.length - 1];
41
42      if (addToQuoteButtonId != null && addToQuoteButtonId.length > 0)
43        this.addToQuoteButtonLookup[addToQuoteButtonId] = this.registry[this.registry.length - 1];
44
45      if (checkThisOnlyOnButtonClick && groupAddToCartButtonId != null && groupAddToCartButtonId.length > 0)
46        this.addToCartButtonLookup[groupAddToCartButtonId] = this.registry[this.registry.length - 1];
47
48      if (employeeDDId != null && employeeDDId.length > 0)
49        this.employeeDDIdsLookup[employeeDDId] = this.registry[this.registry.length - 1];
50    },
51    bindAddToCartButton: function (addToCartButtonId, checkThisOnlyOnButtonClick) {
52
53      if (addToCartButtonId != null && addToCartButtonId.length > 0) {
54
55        if ($.inArray(addToCartButtonId, this.addToCartButtonIds) != -1)
56          return;
57
58        this.addToCartButtonIds.push(addToCartButtonId);
59
60        $("#" + addToCartButtonId).click(function (event) {
61
62          var lastResult;
63
64          if (checkThisOnlyOnButtonClick) {
65
66            var controller = window.variantController.addToCartButtonLookup[addToCartButtonId];
67            //need to have some sort of way to look up the class based on id here?
68            lastResult = controller.checkSelections(false, true, addToCartButtonId);
69
70            if (!lastResult.success) {
71              alert(lastResult.message);
72              event.preventDefault();
73              return false;
74            }
75
76            controller.saveSelections(controller.getSelections(true).join("|"));
77            controller.savePersonalizations(controller.getPersonalizations().join("|"));
78
79            return true;
80
81          }
82          else {
83
84            for (var i = 0; i < window.variantController.registry.length; i++) {
85
86              lastResult = window.variantController.registry[i].checkSelections(true, false, addToCartButtonId);
87
88              if (!lastResult.success) {
89                alert(lastResult.message);
90                event.preventDefault();
91                return false;
92              }
93
94              window.variantController.registry[i].saveSelections(window.variantController.registry[i].getSelections(true).join("|"));
95              window.variantController.registry[i].savePersonalizations(window.variantController.registry[i].getPersonalizations().join("|"));
96            }
97          }
98
99          return true;
100        });
101      }
102    },
103    bindMassAddToCartButton: function (massAddToCartButtonId) {
104      if (massAddToCartButtonId != null && massAddToCartButtonId.length > 0) {
105
106        if ($.inArray(massAddToCartButtonId, this.massAddToCartButtonIds) != -1)
107          return;
108
109        this.massAddToCartButtonIds.push(massAddToCartButtonId);
110
111        $("#" + massAddToCartButtonId).click(function (event) {
112
113          var lastResult;
114
115          for (var i = 0; i < window.variantController.registry.length; i++) {
116
117            lastResult = window.variantController.registry[i].checkSelections(true, false, massAddToCartButtonId);
118
119            if (!lastResult.success) {
120              alert(lastResult.message);
121              event.preventDefault();
122              return false;
123            }
124
125            window.variantController.registry[i].saveSelections(window.variantController.registry[i].getSelections(true).join("|"));
126            window.variantController.registry[i].savePersonalizations(window.variantController.registry[i].getPersonalizations().join("|"));
127          }
128
129          return true;
130        });
131      }
132    },
133    bindWishListButton: function (wishlistButtonId) {
134
135      if (wishlistButtonId != null && wishlistButtonId.length > 0) {
136
137        $("#" + wishlistButtonId).click(function (event) {
138          // Try and enable this button's wishlist popover
139          $(this).popover('enable');
140          var controller = window.variantController.wishlistButtonLookup[wishlistButtonId];
141          var lastResult = controller.checkSelections(false, true, wishlistButtonId);
142
143          if (!lastResult.success) {
144            alert(lastResult.message);
145            event.preventDefault();
146            // Disable wishlist popover
147            $(this).popover('disable');
148            return false;
149          }
150
151          controller.saveSelections(controller.getSelections(true).join("|"));
152          controller.savePersonalizations(controller.getPersonalizations().join("|"));
153
154          return true;
155        });
156      }
157    },
158    bindAddToQuoteButton: function (addToQuoteButtonId) {
159
160      if (addToQuoteButtonId != null && addToQuoteButtonId.length > 0) {
161
162        $("#" + addToQuoteButtonId).click(function (event) {
163          // Try and enable this button's popover
164          $(this).popover('enable');
165          var controller = window.variantController.addToQuoteButtonLookup[addToQuoteButtonId];
166          var lastResult = controller.checkSelections(false, true, addToQuoteButtonId);
167
168          if (!lastResult.success) {
169            alert(lastResult.message);
170            event.preventDefault();
171            // Disable popover
172            $(this).popover('disable');
173            return false;
174          }
175
176          controller.saveSelections(controller.getSelections(true).join("|"));
177          controller.savePersonalizations(controller.getPersonalizations().join("|"));
178
179          return true;
180        });
181      }
182    },
183    bindAddToCartLink: function (addToCartLinkId) {
184      if (addToCartLinkId != null && addToCartLinkId.length > 0) {
185
186        if ($.inArray(addToCartLinkId, this.addToCartLinkIds) != -1)
187          return;
188
189        this.addToCartLinkIds.push(addToCartLinkId);
190
191        $("#" + addToCartLinkId).click(function (event) {
192
193          var lastResult;
194          var controller = window.variantController.addToCartLinkLookup[addToCartLinkId];
195
196          //need to have some sort of way to look up the class based on id here?
197          lastResult = controller.checkSelections(false, true, addToCartLinkId);
198
199          if (!lastResult.success) {
200            alert(lastResult.message);
201            event.preventDefault();
202            return false;
203          }
204
205          if (!controller.uploadPersonalizationFiles()) {
206            event.preventDefault();
207            return false;
208          }
209
210          controller.setSelectionsOnLink($(this), controller.getSelections(false).join("|"));
211          controller.setPersonalizationsOnLink($(this), controller.getPersonalizations(false).join("|"));
212          return true;
213        });
214      }
215    },
216    bindEmployeeDD: function (employeeDDId, customFieldId) {
217      if (employeeDDId != null && employeeDDId.length > 0) {
218        $("#" + employeeDDId).change(function (event) {
219          var dropdownValue = $(this).val();
220          var employeeName = $(this).find('option[value=' + dropdownValue + ']').text();
221          var dv = document.getElementById(customFieldId);
222          if (dv) {
223            var customFields;           
224            var controller = window.variantController.employeeDDIdsLookup[employeeDDId];
225            $.ajax({
226              type: "POST",
227              contentType: "application/json; charset=utf-8",
228              url: "/Store/Controls/ScriptService.asmx/GetCustomFields",
229              dataType: "json",
230              data: JSON.stringify({ 'employeeID': dropdownValue }),
231            }).done(function (response) {
232              if (response) {               
233                dv.innerHTML = "";
234                customFields = response.d;
235                if (customFields.length > 0) {
236                  customFields.forEach(function (field) {
237                    label = document.createElement("span");
238                    label.textContent = field.label + ": ";
239                    label.className = "custom-field-label";
240                    dv.appendChild(label);
241
242                    value = document.createElement("span");
243                    value.textContent = field.value;
244                    value.setAttribute("target", field.name);
245                    value.className = "custom-field-value";
246                    dv.appendChild(value);
247
248                    br = document.createElement("br");
249                    dv.appendChild(br);
250                  });
251
252                  if (controller._useVariantInventory) {
253                    controller.$varInvDDs.each(function (i, item) {
254                      if ($(item).is("select") || (controller._isDDLSwatchCombined && $(item).is("div.variants-combo-main-container"))) {
255                        customFields.forEach(function (field) {
256                          if (item.getAttribute("groupname") == field.name) {
257                            let errorDv = $('.variant-custom-error[groupname=' + controller._customId + '_' + field.name + ']').html(''); 
258                            errorDv[0].setAttribute('data-auto-select', 'true')
259                            errorDv[0].setAttribute('data-error', '');
260                            if (field.value) {
261                              if (controller._isDDLSwatchCombined) {
262                                let varOption = $('#' + item.id).find('.variants-combo-option[varname=' + field.value + ']');
263                                if (varOption && varOption.length > 0 && varOption[0].style.display != 'none') {
264                                  varOption.click();
265                                }
266                                else {                             
267                                  errorDv.html('Profile option unavailable.');
268                                  errorDv[0].setAttribute('data-error', 'option-unavailable');
269                                }
270                              }
271                              else {
272                                let varOption = $('#' + item.id + ' option[varname=' + field.value + ']');
273                                if (varOption && varOption.length > 0)
274                                  $(item).val(varOption.val()).change();
275                                else {
276                                  errorDv.html('Profile option unavailable.');
277                                  errorDv[0].setAttribute('data-error', 'option-unavailable');
278                                }
279                              }
280                            }
281                            else {
282                              errorDv.html(employeeName + ' has not selected a profile option for ' + field.label);
283                              errorDv[0].setAttribute('data-error', 'no-profile-value');
284                            }
285                          }
286                        })
287                      }
288                    })
289                  }
290                }
291              }
292            });
293          }
294          return true;
295        });
296      }
297    }
298  };
299}
300
301
302var VariantAjaxManager = function (itemId, customId, priceId, priceDollarsId, priceCentsId, itemNrId, qtyDiscountsId, qtyDiscountPricesId,
303  productStatusId, productTimeFrameId, variantGTINId, qtyTextboxId, useVariantInventory,
304  qtyDiscountsAcrossVariants, addToCartButtonId, addToCartLinkId, selectedVariantsId, pkgVariants,
305  childPriceId, bindQtyToParent, bindQtyCheckboxId, personalizationIdsId, personalizationStringsId,
306  rewardPointsId, rewardPointsToPurchaseId, qtyInStockId, priceAreaId, salePriceId, salePriceAreaId, wasPriceId, wasPriceAreaId,
307  useQtyOf1IfNoQty, retailPriceId, retailPriceAreaId, youSaveId, weightId, widthId, lengthId, heightId, availabilityId, subscriptionId, isDDLSwatchCombined,
308  jsaonDDLMetaData, isFitmentEnabled, imageId, lazyLoad, productPhotoHandling, externalImageOverrideUrl, zoomOverrideUrl, employeeDDId, customFieldId, addToQuoteButtonId, variantAdditionalInfoId) {
309  this._itemId = itemId;
310  this._imageId = imageId;
311  this._priceId = priceId;
312  this._priceDollarsId = priceDollarsId;
313  this._priceCentsId = priceCentsId;
314  this._itemNrId = itemNrId;
315  this._qtyDiscountsId = qtyDiscountsId;
316  this._qtyDiscountPricesId = qtyDiscountPricesId;
317  this._productStatusId = productStatusId;
318  this._productTimeFrameId = productTimeFrameId;
319  this._variantGTINId = variantGTINId;
320  this._customId = customId;
321  this._qtyTextboxId = qtyTextboxId;
322  this._useVariantInventory = useVariantInventory;
323  this._qtyDiscountsAcrossVariants = qtyDiscountsAcrossVariants;
324  this._addToCartButtonId = addToCartButtonId;
325  this._addToCartLinkId = addToCartLinkId;
326  this._selectedVariantsId = selectedVariantsId;
327  this._pkgVariants = pkgVariants;
328  this._childPriceId = childPriceId;
329  this._bindQtyToParent = bindQtyToParent;
330  this._bindQtyCheckBoxId = bindQtyCheckboxId;
331  this._personalizationIdsId = personalizationIdsId;
332  this._personalizationStringsId = personalizationStringsId;
333  this._rewardPointsId = rewardPointsId;
334  this._rewardPointsToPurchaseId = rewardPointsToPurchaseId;
335  this._qtyInStockId = qtyInStockId;
336  this._priceAreaId = priceAreaId;
337  this._salePriceId = salePriceId;
338  this._salePriceAreaId = salePriceAreaId;
339  this._wasPriceId = wasPriceId;
340  this._wasPriceAreaId = wasPriceAreaId;
341  this._useQtyOf1IfNoQty = useQtyOf1IfNoQty;
342  this._retailPriceId = retailPriceId;
343  this._retailPriceAreaId = retailPriceAreaId;
344  this._youSaveId = youSaveId;
345  this._weightId = weightId;
346  this._lengthId = lengthId;
347  this._widthId = widthId;
348  this._heightId = heightId;
349  this._availability = availabilityId;
350  this._subscriptionId = subscriptionId;
351  this._isDDLSwatchCombined = isDDLSwatchCombined;
352  this._VariantsDDLCollection = jsaonDDLMetaData;
353  this._isFitmentEnabled = isFitmentEnabled;
354  this._lazyLoadEnabled = lazyLoad;
355  this._productPhotoHandling = productPhotoHandling;
356  this._externalImageOverrideUrl = externalImageOverrideUrl;
357  this._zoomOverrideUrl = zoomOverrideUrl;
358  this._employeeDDId = employeeDDId;
359  this._customFieldId = customFieldId;
360  this._addToQuoteButtonId = addToQuoteButtonId;
361  this._variantAdditionalInfoId = variantAdditionalInfoId;
362  this.indexes = {};
363  this.combinedDDLCollection = [];
364  this.emailRegex = /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\[(?:\d{1,3}\.){3}\d{1,3}\])$/;
365  this.selectedVariant = "";
366  this.selectedVariantGroup = "";
367  this.selectedControlID = "";
368  var self = this;
369  //---------------- Helpers Related To Combined DDL with Swatch Object based --------////
370  self.combinedSelect = function (containerElement, options) {
371    // element refs
372    if (containerElement == undefined)
373      return;
374    this.el = containerElement;
375    this.comboEl = containerElement.querySelector('[role=combobox]');
376    this.listboxEl = containerElement.querySelector('[role=listbox]');
377    // data
378    this.idBase = this.comboEl.id;
379    this.options = options; // only all options related to this ddl objects
380    // state
381    this.disabled = false;
382    this.activeIndex = 0;
383    this.open = false;
384  };
385  self.combinedSelect.prototype.init = function () {
386    if (this.options == undefined)
387      return;
388    var self = this;
389    var defaultSelectedOption = this.options.find(function (obj, indx, ar) {
390      if (obj.IsDefaultSelected) {
391        this.activeIndex = indx;
392        return obj;
393      } // if system somehow set the default selection
394    });
395
396    if (!defaultSelectedOption || defaultSelectedOption == null) {
397      defaultSelectedOption = this.options[0]; // otherwise show first item selected
398    }
399    this.comboEl.innerHTML = this.buildInnerHtml(defaultSelectedOption); // first element selected by default
400
401    this.comboEl.addEventListener('click', () => this.updateMenuState(true));
402    this.comboEl.addEventListener('blur', this.onComboBlur.bind(this));
403    VariantButtons.UpdateButtons(defaultSelectedOption.GroupId, defaultSelectedOption.VarintId.toString());
404    this.options.map((option, index) => {
405      const optionEl = document.createElement('div');
406      optionEl.setAttribute('role', 'option');
407      optionEl.setAttribute('varname', option.VariantName);
408      optionEl.id = `${this.idBase}-${option.VarintId}`;//optionEl.id = `${this.idBase}-${index}`;
409
410      if (option.VarintId == defaultSelectedOption.VarintId) {
411        optionEl.className = 'variants-combo-option option-current';
412        optionEl.setAttribute('aria-selected', 'true');
413      } else {
414        optionEl.className = 'variants-combo-option';
415        optionEl.setAttribute('aria-selected', 'false');
416      }
417      optionEl.setAttribute('variantid', option.VarintId);
418
419      //optionEl.innerText = option;
420      optionEl.innerHTML = this.buildInnerHtml(option);
421
422      //on combo option click
423      $(optionEl).on('click', function (event, params) {
424        event.stopPropagation();
425        self.onOptionClick(index, event, params);
426      });
427      optionEl.addEventListener('mousedown', this.onOptionMouseDown.bind(this));
428
429      this.listboxEl.appendChild(optionEl);
430    });
431  };
432  self.combinedSelect.prototype.disableMe = function () {
433    this.disabled = true;
434    $(this.comboEl).removeClass("variants-combo-input-enabled").addClass("variants-combo-input-disabled");
435    console.log('Select is disabled');
436  };
437  self.combinedSelect.prototype.enableMe = function () {
438    this.disabled = false;
439    $(this.comboEl).removeClass("variants-combo-input-disabled").addClass("variants-combo-input-enabled");
440  };
441  self.combinedSelect.prototype.buildInnerHtml = function (option) {
442
443    var photoImagePath = "";
444    var bgColor = "";
445    var displayText = "";
446    var height = "";
447    var width = "";
448
449    if (option) {
450
451      displayText = option.DisplayText;
452      photoImagePath = option.PhotoImagePath;
453      bgColor = option.SwatchThumbColor;
454      height = option.SwatchImageHeight;
455      width = option.SwatchImageWidth;
456      if (option.HasPhotoImage) {
457        return '<div class="variants-combo-div-table">' +
458          '<div class="variants-combo-div-table-Row">' +
459            '<div class="variants-combo-div-table-cell CustomConvertPrice">' + displayText + '</div>' +
460            '<div class="variants-combo-div-table-cell-right">' +
461              '<img src="' + photoImagePath + '" height="' + height + '" width="' + width + '" class="variants-combo-img" ' + (self._lazyLoadEnabled ? 'loading="lazy"' : '') + ' />' +
462            '</div>' +
463          '</div>' +
464        '</div>';
465      } else {
466
467        var styleTag = "background-color:" + bgColor;
468        if (!option.PhotoImagePath && !bgColor) {
469          styleTag = "display:none;";
470        }
471    
472        return '<div class="variants-combo-div-table">' +
473          '<div class="variants-combo-div-table-Row">' +
474           '<div class="variants-combo-div-table-cell CustomConvertPrice">' + displayText + '</div>' +
475          '<div class="variants-combo-div-table-cell-right">' +
476          '<img src="' + photoImagePath + '" class="variants-combo-img-backgroundColor" style="' + styleTag + '" ' + (self._lazyLoadEnabled ? 'loading="lazy"' : '') + ' />' +
477           '</div>' + 
478          '</div>' + 
479        '</div>';
480      }
481    }
482  }
483  self.combinedSelect.prototype.onComboBlur = function () {
484    if (this.disabled)
485      return;
486    //console.log('Select.prototype.onComboBlur');
487    if (this.ignoreBlur) {
488      this.ignoreBlur = false;
489      return;
490    }
491
492    if (this.open) {
493      this.updateMenuState(false, false);
494    }
495  };
496  self.combinedSelect.prototype.onOptionChange = function (index) {
497    if (this.disabled)
498      return;
499        // debugger;
500    //console.log('Select.prototype.onOptionChange');
501    this.activeIndex = index;
502    this.comboEl.setAttribute('aria-activedescendant', `${this.idBase}-${index}`);
503
504    // update active style
505    const options = this.el.querySelectorAll('[role=option]');
506    [...options].forEach(optionEl => {
507      optionEl.classList.remove('option-current');
508    });
509    options[index].classList.add('option-current');
510
511    if (isScrollable(this.listboxEl)) {
512      maintainScrollVisibility(options[index], this.listboxEl);
513    }
514  };
515  self.combinedSelect.prototype.onOptionClick = function (index, evnt, eventParamsdata) {
516    if (this.disabled)
517      return;
518    //debugger;
519    //console.log('Select.prototype.onOptionClick');
520    this.onOptionChange(index);
521    this.selectOption(index, eventParamsdata);
522    this.updateMenuState(false, false);
523  };
524  self.combinedSelect.prototype.onOptionMouseDown = function () {
525    this.ignoreBlur = true;
526  };
527  self.combinedSelect.prototype.selectOption = function (index, eventData) {
528    if (this.disabled)
529      return;
530    //console.log('Select.prototype.selectOption');
531    //debugger;
532    const selected = this.options[index];
533    this.comboEl.innerHTML = this.buildInnerHtml(selected);
534    this.activeIndex = index;
535
536    // update aria-selected
537    const options = this.el.querySelectorAll('[role=option]');
538    [...options].forEach(optionEl => {
539      optionEl.setAttribute('aria-selected', 'false');
540    });
541    var currentOptionElement = options[index];
542    currentOptionElement.setAttribute('aria-selected', 'true');
543
544    //To do: shall remove hidden field logic as hidden field is not working on server
545    //var hdnfld = $(this.comboEl.closest(".variants-combo-main-container")).children("[id$='_hdnComboSelectedValue']"); // sets selectedvalue on parent container as well.
546    //hdnfld.val(selected.VarintId);
547    var ddlchildCtrl = $(this.comboEl.closest(".variants-combo-main-container")).children("[id$='_ddlCombined']"); // sets selectedvalue on parent container as well.
548    ddlchildCtrl.val(selected.VarintId); // set selected value here
549    VariantButtons.UpdateButtons(selected.GroupId, selected.VarintId.toString());
550    //eventdata contains if the nextdlls calls come in then if we do not control it individal drop down donot show their own thumbnail image on left
551    if (!eventData) {
552      //make main image change     //like update the left main image
553      if (selected.ControlId && selected.ControlId != '' && selected.VarintId > 0) {
554        if (!self._useVariantInventory) {
555          try {
556            VariantSwatches.SelectVariant(selected.GroupId, selected.VarintId, false, self._imageId, eval('VariantSwatches_' + selected.ControlId));
557          } catch (e) {
558            console.log('error selecting main photo image');
559          }
560        }
561      }
562      self.updateVariantCustomFields(selected.GroupId, selected.VarintId);
563      self.selectedVariantGroup = selected.GroupId;
564      self.selectedVariant = selected.VarintId;
565      self.selectedControlID = selected.ControlId;
566    }
567    ///variant ajax manager;
568    self.onVariantChange($(this.comboEl.closest(".variants-combo-main-container")));
569
570  };
571  self.combinedSelect.prototype.updateMenuState = function (open, callFocus = true) {
572    if (this.disabled)
573      return;
574
575    this.open = open;
576    this.comboEl.setAttribute('aria-expanded', `${open}`);
577    open ? this.el.classList.add('open') : this.el.classList.remove('open');
578    callFocus && this.comboEl.focus();
579  };
580  self.combinedSelect.prototype.setSelectedValue = function (variantId, isUnselectIfnotFound, isNextCall = false) {
581
582    var foundOption = this.options.find(function (obj, indx, ar) {
583      if (obj.VarintId == variantId) {
584        return obj;
585      }
586    });
587
588    if (!foundOption) {
589      if (isUnselectIfnotFound) {
590        this.resetComboBoxSelection();
591        //do i need to call here on variant chane, currently NO may be // to do check - currently there is another bug in current legacy implementation
592      }
593    } else {
594      //set selected value and every thing should be happen for the drop down like selectoption
595      var curroptEl = null;
596      const options = this.el.querySelectorAll('[role=option]');
597      [...options].forEach(optionEl => {
598        if (optionEl.getAttribute("variantid") == variantId) {
599          curroptEl = optionEl;
600        }
601      });
602
603      if (curroptEl) {
604        var params = [];
605        if (isNextCall) {
606          params.push({ VariantId: variantId, IsNextCall: isNextCall });
607        }
608        $(curroptEl).trigger('click', params); // click on option to make it selected
609      }
610    }
611
612  };
613  self.combinedSelect.prototype.getSelectedValue = function () {
614    //debugger;
615    var selectedValue = '';
616    var comboMainContainerDivElement = this.comboEl.closest(".variants-combo-main-container");
617    var ddlchildCtrl = $(comboMainContainerDivElement).children("[id$='_ddlCombined']"); // sets selectedvalue on parent container as well.
618    selectedValue = ddlchildCtrl.val();
619
620    return selectedValue;
621  };
622  self.combinedSelect.prototype.resetComboBoxSelection = function (keepDefaultItemDisplaySelection) {
623    //default 
624    var keepDefaultItemdisplay = false;
625    if (keepDefaultItemDisplaySelection) {
626      keepDefaultItemdisplay = keepDefaultItemDisplaySelection;
627    }
628    var comboMainContainerDivElement = this.comboEl.closest(".variants-combo-main-container");
629    var ddlCombinedSelection = $(comboMainContainerDivElement).children("[id$='_ddlCombined']");
630    //hdnfld.val('');
631    //$(this.comboEl).children("div.variants-combo-div-table").html('');
632    var hdnSelectedVal = ddlCombinedSelection.val();
633
634    if (hdnSelectedVal != "-999" || (hdnSelectedVal == "-999" && !keepDefaultItemdisplay)) {
635      ddlCombinedSelection.val(''); // test it
636      $(this.comboEl).children("div.variants-combo-div-table").html('');
637    }
638    // update aria-selected
639    const options = this.el.querySelectorAll('[role=option]');
640    [...options].forEach(optionEl => {
641      if (hdnSelectedVal != "-999" || (hdnSelectedVal == $(optionEl).attr("variantid") && !keepDefaultItemdisplay)) {
642        optionEl.setAttribute('aria-selected', 'false');
643        $(optionEl).removeClass("option-current");
644      }
645    });
646
647  };
648  self.combinedSelect.prototype.reconfigureComboOptions = function (variantsJson, variantStockStatuses, variantModifierTexts, variantNames) {
649    var mySelf = this;
650    var customID = self._customId;
651    var previousVal = this.getSelectedValue(); // get selectected value
652    var bPreviousFound = false;
653    var firstVariantID = "-999";
654
655    //let's hide the combo options instead of removing
656    $(this.listboxEl).children("[role='option']").each(function () {
657      var $currOption = $(this);
658      if ($currOption.attr("variantid") != "-999") {
659        $currOption.css("display", "none");
660      }
661    });
662    this.resetComboBoxSelection(true);
663
664    var defaultGroupSelection = this.doIHaveDefaultGroupOption();
665
666    var firstVariant = true;
667    $.each(variantsJson, function (key, value) {
668      //add applied variants in sort order. the leading space is to stop json resort variants by key value
669      var variantId = key.trim();
670      var foundOption = $(mySelf.listboxEl).children("[role='option'][variantid='" + variantId + "']");
671      if (foundOption) {
672        foundOption.css("display", "block");
673        var currentVariant = foundOption[0];
674        currentVariant.innerHTML = currentVariant.innerHTML.replace(currentVariant.innerText, value.trim());
675        mySelf.options.find(x => x.VarintId == variantId).DisplayText = value.trim();
676        if (!defaultGroupSelection && firstVariant) {
677          firstVariant = false; // this is to make dropdown a first selection only first time
678          firstVariantID = variantId;
679        }
680      }
681    });
682
683    if (previousVal != "") {
684
685      //keep previous selection selected if it is still available
686      $.each(variantsJson, function (key, value) {
687        //add applied variants in sort order. the leading space is to stop json resort variants by key value
688        var variantId = key.trim();
689        //only set the selected value to previous one if upcoming in variantjson contains the variant id of previous variantid
690        if (variantId != "-999" && variantId == previousVal && !bPreviousFound && (variantStockStatuses === null || variantStockStatuses[key] != 0)) {
691          bPreviousFound = true;
692          mySelf.setSelectedValue(previousVal, true, true);
693        }
694        else if (variantId != "-999" && variantId == previousVal && (variantStockStatuses != null && variantStockStatuses[key] == 0)) {
695          let errorDv = $('.variant-custom-error[groupname=' + customID + '_' + mySelf.el.getAttribute("groupname") + ']');
696          if (errorDv && errorDv.length > 0 && errorDv[0].hasAttribute('data-auto-select')) {
697            errorDv.html('Profile option is unavailable.');
698            errorDv[0].setAttribute('data-error', 'status-unavailable');
699          }
700          if (!firstVariant)
701            mySelf.setSelectedValue(firstVariantID, true, true);
702        }
703        var button = $("div[id^='varbutton_" + mySelf.options.find(x => x.VarintId == variantId).GroupId + "_" + variantId + "']");
704        if (button.length > 0 && variantNames !== null && variantModifierTexts !== null)
705          button.html("<span class='desc-text'>" + variantNames[key] + "</span><span class='modifier-text'>" + variantModifierTexts[key] + "</span>");
706      });
707    }
708    else {
709      if (!firstVariant)
710        mySelf.setSelectedValue(firstVariantID, true, true);
711    }
712    VariantButtons.HideButtons(mySelf.options[0].GroupId, variantsJson);
713  };
714  self.combinedSelect.prototype.doIHaveDefaultGroupOption = function () {
715
716    var result = false;
717    var defaultGroupSelection = this.options.find(function (obj, indx, ar) {
718      if (obj.VarintId == "-999") {
719        return obj;
720      } // if system somehow set the default selection
721    });
722
723
724    if (defaultGroupSelection) {
725      result = true;
726    }
727    return result;
728
729  }
730  self.locateCombinedDDLObject = function (elementId) {
731    var currentCombinedDDL = this.combinedDDLCollection.find(function (obj, index, array) {
732      if (obj.el.id == elementId) {
733        return obj;
734      }
735    });
736    return currentCombinedDDL;
737  };
738
739  $(function () {
740    self.init();
741  });
742};
743
744VariantAjaxManager.prototype = {
745
746  init: function () {
747    var self = this;
748    //debugger;
749
750    var groupNameSelector = "variantGroupID_" + this._customId;
751
752    var ddlSelector = ".variantDropDown" + this._customId + ", .variantRadioButtonList" + this._customId + ", .variantCheckBox" + this._customId;
753
754    if (this._isDDLSwatchCombined) {
755      ddlSelector = ".variantRadioButtonList" + this._customId + ", .variantCheckBox" + this._customId; // for avoid binding change ddl event on combined ddl which is of type div not type select
756      this._VariantsDDLCollection.map((groupItem, index) => {
757
758        var combinedSelect = new self.combinedSelect($('#' + groupItem.SelectDDLClientId).get(0), groupItem.DropDownDataCol);
759        combinedSelect.init();
760        this.combinedDDLCollection.push(combinedSelect); // maintain all ddl collection object
761      });
762    }
763    var $dd = $(ddlSelector);
764    this.$dd = $dd;
765
766    //20220309 AG Shared for each functions
767    function getCurrentCombinedDDL(elementId) {
768      return self._isDDLSwatchCombined ? self.locateCombinedDDLObject(elementId) : null;
769    }
770    function disableVariant(element, currentCombinedDDL) {
771      if ($(element).is("select")) {
772        $(element).prop("disabled", "disabled");
773      }
774      else if (this._isDDLSwatchCombined && $(element).is("div.variants-combo-main-container")) {
775        // ?? this is combined drop down what to do with it?
776        currentCombinedDDL.disableMe();
777      }
778      else {
779        $(element).find("input").attr("disabled", "disabled").first().prop("checked", "checked");
780      }
781    }
782
783    //20220308 AG Hide variants on initial load. Variant options will be loaded after fitment is selected
784    if (this._isFitmentEnabled) {
785      $dd.each(function (index, element) {
786        var currentCombinedDDL = getCurrentCombinedDDL($(this).prop("id"));
787        self.indexes[this.id] = index;
788
789        // Disable all variants to ensure they wont be used
790        disableVariant(this, currentCombinedDDL);
791      });
792    }
793
794    if (this._useVariantInventory) {
795
796      if (this._isDDLSwatchCombined) {
797        this.$varInvDDs = $(".variantDropDown-Combined" + this._customId + ", " + ddlSelector).not("[id*=NonInventoryVariantGroup" + this._customId + "]");
798      } else {
799        this.$varInvDDs = $dd.not("[id*=NonInventoryVariantGroup" + this._customId + "]");
800      }
801
802
803      if ($("#" + this._selectedVariantsId).val() !== undefined) {
804        var ids = $("#" + this._selectedVariantsId).val().split("|");
805
806        var lastVal;
807        this.$varInvDDs.each(function (i) {
808          self.indexes[this.id] = i;
809          var currentCombinedDDL = getCurrentCombinedDDL($(this).prop("id"));
810
811          //if (i < ids.length) {
812            //if ($(this).is("select")) {
813              //$(this).val(ids[i]); // seems like setting up a selected
814
815            //} else if (self._isDDLSwatchCombined && $(this).is("div.variants-combo-main-container")) {
816              // // ?? this is combined drop down what to do with it?                    
817              //var currentCombinedDDL =  locateCombinedDDLObject($(this));
818              //currentCombinedDDL.setSelectedValue(ids[i], true); // should unselect for inventory variant case?
819            //}
820          //}
821
822          if (self._useVariantInventory && i > 0 && lastVal === "-999") {
823            disableVariant(this, currentCombinedDDL);
824          }
825
826          if ($(this).is("select")) {
827            lastVal = $(this).val();
828          } else if (self._isDDLSwatchCombined && $(this).is("div.variants-combo-main-container")) {
829            lastVal = currentCombinedDDL.getSelectedValue(); // should unselect for inventory variant case?
830          }
831          else {
832            if ($(this).find("input:checked").length > 0) {
833              lastVal = $(this).find("input:checked").val();
834            }
835            else {
836              lastVal = "-999";
837            }
838          }
839        });
840      }
841      else {
842        this.$varInvDDs.each(function (i) {
843          self.indexes[this.id] = i;
844        });
845      }
846    }
847
848    $('.variant-repeater__variant').unbind('click').click(function () {
849
850        var variant = $(this);
851
852        if (variant.hasClass('selected'))
853          variant.removeClass('selected');
854        else 
855          variant.addClass("selected");
856
857        self.updatePrice();
858      });
859
860    $(".variantCheckBox" + this._customId + " label").each(function () {
861      $(this).addClass("CustomConvertPrice");
862    });
863
864    $(".variantRadioButtonList" + this._customId + " label").each(function () {
865      $(this).addClass("CustomConvertPrice");
866    });
867
868    $(".variantDropDown" + this._customId + " option").each(function () {
869      $(this).addClass("CustomConvertPrice");
870    });
871
872    $(".variant-repeater__variant .card-text").each(function () {
873      $(this).addClass("CustomConvertPrice");
874    });
875
876    $dd.change(function () {
877      if ($(this).is("select")) {
878        try {
879          self.selectedVariantGroup = $(this).parent().find("input[type = hidden]").val();
880          self.selectedVariant = $(this).val();
881          self.selectedControlID = "ProductVariations_variantGroup" + self._customId + "_" + self.selectedVariantGroup;
882          self.updateVariantCustomFields(self.selectedVariantGroup, self.selectedVariant);
883        }
884        catch { }
885      }
886      self.onVariantChange($(this));
887    });
888
889    $(".variantRadioButtonList" + this._customId + " input").change(function () {
890      try {
891        self.selectedVariantGroup = $(this).attr("name").split("_").pop();
892        self.selectedVariant = $(this).val();
893        self.selectedControlID = "ProductVariations_variantGroup" + self._customId + "_" + self.selectedVariantGroup;
894        self.updateVariantCustomFields(self.selectedVariantGroup, self.selectedVariant);
895      }
896      catch { }
897      self.onVariantChange($(this));
898    });
899
900    $(".variantCheckBox" + this._customId + " input").change(function () {
901      self.onVariantChange($(this));
902    });
903
904    $(".personalizationTextbox" + this._customId).change(function () {
905      self.onPersonalizationChange($(this));
906    });
907
908    $(".personalizationTextboxWithConfirm" + this._customId).change(function () {
909      self.onPersonalizationChange($(this));
910    });
911
912    $(".PersonalizationFileUpload" + this._customId).change(function () {
913      self.onPersonalizationChange($(this));
914    });
915
916    $(".PersonalizationEmailAddress" + this._customId).change(function () {
917      self.onPersonalizationChange($(this));
918    });
919
920    $(".PersonalizationPhoneNumber" + this._customId).change(function () {
921      self.onPersonalizationChange($(this));
922    });
923
924    $(".PersonalizationDatePicker" + this._customId).change(function () {
925      self.onPersonalizationChange($(this));
926      self.enableSteps($(this), self._customId);
927    });
928
929    $(".PersonalizationDropDown" + this._customId).change(function () {
930      self.onPersonalizationChange($(this));
931      self.enableSteps($(this), self._customId);
932    });
933
934    $('input[class*="NextStep' + this._customId + '"]').keyup(function (e) {
935      self.enableSteps($(this), self._customId);
936    });
937
938    $('select[class*="NextStep' + this._customId + '"]').keyup(function (e) {
939      self.enableSteps($(this), self._customId);
940    });
941
942    $('textarea[class*="NextStep' + this._customId + '"]').keyup(function (e) {
943      self.enableSteps($(this), self._customId);
944    });
945
946    if (this._subscriptionId != "") {
947
948      $("#" + this._subscriptionId).change(function () {
949        self.updatePrice();
950      });
951    }
952
953    try {
954      if (typeof this.$varInvDDs != 'undefined' && this.$varInvDDs) {
955        var firstInvVariantddl = this.$varInvDDs.first();
956        if (!this._isDDLSwatchCombined) {
957          firstInvVariantddl.change();  // ddl change event internally calls to this // but testing needs here do not know yet the purpose
958        } else {
959
960          if (firstInvVariantddl.is("div.variants-combo-main-container")) {
961            self.onVariantChange($(firstInvVariantddl)); // ddl change event internally calls to this // but testing needs here do not know yet the purpose
962          } else {
963            firstInvVariantddl.change();
964          }
965        }
966      }
967    }
968    catch (err) { }
969
970    this.initVariantCustomFields();
971  },
972
973  ajaxCall: function (method, parameters, success) {
974    $.ajax({
975      type: "POST",
976      contentType: "application/json; charset=utf-8",
977      url: "/Store/Controls/ScriptService.asmx/" + method,
978      dataType: "json",
979      data: parameters
980    }).done(success);
981  },
982
983  onPersonalizationChange: function ($element) {
984    $element.removeClass("needsSelection");
985    this.updatePrice();
986  },
987
988  onVariantChange: function ($element) {
989    if (this._useVariantInventory) {
990      this.updateVariants($element);
991    }
992    else {
993      this.updatePrice();
994    }
995
996    $element.removeClass("needsSelection");
997  },
998
999  updateVariantCustomFields: function (groupId, variantId) {
1000    var $group = $(".variant-custom-fields__group[data-group='" + groupId + "']");
1001    if ($group.length === 0) return;
1002    $group.find(".variant-custom-fields__variant").hide();
1003    $group.find(".variant-custom-fields__variant[data-value='" + variantId + "']").show();
1004  },
1005
1006  initVariantCustomFields: function () {
1007    var self = this;
1008    $(".variant-custom-fields__group").each(function () {
1009      var groupId = $(this).attr("data-group");
1010      $(this).find(".variant-custom-fields__variant").hide();
1011
1012      var variantId = null;
1013
1014      var $select = $("select[id*='variantGroup" + self._customId + "_" + groupId + "']");
1015      if ($select.length) {
1016        variantId = $select.val();
1017      }
1018
1019      if (!variantId || variantId === '-999') {
1020        var $checked = $(".variantRadioButtonList" + self._customId + " input[name$='_" + groupId + "']:checked");
1021        if ($checked.length) {
1022          variantId = $checked.val();
1023        }
1024      }
1025
1026      self.updateVariantCustomFields(groupId, variantId);
1027    });
1028  },
1029
1030  onFitmentChange: function (matchedChildrenIds) {
1031    this.getVariantsFromFitment(matchedChildrenIds);
1032  },
1033
1034  enableSteps: function ($element, customId) {
1035    var arr = $element.prop('class').split(" ");
1036
1037    if (arr.length >= 3) {
1038
1039      //have to find step group, stepID and nextstep
1040      var stepGroupClass = "";
1041      var stepIdClass = "";
1042      var nextStepIdClass = "";
1043      for (var i = 0; i < arr.length; i++) {
1044        if (arr[i].indexOf("StepGroup") != -1)
1045          stepGroupClass = arr[i];
1046        else if (arr[i].indexOf("StepID") != -1)
1047          stepIdClass = arr[i];
1048        else if (arr[i].indexOf("NextStep") != -1)
1049          nextStepIdClass = arr[i];
1050      }
1051
1052      if (stepIdClass != "" && nextStepIdClass != "") {
1053        var stepIDs = stepIdClass.split("_");
1054        var stepID = stepIDs[stepIDs.length - 1];
1055        var nextStepIDs = nextStepIdClass.split("_");
1056        var nextStepID = nextStepIDs[nextStepIDs.length - 1];
1057        var c = ".StepID" + customId + "_" + nextStepID;
1058        if ($element.val() == "") {
1059          $(c).prop("disabled", true);
1060          $(c).val("");
1061          $(c).trigger("keyup");
1062        }
1063        else {
1064          $(c).prop("disabled", false);
1065          if ($(c).hasClass('iti__tel-input')) {
1066            var iti = intlTelInput.getInstance($(c)[0]);
1067            iti.setDisabled(false);
1068          }
1069        }
1070      }
1071    }
1072  },
1073
1074  validateEmail: function ($element) {
1075    var val = $element.val().trim();
1076    if (val.length > 0 && !this.emailRegex.test(val)) {
1077      return "Invalid email address.";
1078    }
1079  },
1080
1081  setSelectionsOnLink: function (link, selections) {
1082
1083    if (selections == '')
1084      return;
1085
1086    var href = $(link).prop("href");
1087
1088    //need to get selections from qty grid as well
1089    //needs to build a string to add multiple items to cart, one for each qty grid option that is specified, and the the options from the rest of the selections
1090    var qtyGrid = $(".VariantQuantityGrid" + this._customId);
1091    //if we have a qty grid, then for each that has qty, need to add that to the link
1092    //addtocart.aspx?itemid_1=blah&quantity_1=blah&variantid_1=1|2|3  need to get variant and qty of the individual qty grid column
1093    if (qtyGrid.length > 0) {
1094      //then we basically have to rebuild the link
1095      //get a list of all textboxes
1096      var $qtyTextboxes = qtyGrid.find(".VariantQuantityGridTextbox" + this._customId);
1097
1098      var qs = "";
1099
1100      for (var i = 0; i < $qtyTextboxes.length; i++) {
1101        var iQty = parseInt($($qtyTextboxes[i]).find(".VariantQuantityBox").val());
1102        var iVariantID = parseInt($($qtyTextboxes[i]).find("input[id$='hfVariantQuantityGridVariantID" + this._customId + "']").val());
1103
1104        if (iQty > 0) {
1105
1106          var sVariants = iVariantID;
1107          if (selections.length > 0)
1108            sVariants += "|" + selections;
1109
1110          if (qs.length > 0)
1111            qs += "&";
1112          qs += "itemID_" + i + "=" + this._itemId + "&quantity_" + i + "=" + iQty + "&variantID_" + i + "=" + sVariants;
1113        }
1114      }
1115
1116      href = "/store/AddToCart.aspx?" + qs;
1117    }
1118    else {
1119      href += "&variantID=" + selections;
1120    }
1121
1122    $(link).prop("href", href);
1123  },
1124
1125  setPersonalizationsOnLink: function (link, selections) {
1126
1127    if (selections == '')
1128      return;
1129
1130    var href = $(link).prop("href");
1131    href += "&personalization=" + selections;
1132    href += "&personalizationids=" + $("#" + this._personalizationIdsId).val();
1133
1134    $(link).prop("href", href);
1135  },
1136
1137  uploadPersonalizationFiles: function () {
1138
1139    var self = this;
1140    $(".PersonalizationFileUpload" + this._customId).each(function (index, element) {
1141      if ($(element).val() != '') {
1142
1143        var fileData = $(element).prop("files")[0];
1144        var formData = new window.FormData();
1145        formData.append("file", fileData);
1146
1147        var temp = $.ajax({
1148          type: "POST",
1149          url: "/Store/UploadFile.ashx",
1150          data: formData,
1151          dataType: "text",
1152          cache: false,
1153          contentType: false,
1154          processData: false,
1155          async: false
1156        }).responseText;
1157
1158        if (temp) {
1159          result = JSON.parse(temp);
1160
1161          if (result) {
1162
1163            if (result.indexOf("Error") != -1) {
1164              alert(result);
1165              return false;
1166            }
1167            else {
1168              $(element).prop('data-url', result);
1169              return true;
1170            }
1171
1172          }
1173          else {
1174            alert("Failed to connect to server to upload file.");
1175            return false;
1176          }
1177        }
1178        else {
1179          alert("Failed to connect to server to upload file.");
1180          return false;
1181        }
1182      }
1183    });
1184
1185    return true;
1186  },
1187
1188  saveSelections: function (selections) {
1189    $("#" + this._selectedVariantsId).val(selections);
1190  },
1191
1192  savePersonalizations: function (selections) {
1193    $("#" + this._personalizationStringsId).val(selections);
1194  },
1195
1196  checkSelections: function (bForceValidQty, bLinkClicked, callerButtonId) {
1197    var selected = true;
1198    var self = this;
1199    //this part is also required some domain and data setup knowledge
1200    var result = {
1201      success: true,
1202      message: ""
1203    };
1204
1205    //need to have ability to only check for ones that have a quantity
1206    var qtyGrid = $(".VariantQuantityGrid" + this._customId);
1207
1208    if (bForceValidQty && this.qtyIsEmpty() && qtyGrid.length == 0) {
1209      return result;
1210    }
1211    else if (qtyGrid.length > 0 && bLinkClicked) {
1212      //verify we have a valid quantity in the grid before we try to add
1213      //but only when adding via the link, b/c the button will just ignore if 0 qtys
1214      var $qtyTextboxes = qtyGrid.find(".VariantQuantityGridTextbox" + this._customId);
1215      var qtyGridHasQty = false;
1216      for (var i = 0; i < $qtyTextboxes.length; i++) {
1217        var iQty = parseInt($($qtyTextboxes[i]).find(".VariantQuantityBox").val());
1218
1219        if (iQty > 0) {
1220
1221          qtyGridHasQty = true;
1222        }
1223      }
1224      selected = qtyGridHasQty;
1225      if (!selected) {
1226        result.message = "A quantity wasn't entered";
1227      };
1228    }
1229
1230    var sStoreTextVariantMessage = $("input[id$='hfAlertMsg_Variant']").val();
1231    if (sStoreTextVariantMessage == undefined || sStoreTextVariantMessage.length <= 0) {
1232      sStoreTextVariantMessage = "Please select the product options for this item in the lists below, there is at least 1 selection missing.\n\n";
1233    }
1234
1235    //both types of drop down can be handled here in one selector
1236    $(".variantDropDown" + this._customId + ", .variantDropDown-Combined" + this._customId).each(function (index, element) {
1237      var $dd = $(element);
1238      var isNonInventory = $dd.attr('id').indexOf('NonInventoryVariantGroup') != -1;
1239      var ddSelectedVal = '';
1240
1241      var isValidationRequired = true;
1242      if (callerButtonId.indexOf('btnUpdateQuantities') > 0) {
1243        if ($dd.attr('id').indexOf('_rpCart_') > 0) {
1244          isValidationRequired = true;
1245        }
1246        else {
1247          isValidationRequired = false;
1248        }
1249      }
1250
1251      if (self._isDDLSwatchCombined) {
1252        var combinedDllObj = self.locateCombinedDDLObject($dd.attr('id'));
1253        if (combinedDllObj) {
1254          ddSelectedVal = combinedDllObj.getSelectedValue();
1255        }
1256      } else {
1257        ddSelectedVal = $dd.val();
1258      }
1259
1260      if (ddSelectedVal === "-999" && !isNonInventory && isValidationRequired) {
1261        $dd.addClass("needsSelection");
1262        selected = false;
1263
1264        if (result.message.length <= 0) {
1265          result.message = sStoreTextVariantMessage.replace("##VARIANTGROUP##", element.getAttribute("groupname")).replace("##NUMBEROFSELECTION## ", "");
1266        }
1267      } else {
1268        $dd.removeClass("needsSelection");
1269      }
1270    });
1271
1272
1273    $(".variantRadioButtonList" + this._customId).each(function (index, element) {
1274      var $radiolist = $(element);
1275      var $rb = element.querySelectorAll("input:checked");
1276      var isNonInventory = $rb[0].id.indexOf('NonInventoryVariantGroup') != -1;
1277      if (($rb.length <= 0 || ($rb.length > 0 && ($rb[0].value === "-999" && !isNonInventory)))) {
1278        $radiolist.addClass("needsSelection");
1279        selected = false;
1280
1281        if (result.message.length <= 0) {
1282          result.message = sStoreTextVariantMessage.replace("##VARIANTGROUP##", element.getAttribute("groupname")).replace("##NUMBEROFSELECTION## ", "");
1283        }
1284      } else {
1285        $radiolist.removeClass("needsSelection");
1286      }
1287    });
1288
1289    $(".variantCheckBox" + this._customId).each(function (index, element) {
1290      var $chklist = $(element);
1291      var minSelection = parseInt(element.getAttribute("minselection"));
1292      var maxSelection = parseInt(element.getAttribute("maxselection"));
1293      var selectedTotal = element.querySelectorAll("input:checked").length;
1294      if ((minSelection > 0 && selectedTotal < minSelection) || (maxSelection > 0 && selectedTotal > maxSelection)) {
1295        $chklist.addClass("needsSelection");
1296        selected = false;
1297
1298        if (result.message.length <= 0) {
1299          if (minSelection != maxSelection && maxSelection > 0) {
1300            result.message = sStoreTextVariantMessage.replace("##VARIANTGROUP##", element.getAttribute("groupname")).replace("##NUMBEROFSELECTION##", minSelection.toString() + "-" + maxSelection.toString());
1301          }
1302          else {
1303            result.message = sStoreTextVariantMessage.replace("##VARIANTGROUP##", element.getAttribute("groupname")).replace("##NUMBEROFSELECTION##", minSelection.toString());
1304          }
1305        }
1306      } else {
1307        $chklist.removeClass("needsSelection");
1308      }
1309    });
1310
1311    var personalizeMessage = $("input[id$='hfAlertMsg_Personalize']").val();
1312    var hasPersonalizeError = false;
1313
1314    if (callerButtonId.indexOf('btnUpdateQuantities') <= 0) { //Personalization validation is not required if quantities are updated from Small Cart
1315      $(".personalizationTextbox" + this._customId + ".ProductPersonalizationRequired").each(function (index, element) {
1316        if ($(element).val() == '') {
1317          $(element).addClass("needsSelection");
1318          selected = false;
1319          hasPersonalizeError = true;
1320          if (personalizeMessage.length <= 0) {
1321            personalizeMessage = "Please enter a personalization value for the required fields.";
1322          }
1323        } else {
1324          $(element).removeClass("needsSelection");
1325        }
1326      });
1327
1328      $(".personalizationTextboxWithConfirm" + this._customId + ".ProductPersonalizationRequired").each(function (index, element) {
1329        if ($(element).val() == '') {
1330          $(element).addClass("needsSelection");
1331          selected = false;
1332          hasPersonalizeError = true;
1333          if (personalizeMessage.length <= 0) {
1334            personalizeMessage = "Please enter a personalization value for the required fields.";
1335          }
1336        } else {
1337          $(element).removeClass("needsSelection");
1338        }
1339      });
1340
1341      $(".PersonalizationEmailAddress" + this._customId).each(function (index, element) {
1342        var result = self.validateEmail($(element));
1343        if (result && result.length > 0) {
1344          hasPersonalizeError = true;
1345          $(element).addClass("needsSelection");
1346          selected = false;
1347
1348          if (personalizeMessage.length <= 0) {
1349            personalizeMessage = personalizeMessage + "\n\n" + result;
1350          }
1351          else {
1352            personalizeMessage += "\n\n" + result;
1353          }
1354        } else {
1355          $(element).removeClass("needsSelection");
1356        }
1357      });
1358
1359      $(".PersonalizationEmailAddress" + this._customId + ".ProductPersonalizationRequired").each(function (index, element) {
1360        if ($(element).val() == '') {
1361          $(element).addClass("needsSelection");
1362          selected = false;
1363          hasPersonalizeError = true;
1364          if (personalizeMessage.length <= 0) {
1365            personalizeMessage = "Please enter a personalization value for the required fields.";
1366          }
1367        } else {
1368          $(element).removeClass("needsSelection");
1369        }
1370      });
1371
1372      $(".PersonalizationPhoneNumber" + this._customId + ".ProductPersonalizationRequired").each(function (index, element) {
1373        if ($(element).val() == '') {
1374          $(element).addClass("needsSelection");
1375          selected = false;
1376          hasPersonalizeError = true;
1377          if (personalizeMessage.length <= 0) {
1378            personalizeMessage = "Please enter a personalization value for the required fields.";
1379          }
1380        } else {
1381          $(element).removeClass("needsSelection");
1382        }
1383      });
1384
1385      $(".PersonalizationDatePicker" + this._customId + ".ProductPersonalizationRequired").each(function (index, element) {
1386        if ($(element).val() == '') {
1387          $(element).addClass("needsSelection");
1388          selected = false;
1389          hasPersonalizeError = true;
1390          if (personalizeMessage.length <= 0) {
1391            personalizeMessage = "Please enter a personalization value for the required fields.";
1392          }
1393        } else {
1394          $(element).removeClass("needsSelection");
1395        }
1396      });
1397
1398      $(".PersonalizationDropDown" + this._customId + ".ProductPersonalizationRequired").each(function (index, element) {
1399        if ($(element).val() == '') {
1400          $(element).addClass("needsSelection");
1401          selected = false;
1402          hasPersonalizeError = true;
1403          if (personalizeMessage.length <= 0) {
1404            personalizeMessage = "Please enter a personalization value for the required fields.";
1405          }
1406        } else {
1407          $(element).removeClass("needsSelection");
1408        }
1409      });
1410
1411      $(".PersonalizationFileUpload" + this._customId + ".ProductPersonalizationRequired").each(function (index, element) {
1412        if ($(element).val() == '') {
1413          selected = false;
1414          hasPersonalizeError = true;
1415          $(element).addClass("needsSelection");
1416          if (personalizeMessage.length <= 0) {
1417            personalizeMessage = "Please enter a personalization value for the required fields.";
1418          }
1419        }
1420        else {
1421          $(element).removeClass("needsSelection");
1422        }
1423      });
1424
1425      var customId = this._customId;
1426
1427      $(".personalizationTextboxWithConfirm" + this._customId).each(function (index, element) {
1428        var value = $(element).val();
1429        var $confirmBox = $("[id$='" + $(element).attr("data-confirmid") + "']");
1430        if (value != '' && $confirmBox.length > 0) {
1431          var confirmValue = $($confirmBox).val();
1432          if (confirmValue != value) {
1433            selected = false;
1434            hasPersonalizeError = true;
1435            personalizeMessage = personalizeMessage + "\n\nThe personalization values entered do n
1435ot match. Please enter matching values.";
1436            $confirmBox.addClass("needsSelection");
1437          }
1438          else {
1439            $confirmBox.removeClass("needsSelection");
1440          }
1441        }
1442      });
1443    }
1444
1445    if (!selected) {
1446      result.success = false;
1447      if (hasPersonalizeError)
1448        result.message = result.message + "\n\n" + personalizeMessage;
1449    }
1450
1451    return result;
1452  },
1453
1454  getSelections: function (bForceValidQty) {
1455    var options = [];
1456
1457    //need to have ability to only check for ones that have a quantity
1458    if (bForceValidQty && this.qtyIsEmpty()) {
1459      return options;
1460    }
1461    // dropdowns
1462    if (this._isDDLSwatchCombined) {
1463      $(".variantDropDown-Combined" + this._customId).children("[id$='_ddlCombined']").each(function () {
1464        options.push($(this).val());
1465      });
1466    } else {
1467      $(".variantDropDown" + this._customId).each(function () {
1468        options.push($(this).val());
1469      });
1470    }
1471
1472    //variant repeater
1473    $(".variant-repeater__variant.selected").each(function () {
1474      options.push($(this).data('value'));
1475    });
1476
1477
1478    // radio buttons
1479    $(".variantRadioButtonList" + this._customId + " input:radio:checked").each(function () {
1480      options.push($(this).val());
1481    });
1482
1483    // checkboxes
1484    $(".variantCheckBox" + this._customId + " input:checkbox:checked").each(function () {
1485      options.push($(this).parent().prop("id"));
1486    });
1487
1488    return options.filter(option => option != null);
1489  },
1490
1491  getPersonalizations: function () {
1492
1493    var options = [];
1494
1495    //order is important here, must get them in the same order they are on the page
1496    $(".personalization" + this._customId).each(function () {
1497      if (typeof $(this).prop('data-url') != 'undefined' && $(this).prop('data-url') != '') {
1498        options.push($(this).prop('data-url'));
1499      }
1500      else if ($(this).hasClass('iti__tel-input')) {
1501        var iti = intlTelInput.getInstance($(this)[0]);
1502        options.push(iti.getNumber(intlTelInput.utils.numberFormat.INTERNATIONAL));
1503      }
1504      else {
1505        options.push($(this).val().replace(/\|/g, '%7C'));
1506      }
1507    });
1508    return options;
1509  },
1510
1511  qtyIsEmpty: function () {
1512
1513    if (this._bindQtyToParent) {
1514      if (this._bindQtyCheckBoxId.length > 0 && $("#" + this._bindQtyCheckBoxId + ":checked").length > 0) {
1515        return false;
1516      }
1517      else
1518        return true;
1519    }
1520
1521    var quantity = $("#" + this._qtyTextboxId).val();
1522
1523    if (!quantity) {
1524      var combinedQty = 0;
1525
1526      if (this._qtyDiscountsAcrossVariants) {
1527        $(".VariantQuantityGridTextbox" + this._customId + " input").each(function () {
1528          var qty = parseInt($(this).val());
1529          if (!isNaN(qty)) {
1530            combinedQty = combinedQty + qty;
1531          }
1532        });
1533      }
1534
1535      quantity = combinedQty;
1536    }
1537
1538    if (quantity <= 0) {
1539      if (!this._useQtyOf1IfNoQty)
1540        return true;
1541    }
1542
1543    return false;
1544
1545  },
1546
1547  getQuantity: function () {
1548    var quantity = $("#" + this._qtyTextboxId).val();
1549
1550    if (!quantity) {
1551      var combinedQty = 0;
1552
1553      if (this._qtyDiscountsAcrossVariants) {
1554        $(".VariantQuantityGridTextbox" + this._customId + " input").each(function () {
1555          var qty = parseInt($(this).val());
1556          if (!isNaN(qty)) {
1557            combinedQty = combinedQty + qty;
1558          }
1559        });
1560      }
1561
1562      if ($("#hfQtyDiscountAcrossVariants").val() === "True") {
1563        $(".ProductDetailsVariantMatrixQuantityBox input").each(function () {
1564          var qty = parseInt($(this).val());
1565          if (!isNaN(qty)) {
1566            combinedQty = combinedQty + qty;
1567          }
1568        });
1569      }
1570
1571      quantity = combinedQty;
1572    }
1573
1574    if (quantity <= 0) {
1575      quantity = 1;
1576    }
1577
1578    return quantity;
1579  },
1580
1581  htmlEscape: function (str) {
1582    return String(str)
1583      .replace(/&/g, '&amp;')
1584      .replace(/"/g, '&quot;')
1585      .replace(/'/g, '&#39;')
1586      .replace(/</g, '&lt;')
1587      .replace(/>/g, '&gt;');
1588  },
1589
1590  getUpdatedImgUrl: function (url, newPath, productPhotoHandling, externalImageOverrideUrl) {
1591    if (productPhotoHandling == 'ExternalImaging') {
1592      var oldMainImageOptions = window.resizehelper.getExternalImageOptionsFromUrl(externalImageOverrideUrl, url);
1593      return window.resizehelper.getExternalImageUrl(externalImageOverrideUrl, newPath, oldMainImageOptions.width, oldMainImageOptions.height);
1594    }
1595    var oldUrl = url.split('?')
1596    var newUrl = newPath;
1597    if (newPath.startsWith("/") && oldUrl.length > 1) {
1598      newUrl = "/resize" + newPath;
1599    }
1600    if (oldUrl.length > 1)
1601      newUrl = newUrl + "?" + oldUrl[1];
1602    return newUrl;
1603  },
1604
1605  updatePrice: function () {
1606    var itemID = this._itemId;
1607    var quantity = this.getQuantity();
1608
1609    var options = this.getSelections();
1610    this.saveSelections(options.join("|"));
1611    var sOptions = options.join(", ");
1612
1613    if (this._pkgVariants && this._pkgVariants.length > 0) {
1614      if (sOptions.length > 0)
1615        sOptions += ", ";
1616      sOptions += this._pkgVariants;
1617    }
1618    var personalizations = this.getPersonalizations();
1619    this.savePersonalizations(personalizations.join("|"));
1620    var sPersonalizations = '';
1621    $(personalizations).each(function (index, element) {
1622      if (sPersonalizations != '')
1623        sPersonalizations += ",";
1624      sPersonalizations += JSON.stringify(element);
1625    });
1626
1627    var personalizationIds = $("#" + this._personalizationIdsId).val();
1628    if (typeof personalizationIds != 'undefined' && personalizationIds.length > 0)
1629      personalizationIds = personalizationIds.replace(/\|/g, ', ');
1630    else
1631      personalizationIds = '';
1632
1633
1634    var subscriptionId = "0";
1635    if (this._subscriptionId != '') {
1636      subscriptionId = $("#" + this._subscriptionId).val();
1637      let selectedOption = $("#" + this._subscriptionId + ' option:selected').text();
1638      if (typeof subscriptionId == 'undefined' || selectedOption == "NoRenewal")
1639        subscriptionId = "0";
1640    }
1641
1642    var params = '{"itemID": ' + itemID + ', "quantity": ' + quantity + ', "variantIDs": [' + sOptions + '], "personalizationIds": [' + personalizationIds + '], "personalizationStrings": [' + sPersonalizations + '], "subscription": ' + subscriptionId + '}';
1643
1644    var self = this;
1645
1646    this.ajaxCall("GetPriceWithOptions", params, function (result) {
1647
1648      var resultPreSalePrice = Number(result.d.preSalePrice.replace(/[^0-9\.-]+/g, ""));
1649      var resultPrice = Number(result.d.price.replace(/[^0-9\.-]+/g, ""));
1650
1651      if (self._qtyDiscountPricesId) {
1652        $("#" + self._qtyDiscountPricesId).html(result.d.qtyBreakPrices);
1653      }
1654      else if (resultPreSalePrice > resultPrice && self._salePriceId && $('#' + self._salePriceId).length > 0) {
1655
1656        if (self._childPriceId) {
1657          $("#" + self._priceId).find("#" + self._childPriceId).html('');
1658          $("#" + self._priceId).find("#" + self._childPriceId).hide();
1659          $("#" + self._priceAreaId).hide();
1660        }
1661        else if (self._priceId) {
1662          $("#" + self._priceId).html('');
1663          $("#" + self._priceAreaId).hide();
1664        }
1665
1666        if (self._wasPriceId && $('#' + self._wasPriceId).length > 0) {
1667          $('#' + self._wasPriceId).html(result.d.preSalePrice);
1668          $('#' + self._wasPriceAreaId).show();
1669        }
1670
1671        if (self._salePriceId && $('#' + self._salePriceId).length > 0) {
1672          $('#' + self._salePriceId).html(result.d.price);
1673          $('#' + self._salePriceAreaId).show();
1674        }
1675      }
1676      else {
1677
1678        if (self._wasPriceId && $('#' + self._wasPriceId).length > 0) {
1679          $('#' + self._wasPriceId).html('');
1680          $('#' + self._wasPriceAreaId).hide();
1681        }
1682        if (self._salePriceId && $('#' + self._salePriceId).length > 0) {
1683          $('#' + self._salePriceId).html('');
1684          $('#' + self._salePriceAreaId).hide();
1685        }
1686
1687        if (self._priceAreaId) {
1688          $("#" + self._priceAreaId).show();
1689        }
1690
1691        if (self._childPriceId) {
1692          $("#" + self._priceId).find("#" + self._childPriceId).html(result.d.price);
1693        }
1694        else if (self._priceAreaId) {
1695          $("#" + self._priceId).html(result.d.price);
1696        }
1697      }
1698
1699
1700      if (self._itemNrId) {
1701        $("#" + self._itemNrId).html(self.htmlEscape(result.d.itemNr));
1702      }
1703      if (self._qtyDiscountsId) {
1704        $("#" + self._qtyDiscountsId).html(result.d.qtyPricing);
1705      }
1706      if (self._productStatusId) {
1707        $("#" + self._productStatusId).html(result.d.status);
1708      }
1709      if (self._productTimeFrameId) {
1710        $("#" + self._productTimeFrameId).html(result.d.timeFrame);
1711      }
1712      if (self._variantGTINId) {
1713        $("#" + self._variantGTINId).html(result.d.gtin);
1714      }
1715      if (self._variantAdditionalInfoId) {
1716        $("#" + self._variantAdditionalInfoId).html(result.d.additionalInfo);
1717      }
1718      if (self._qtyInStockId) {
1719        $("#" + self._qtyInStockId).html(result.d.inStockQty);
1720      }
1721      if (self._rewardPointsId) {
1722        $("#" + self._rewardPointsId).html(result.d.rewardPointsEarned);
1723      }
1724      if (self._rewardPointsToPurchaseId) {
1725        $("#" + self._rewardPointsToPurchaseId).html(result.d.rewardPointsToPurchase);
1726      }
1727      if (self._retailPriceId) {
1728        $('#' + self._retailPriceId).html(result.d.retailPrice);
1729      }
1730      if (self._priceDollarsId) {
1731        $('#' + self._priceDollarsId).html(result.d.priceDollars);
1732      }
1733      if (self._priceCentsId) {
1734        $('#' + self._priceCentsId).html(result.d.priceCents);
1735      }
1736      if (self._youSaveId) {
1737        $("#" + self._youSaveId).html(result.d.youSave);
1738      }
1739      if (self._weightId) {
1740        $("#" + self._weightId).html(result.d.weight);
1741      }
1742      if (self._availabilityId) {
1743        $("#" + self._availabilityId).html(result.d.availability);
1744      }
1745      if (self._lengthId) {
1746        $("#" + self._lengthId).html(result.d.itemLength);
1747      }
1748      if (self._widthId) {
1749        $("#" + self._widthId).html(result.d.itemWidth);
1750      }
1751      if (self._heightId) {
1752        $("#" + self._heightId).html(result.d.itemHeight);
1753      }
1754
1755      if (sOptions.length > 0) {
1756        var estimateLink = $("a.estimate-shipping");
1757        if (estimateLink.length != 0) {
1758          var estimateUrl = estimateLink.prop("href").replace(/(\?|&)variantIds=[^&]*/, "");
1759          estimateLink.prop("href", estimateUrl + ((estimateUrl.indexOf("?") >= 0) ? "&" : "?") + "variantIds=" + sOptions);
1760        }
1761
1762        var notifymelink = $("#lnkNotifyMe");
1763        if (notifymelink != null && notifymelink.length > 0) {
1764          if (result.d.ShowNotifyMe == 'TRUE') {
1765            var notifyurl = notifymelink.attr("data-href").replace(/(\?|&)variantIds=[^&]*/, "");
1766            if (notifyurl != "")
1767              notifymelink.attr("data-href", notifyurl + ((notifyurl.indexOf("?") >= 0) ? "&" : "?") + "variantIds=" + sOptions); //notifymelink.data("href", notifyurl + ((notifyurl.indexOf("?") >= 0) ? "&" : "?") + "variantIds=" + sOptions); //For Some reason, this was not working for foundation theme
1768
1769            notifymelink.show();
1770          }
1771          else {
1772            notifymelink.hide();
1773          }
1774        }
1775
1776        if (self._addToCartButtonId) {
1777          if (result.d.ShowAddToCart == 'TRUE')
1778            $("#" + self._addToCartButtonId).show();
1779          else
1780            $("#" + self._addToCartButtonId).hide();
1781        }
1782        if (self._addToQuoteButtonId) { //For the situation where add to Cart is not available, we shouldn't allow adding the item to quote as well.
1783          if (result.d.ShowAddToCart == 'TRUE')
1784            $("#" + self._addToQuoteButtonId).show();
1785          else
1786            $("#" + self._addToQuoteButtonId).hide();
1787        }
1788        if (result.d.variantInventoryImg != '') {
1789          var mainimg = document.getElementById(self._imageId);
1790          if (mainimg != null && mainimg.src != undefined && !mainimg.src.includes(result.d.variantInventoryImg)) {
1791            mainimg.src = self.getUpdatedImgUrl(mainimg.src, result.d.variantInventoryImg, self._productPhotoHandling, self._externalImageOverrideUrl);
1792
1793            var mainimgHref = document.getElementsByClassName("main-product-photo");
1794            if (mainimgHref != null && mainimgHref[0].href != undefined) {
1795              mainimgHref[0].href = self.getUpdatedImgUrl(mainimgHref[0].href, result.d.variantInventoryImg, self._productPhotoHandling, self._zoomOverrideUrl);
1796            }
1797            var mainimgzoom = document.getElementsByClassName("zoomImg");
1798            if (mainimgzoom != null && mainimgzoom.length > 0 && mainimgzoom[0].src != undefined) {
1799              mainimgzoom[0].src = self.getUpdatedImgUrl(mainimgzoom[0].src, result.d.variantInventoryImg, self._productPhotoHandling, self._zoomOverrideUrl);
1800            }
1801          }
1802        }
1803        else {
1804          if (self._useVariantInventory) {
1805            try {
1806              VariantSwatches.SelectVariant(self.selectedVariantGroup.toString(), self.selectedVariant.toString(), false, self._imageId, eval('VariantSwatches_' + self.selectedControlID));
1807            } catch (e) {
1808              console.log('error selecting main photo image');
1809            }
1810          }
1811        }
1812
1813        if (typeof affirm != 'undefined') {
1814          var affirmPromo = $(".affirm-as-low-as");
1815          if (affirmPromo != null && affirmPromo.length > 0) {
1816            affirmPromo.attr('data-amount', Math.round(resultPrice * 100));
1817            affirm.ui.refresh();
1818          }
1819        }
1820        if ($("div[data-pp-message]").length > 0) {
1821          $("div[data-pp-message]").attr('data-pp-amount', resultPrice);
1822        }
1823      }
1824
1825      if (localStorage.getItem('LatestCurrency')) {
1826        if (typeof triggerConvertPriceWithCurrencyCode === 'function') {
1827          triggerConvertPriceWithCurrencyCode();
1828        }
1829      }
1830    });
1831  },
1832
1833  updateVariants: function ($element) {
1834
1835    var self = this;
1836    var options = [];
1837    var elementID = $element.get(0).id;
1838
1839    if (this.indexes[elementID] == null) {
1840      this.updatePrice();
1841      return;
1842    }
1843
1844    var nextIndex = this.indexes[elementID] + 1;
1845
1846    var $sel = this.$varInvDDs.slice(0, nextIndex);
1847
1848    $sel.each(function () {
1849      if ($(this).is("select")) {
1850        options.push($(this).val());
1851
1852      } else if (self._isDDLSwatchCombined && $(this).is("div.variants-combo-main-container")) {
1853        var combinedDll = self.locateCombinedDDLObject($(this).prop("id"));
1854        if (combinedDll) {
1855          options.push(combinedDll.getSelectedValue());
1856        }
1857      } else {
1858        options.push($(this).find("input:checked").val());
1859      }
1860    });
1861    //debugger;
1862    //this is an input of type hidden - Generated in BuildLabel() method on server side in VariantGroupControlBuilder.cs class seems no issue for dropdown select
1863    var groupID = self.getGroupId(nextIndex);
1864
1865    if (typeof groupID === 'undefined') {
1866      this.updatePrice();
1867      return;
1868    }
1869    var $next = $(this.$varInvDDs.get(nextIndex));
1870
1871    if ($next.length == 0) {
1872      this.updatePrice();
1873      return;
1874    }
1875
1876
1877    var currentElementVal = "";
1878    var bFoundCombinedSelectElem = false;
1879    var ddlCombined = null;
1880    if (this._isDDLSwatchCombined && $element.is("div.variants-combo-main-container")) {
1881      //means its combined combo then first locate its object
1882      bFoundCombinedSelectElem = true;
1883      ddlCombined = this.locateCombinedDDLObject(elementID);
1884      if (ddlCombined) {
1885        currentElementVal = ddlCombined.getSelectedValue(); // gets its selected value
1886      }
1887    } else {
1888      currentElementVal = $element.val(); // otherwise take it as normal current element value
1889    }
1890
1891    //An elment can be a select or combined select or input type radio or input type checkbox
1892    if (currentElementVal === "-999" || (!$element.is("select") && !bFoundCombinedSelectElem && $element.find("input:checked").length == 0)) {
1893      this.setDefaults($element);
1894      this.updatePrice();
1895      return;
1896    }
1897
1898    var qty = this.getQuantity();
1899
1900    var itemID = this._itemId;
1901
1902    if (itemID == null || isNaN(itemID))
1903      itemID = 0;
1904
1905    if ($next.is("select")) {
1906      $next.prop("disabled", false);
1907    } else if (this._isDDLSwatchCombined && $next.is("div.variants-combo-main-container")) {
1908      var ddlnext = this.locateCombinedDDLObject($next.prop("id"));
1909      if (ddlnext) {
1910        ddlnext.enableMe();
1911      }
1912    }
1913
1914    var vids = options.join(', ');
1915    if (vids.length == 0)
1916      return;
1917
1918    var params = '{"variantIDs": [' + vids + '], "groupID": ' + groupID + ', "qty": ' + qty + ', "itemID":' + itemID + '}';
1919
1920    this.ajaxCall("GetApplicableVariants", params, function (result) {
1921      var results = JSON.parse(result.d);
1922      var variants = results.variants;
1923      var variantStockStatuses = results.variantStockStatuses;
1924      var variantModifierTexts = results.variantModifierTexts;
1925      var variantNames = results.variantNames;
1926
1927      var $selected;
1928      var ddlNextCombo = null;
1929
1930      if ($next.is("select") && !self._isDDLSwatchCombined) {
1931        self.handleNonCombinedSelect($next, groupID, variants, false, variantStockStatuses, variantModifierTexts, variantNames);
1932        $selected = $next;
1933      } else if (self._isDDLSwatchCombined && $next.is("div.variants-combo-main-container")) {
1934        ddlNextCombo = self.handleCombinedSelect($next, groupID, variants, variantStockStatuses, variantModifierTexts, variantNames);
1935        $selected = $next;
1936      } else {
1937        $selected = $next.find("input:checked");
1938        self.handleVariantControl($next, groupID, variants, variantStockStatuses);
1939      }
1940
1941      self.setDefaults($next);
1942      if (self._isDDLSwatchCombined && $selected.is("div.variants-combo-main-container")) {
1943        var selectedVal = ddlNextCombo.getSelectedValue();
1944        if (selectedVal === "-999") {
1945          self.updatePrice();
1946        }
1947      }
1948      else {
1949        var selectedVal = $selected.val();
1950
1951        if (selectedVal !== "-999") {
1952          //upate next available variant if pre selected a value
1953          self.updateVariants($next)
1954        }
1955        else {
1956          self.updatePrice(true);
1957        }
1958      }
1959    });
1960  },
1961
1962  getVariantsFromFitment: function (childIds) {
1963    var self = this;
1964
1965    this.ajaxCall("GetParentVariantsFromChildIds", '{ "childProducts": ' + JSON.stringify(childIds) + ', "quantity": ' + this.getQuantity() + ' }', function (result) {
1966      var variantOptions = JSON.parse(result.d);
1967
1968      self.$dd.each(function (index, selector) {
1969        var element = $(selector);
1970        var groupID = self.getGroupId(element);
1971        var options = variantOptions[groupID];
1972        var ddlNextCombo;
1973
1974        if (options == null)
1975          self.toggleGroup(groupID, false);
1976        else {
1977          if (element.is("select") && !self._isDDLSwatchCombined) {
1978            self.handleNonCombinedSelect(element, groupID, options, true);
1979          }
1980          else if (self._isDDLSwatchCombined && element.is("div.variants-combo-main-container")) {
1981            ddlNextCombo = self.handleCombinedSelect(element, groupID, options);
1982          }
1983          else {
1984            self.handleVariantControl(element, groupID, options);
1985          }
1986
1987          self.setDefaults(element);
1988
1989          self.toggleGroup(groupID, true);
1990        }
1991      });
1992    });
1993  },
1994
1995  setDefaults: function ($startElement) {
1996    var self = this;
1997    var selectedVal;
1998
1999    if (!this._isDDLSwatchCombined && $startElement.is("select")) {
2000      selectedVal = $startElement.val(); // regular ddl or select
2001
2002    } else if (this._isDDLSwatchCombined && $startElement.is("div.variants-combo-main-container")) {
2003      //means its combined combo then first locate its object
2004      var ddlCombined = this.locateCombinedDDLObject($startElement.get(0).id);
2005      if (ddlCombined) {
2006        selectedVal = ddlCombined.getSelectedValue(); // gets its selected value
2007      }
2008    }
2009    else {
2010      var $checked = $startElement.find("input:checked");
2011
2012      if ($checked.length > 0) {
2013        selectedVal = $checked.val();
2014      }
2015      else {
2016        selectedVal = "-999";
2017      }
2018    }
2019
2020    if (selectedVal === "-999") {
2021      var $nextElements = this.$varInvDDs ? this.$varInvDDs.slice(this.indexes[$startElement.get(0).id] + 1) : this.$dd.slice(this.indexes[$startElement.get(0).id] + 1);
2022      $nextElements.each(function () {
2023        if (!self._isDDLSwatchCombined && $(this).is("select")) {
2024          $(this).val("-999").prop("disabled", "disabled");
2025          var groupID = self.getGroupId($(this));
2026          self.updateVariantCustomFields(groupID, -999);
2027
2028        } else if (self._isDDLSwatchCombined && $(this).is("div.variants-combo-main-container")) {
2029          var combinedddl = self.locateCombinedDDLObject($(this).prop("id"));
2030          if (combinedddl) {
2031            combinedddl.setSelectedValue("-999", true);
2032            combinedddl.disableMe(); //just like prop disabled
2033          }
2034        }
2035        else {
2036          $(this).find("input").each(function () {
2037            $(this).prop("checked", false);
2038            if (this.value === "-999") {
2039              $(this).prop("checked", "checked");
2040            }
2041            else {
2042              $(this).prop("disabled", "disabled");
2043            }
2044            var groupID = self.getGroupId($(this));
2045            self.updateVariantCustomFields(groupID, this.value);
2046          });
2047        }
2048      });
2049    }
2050  },
2051
2052  handleNonCombinedSelect: function (element, groupID, variants, dontDisplaySwatches = false, variantStockStatuses = null, variantModifierTexts = null, variantNames = null) {
2053    var previousVal = element.val();
2054    var customID = this._customId;
2055    element.children("option[value!='-999']").each(function () {
2056      // ZB 1-28-2015: Disable swatches for variants that aren't compatible with the currently selected parent variant
2057      var variantId = $(this).prop('value');
2058      var $swatches = $("img[id^='varswatch_" + groupID + "_" + variantId + "_']");
2059      if (dontDisplaySwatches)
2060        $swatches.parent().hide();
2061      else
2062        $swatches.addClass("SwatchNotApplicable");
2063      $(this).remove();
2064    });
2065
2066    $.each(variants, function (key, value) {
2067      //add applied variants in sort order. the leading space is to stop json resort variants by key value
2068      var variantId = key.trim();
2069      var $swatches = $("img[id^='varswatch_" + groupID + "_" + variantId + "']");
2070      var button = $("div[id^='varbutton_" + groupID + "_" + variantId + "']");
2071      var variantName = value;
2072      if (button.length > 0 && variantNames !== null && variantModifierTexts !== null) { 
2073        button.html("<span class='desc-text'>" + variantNames[key] + "</span><span class='modifier-text'>" + variantModifierTexts[key] + "</span>");
2074        variantName = variantNames[key];
2075      }
2076      element.append($("<option>", { value: variantId, varname: variantName }).text(value));
2077      if (dontDisplaySwatches)
2078        $swatches.parent().show();
2079      else
2080        $swatches.removeClass("SwatchNotApplicable");
2081      if (previousVal == variantId && variantStockStatuses !== null)
2082        if (variantStockStatuses[key] == "0") {
2083          previousVal = "";
2084          let errorDv = $('.variant-custom-error[groupname=' + customID + '_' + element[0].getAttribute("groupname") + ']');
2085          if (errorDv && errorDv.length > 0 && errorDv[0].hasAttribute('data-auto-select')) {
2086            errorDv.html('Profile option is unavailable.');
2087            errorDv[0].setAttribute('data-error', 'status-unavailable');
2088          }
2089        }
2090    });
2091
2092    //keep previous selection selected if it is still available
2093    element.children("option[value!='-999']").each(function () {
2094        if (previousVal == $(this).prop('value')) 
2095          $(this).prop('selected', true);
2096    });
2097    VariantButtons.UpdateButtons(groupID, element.val());
2098    VariantButtons.HideButtons(groupID, variants);
2099    VariantSwatches.HideSwatches(groupID);
2100  },
2101  handleCombinedSelect: function (element, groupID, variants, variantStockStatuses = null, variantModifierTexts = null, variantNames = null) {
2102    var ddlNextCombo = this.locateCombinedDDLObject(element.prop("id"));
2103    if (ddlNextCombo) {
2104      ddlNextCombo.reconfigureComboOptions(variants, variantStockStatuses, variantModifierTexts, variantNames);
2105    }
2106    return ddlNextCombo;
2107  },
2108  handleVariantControl: function (element, groupID, variants) {
2109    var lookup = {};
2110
2111    $.each(variants, function (key, value) {
2112      lookup[key.trim()] = value;
2113    });
2114
2115    element.find("input").each(function () {
2116      if (this.value !== "-999" && !lookup[this.value]) {
2117        $(this).prop("checked", false);
2118        $(this).prop("disabled", "disabled");
2119      }
2120      else {
2121        $(this).removeAttr("disabled");
2122        var variantLabel = lookup[this.value];
2123        if (variantLabel) {
2124          $("label[for='" + this.id + "']").text(variantLabel);
2125        }
2126      }
2127    });
2128  },
2129
2130  ///Get group id of the variant
2131  getGroupId: function (index) {
2132    if (index instanceof Element || index instanceof HTMLDocument)
2133      index = index.id;
2134    else if (index instanceof jQuery)
2135      index = index.attr("id");
2136
2137    //20220311 AG If index is a string, its an element id
2138    if (typeof index === "string") {
2139      return index.split("_").pop();
2140    }
2141
2142    return $("#variantGroupID" + this._customId + "_" + (index)).val();
2143  },
2144
2145  ///Toggle groupname, input, and swatches
2146  toggleGroup: function (groupID, toggle) {
2147    var variantControl = $("[id$='variantGroup" + this._customId + "_" + groupID + "']");
2148    var checkBoxVariantControl = $("[id$='VariantGroup" + this._customId + "_" + groupID + "']");
2149
2150    //toggle group name
2151    $("[id^='variantGroupID" + this._customId + "'][value='" + groupID + "']").parent().toggle(toggle);
2152    //toggle variant control
2153    variantControl.toggle(toggle);
2154    checkBoxVariantControl.toggle(toggle);
2155    //toggle swatches
2156    $("[id^='varswatch_" + groupID + "']").closest(".ProductDetailsSwatches").toggle(toggle);
2157
2158    if (toggle)
2159      variantControl.removeAttr('disabled');
2160  }
2161};
2162
2163//----------------------------- // Helpers Related To Combined DDL with Swatch, Mainly ship with  --------////
2164function isScrollable(element) {
2165  return element && element.clientHeight < element.scrollHeight;
2166}
2167
2168
2169// ensure given child element is within the parent's visible scroll area
2170function maintainScrollVisibility(activeElement, scrollParent) {
2171  const { offsetHeight, offsetTop } = activeElement;
2172  const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;
2173
2174  const isAbove = offsetTop < scrollTop;
2175  const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;
2176
2177  if (isAbove) {
2178    scrollParent.scrollTo(0, offsetTop);
2179  } else if (isBelow) {
2180    scrollParent.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight);
2181  }
2182}
2183
2184VariantSwatches = {
2185  SetResizedImageLinks: function (img, zoom, swatchUrl, variantSwatch) {
2186    var newMainImageUrl = img.attr("src");
2187    var newScaledUpImageUrl = "";
2188    var zoomWidth = variantSwatch.ZoomWidth;
2189    var zoomHeight = variantSwatch.ZoomHeight;
2190    var ImagingMode = variantSwatch.ImagingMode;
2191    var ProductPhotoOverride = variantSwatch.ProductPhotoOverride;
2192    var ZoomPhotoOverride = variantSwatch.ZoomPhotoOverride;
2193    if (ImagingMode == "ExternalImaging") {
2194      var oldMainImageOptions = window.resizehelper.getExternalImageOptionsFromUrl(ProductPhotoOverride, img.attr("src"));
2195      newMainImageUrl = window.resizehelper.getExternalImageUrl(ProductPhotoOverride, swatchUrl, oldMainImageOptions.width, oldMainImageOptions.height);
2196      newScaledUpImageUrl = window.resizehelper.getExternalImageUrl(ZoomPhotoOverride, swatchUrl, zoomWidth, zoomHe
2196ight);
2197    } else {
2198      var baseResizerPath = window.resizehelper.getBaseResizerPath(swatchUrl);
2199      var oldParams = "";
2200      if (baseResizerPath.indexOf('?') > -1) {
2201        oldParams = newMainImageUrl.substring(newMainImageUrl.indexOf('?') + 1);
2202        var poStartIndex = oldParams.indexOf("po=");
2203        if (poStartIndex < 0)
2204          poStartIndex = oldParams.indexOf("path=");
2205        if (poStartIndex > -1) {
2206          var ampAfterIndex = oldParams.substring(poStartIndex).indexOf("&");
2207          if (ampAfterIndex > -1)
2208            oldParams = oldParams.substring(poStartIndex + ampAfterIndex + 1);
2209        }
2210      }
2211      newMainImageUrl = img.attr("src").replace(/\/resize\/.+(\?.*)/, baseResizerPath + oldParams);
2212      newScaledUpImageUrl = baseResizerPath + "bw=" + zoomWidth + "&w=" + zoomWidth + "&bh=" + zoomHeight + "&h=" + zoomHeight
2213    }
2214    img.attr("src", newMainImageUrl);
2215    img.siblings("img").attr("src", newScaledUpImageUrl);
2216    if (img.attr("id").indexOf("lvCategory") == -1) {
2217      zoom.attr("href", newScaledUpImageUrl);
2218    }
2219  },
2220
2221  SelectVariant: function (groupID, variantID, setDropDown, imageId, variantSwatch) {
2222    var mainPhotoPresent = false;
2223    if (imageId !== "") {
2224      var $img = $("#" + imageId);
2225      if ($img.length > 0)
2226        mainPhotoPresent = true;
2227    }
2228    $(".varpicmax_img[id^='varswatch_" + groupID + "_" + "']").removeClass("ProductDetailsSelectedVariant");
2229    var o = variantSwatch.SwatchArray[variantID];
2230    if (o) {
2231      if (mainPhotoPresent) {
2232        $zoomlink = $img.parent();
2233        if (o.SwatchURL != "") {
2234          if (variantSwatch.ImagingMode == "ExternalImaging") {
2235            this.SetResizedImageLinks($img, $zoomlink, o.SwatchURL, variantSwatch);
2236          } else {
2237            if ($img.attr("src").indexOf("path=") != -1) {
2238              if ($img.attr("src").indexOf("&") != -1) {
2239                $img.attr("src", $img.attr("src").replace(new RegExp("path=.+?&"), "path=" + o.SwatchURL + "&")).attr("alt", "").attr("title", "");
2240                $img.siblings("img").attr("src", o.SwatchURL);
2241                if ($img.attr("id").indexOf("lvCategory") == -1) {
2242                  $zoomlink
2243                    .attr("href", $zoomlink.attr("href").replace(new RegExp("path=.+?&"), "path=" + o.SwatchURL + "&"));
2244                }
2245              } else {
2246                $img.attr("src", $img.attr("src").replace(new RegExp("path=.+"), "path=" + o.SwatchURL)).attr("alt", "").attr("title", "");
2247                if ($img.attr("id").indexOf("lvCategory") == -1) {
2248                  $zoomlink
2249                    .attr("href", $zoomlink.attr("href").replace(new RegExp("path=.+"), "path=" + o.SwatchURL));
2250                }
2251              }
2252            } else if ($img.attr("src").indexOf("/resize/") != -1) {
2253              this.SetResizedImageLinks($img, $zoomlink, o.SwatchURL, variantSwatch);
2254            } else {
2255              $img.attr("src", o.SwatchURL).attr("alt", "").attr("title", "");
2256              $img.siblings("img").attr("src", o.SwatchURL);
2257              if ($img.attr("id").indexOf("lvCategory") == -1) {
2258                $zoomlink.attr("href", o.SwatchURL);
2259              }
2260            }
2261          }
2262        } else {
2263          var groupVars = [];
2264          var hasSwatch = false;
2265          $("#" + o.ControlPath).children().each(function () {
2266            var v = variantSwatch.SwatchArray[$(this).val()];
2267            if (v && v.SwatchURL !== "") {
2268              hasSwatch = true;
2269            }
2270          });
2271          if (typeof ResetImage == 'function' && hasSwatch)
2272            ResetImage();
2273        }
2274      } else if (typeof ResetImage == 'function')
2275        ResetImage();
2276      if (setDropDown) {
2277        //for radio options only
2278        var count = $("[id$='" + o.ControlPath + "']").find("tr").length;
2279        for (let i = 0; i < count; i++) {
2280          if ($("[id$='" + o.ControlPath + "_" + i + "']").val() == variantID) {
2281            $("[id$='" + o.ControlPath + "_" + i + "']").prop("checked", true);
2282          }
2283          else {
2284            $("[id$='" + o.ControlPath + "_" + i + "']").prop("checked", false);
2285          }
2286        }
2287        //end of radio options only
2288        $("[id$='" + o.ControlPath + "']").val(variantID).change();
2289      }
2290    }
2291    $(".varpicmax_img[id^='varswatch_" + groupID + "_" + variantID + "_" + "']").addClass("ProductDetailsSelectedVariant");
2292  },
2293
2294  HideSwatches: function (groupID) {
2295    var swatches = $("[id^='varswatch_" + groupID + "']");
2296    for (var i = 0; i < swatches.length; i++) {
2297      if (swatches[i].classList.contains("SwatchNotApplicable")) {
2298        swatches[i].style.display = "none";
2299      }
2300      else {
2301        swatches[i].style.display = null;
2302      }
2303    }
2304  }
2305}
2306
2307VariantButtons = {
2308  SelectVariant: function (groupID, variantID, setDropDown, variantButtons, isCombined) {
2309    var o = variantButtons.ButtonArray[variantID];
2310    VariantButtons.UpdateButtons(groupID, variantID);
2311    if (o) {
2312      if (setDropDown) {
2313        if (isCombined) {
2314          $("[id$='combo-option-Id-" + variantID + "']").click()
2315        }
2316        else
2317          $("[id$='" + o.ControlPath + "']").val(variantID).change();
2318      }
2319    }
2320  },
2321
2322  UpdateButtons: function (groupID, variantID) {
2323    var buttons = $('.var-button[groupID=' + groupID + ']');
2324    for (var i = 0; i < buttons.length; i++) {
2325      if (buttons[i].getAttribute("variantID") !== variantID)
2326        buttons[i].classList.remove('var-selected');
2327      else
2328        buttons[i].classList.add('var-selected');
2329    }
2330  },
2331
2332  HideButtons: function (groupID, variants) {
2333    var buttons = $('.var-button[groupID=' + groupID + ']');
2334    for (var i = 0; i < buttons.length; i++) {
2335      var isVisible = variants[" " + buttons[i].getAttribute("variantID")];
2336      if (!isVisible) {
2337        buttons[i].style.display = "none";
2338        buttons[i].classList.add('var-unavailable');
2339      }
2340      else {
2341        buttons[i].style.display = null;
2342        buttons[i].classList.remove('var-unavailable');
2343      }
2344    }
2345  }
2346}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.