PageSourceSearch

https://www.hollisterco.com/hol/eaeda019/js/productV2.js

js hollisterco.com collected 2026-09-24 09:19:55 UTC 557,133 bytes, 13,304 lines download raw bytes

1redesign.define('productPartial/pdp_productThumbnailButton',['handlebars','dsPartial/thumbnail'], function(Handlebars) {
2
3this["ANF"] = this["ANF"] || {};
4this["ANF"]["templates"] = this["ANF"]["templates"] || {};
5
6Handlebars.registerPartial("pdp_productThumbnailButton", this["ANF"]["templates"]["pdp_productThumbnailButton"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
7    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
8
9  return "        <button class=\"product-thumbnail-button\" tabindex=\"-1\" data-image-type=\""
10    + alias2(alias1((depth0 != null ? depth0.imageType : depth0), depth0))
11    + "\" data-image-id=\""
12    + alias2(alias1((depth0 != null ? depth0.imageId : depth0), depth0))
13    + "\">\n"
14    + ((stack1 = container.invokePartial(partials.thumbnail,depth0,{"name":"thumbnail","hash":{"selectedText":"Selected","selected":(depth0 != null ? depth0.selected : depth0),"alt":(depth0 != null ? depth0.alt : depth0),"data-src":(depth0 != null ? depth0["data-src"] : depth0)},"data":data,"indent":"            ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
15    + "        </button>\n";
16},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
17    var stack1;
18
19  return "<div class=\"product-thumbnails slider js-slider js-thumbnails thumbnail-slider\" style=\"display:none;\">\n"
20    + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.thumbnails : depth0),{"name":"each","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
21    + "</div>";
22},"usePartial":true,"useData":true}));
23
24return this["ANF"];
25
26});
27/*
28*	Usage
29*		To get individual segments
30*			segment = xSeg.get(xSeg.XSEG_GLOBAL);
31*
32*		To check if the segment's page is a value
33* 			var isInPageTest = xSeg.checkPageSegment(xSeg.XSEG_GLOBAL, "A");
34*
35*		To check if the segment's module is a value
36* 			var isInModuleTest = xSeg.checkModuleSegment(xSeg.XSEG_GLOBAL, "1");
37*/
38redesign.define('coreServices/xSeg',['anfUtil/testFramework', 'jsCookie'], function (test, cookies) {
39  'use strict';
40
41  var partRegex = new RegExp(/([a-zA-Z]+)=([a-zA-Z]+)-(\d+)/);
42  var nullValue = Object.create(Object.prototype,  {
43    'page': {
44      value: null,
45      writable: false
46    },
47    'module': {
48      value: null,
49      writable: false
50    }
51  });
52  var constants = [
53    {
54      name: 'XSEG_BAG',
55      value: 'b'
56    },
57    {
58      name: 'XSEG_CATALOG',
59      value: 'c'
60    },
61    {
62      name: 'XSEG_CHECKOUT',
63      value: 'co'
64    },
65    {
66      name: 'XSEG_CUSTOMER_SERVICE',
67      value: 'cs'
68    },
69    {
70      name: 'XSEG_GLOBAL',
71      value: 'g'
72    },
73    {
74      name: 'XSEG_HOMEPAGE',
75      value: 'h'
76    },
77    {
78      name: 'XSEG_PRODUCT',
79      value: 'p'
80    },
81    {
82      name: 'XSEG_SEARCH',
83      value: 's'
84    },
85    {
86      name: 'XSEG_SORT_RULE_MANAGER',
87      value: 'sq'
88    }
89  ];
90  var module = {
91    /*
92    * @description get the specific segment of the xSeg cookie
93    * @param {string} segment the part of the xSeg cookie you are trying to get
94    * @return {object} a standard object that contains the page and module portions of the segment, if segment was not found these values will be null
95    */
96    get: function (segment) {
97      var returnValue = nullValue;
98
99      if (test.object.containsKey(this.xSeg, segment, false)) {
100        returnValue = this.xSeg[segment];
101      }
102      return returnValue;
103    },
104    /*
105    * @description check if the page part of the segment equals the value supplied
106    * @param {string} segment : the part of the xSeg cookie you are trying to get
107    * @param {string} value : the value to be evaluated against the segment's page value
108    * @return {boolean} if the value is the same as the segment's page value
109    */
110    checkPageSegment: function (segment, value) {
111      var segmentValue = this.get(segment);
112      return (segmentValue.page === value);
113    },
114    /*
115    * @description check if the module part of the segment equals the value supplied
116    * @param {string} segment : the part of the xSeg cookie you are trying to get
117    * @param {string} value : the value to be evaluated against the segment's module value
118    * @return {boolean} if the value is the same as the segment's module value
119    */
120    checkModuleSegment: function (segment, value) {
121      var segmentValue = this.get(segment);
122      return (segmentValue.module === value);
123    }
124  };
125
126  /* Start Section For processing the xSegValue */
127
128  /*
129  * @description Private method to break down the x=y-0 parts of the xSeg value
130  * @param {string} part : the individual segments from the xSeg cookie
131  * @return {object}
131 the processed object containing the key, page, and module
132  */
133  function processPart(part) {
134    var returnValue = {
135      key: null,
136      page: null,
137      module: null
138    };
139
140    var partBreakDown = partRegex.exec(part);
141
142    try {
143      returnValue.key = partBreakDown[1];
144      returnValue.page = partBreakDown[2];
145      returnValue.module = partBreakDown[3];
146    } catch (e) {
147      // Do nothing on failure
148    }
149
150    return returnValue;
151  }
152
153  /*
154  * @description Private method to add a processed part to the rest of the segments object
155  * @param {object} segmentGroups : the object that holds the segments
156  * @param {object} segment : the segment being added to the segments.  should contain a key, page, and module value.
157  * @return {object} the segmentGroups with the added segment
158  */
159  function combineProcessedParts(segmentGroups, segment) {
160    if (
161      test.string.not.empty(segment.key, false) &&
162      test.string.not.empty(segment.page, false) &&
163      test.string.not.empty(segment.module, false)
164    ) {
165      var segmentDescription = Object.create(Object.prototype,  {
166        'page': {
167          value: segment.page,
168          writable: false
169        },
170        'module': {
171          value: segment.module,
172          writable: false
173        }
174      });
175
176      Object.defineProperty(segmentGroups, segment.key, {
177        value: segmentDescription,
178        writable: false
179      });
180    }
181
182    return segmentGroups;
183  }
184
185  Object.defineProperty(module, 'xSeg', {
186    configurable: false,
187    enumerable: false,
188    get: function () {
189      var cookie = cookies.get('xSeg');
190      var returnValue = {};
191      if (test.string.not.empty(cookie, false) && test.string.not.equalsIgnoreCase(cookie, 'null', false)) {
192        returnValue = cookie.split('&')
193          .map(processPart)
194          .reduce(combineProcessedParts, {});
195      }
196      return returnValue;
197    }
198  });
199  /* End Section For processing the xSegValue */
200
201  /* Start Section For setting up CONSTANTS */
202  constants.forEach(function (constant) {
203    Object.defineProperty(module, constant.name, {
204      value: constant.value,
205      writable: false,
206      enumerable: false
207    });
208  });
209  /* End Section For setting up CONSTANTS */
210
211  return module;
212});
213
214redesign.define('productModules/helpers/Utils',[
215  'coreServices/xSeg'
216], function defineUtils(
217  xSeg
218) {
219  'use strict';
220
221  var instance = null;
222
223  function Utils() {
224    if (instance !== null) {
225      throw new Error('Cannot instantiate more than one Utils, use Utils.getInstance()');
226    }
227
228    this.initialize();
229  }
230
231  Utils.prototype = {
232    initialize: function init() {
233      // Initializes the singleton.
234    },
235
236    urlSearchParams: new URLSearchParams(window.location.search),
237
238    /**
239    * Detect if user is coming to PDP from an internal source
240    * e.g. category page or not google!
241    */
242
243    isInternalBrowsingCustomer: function isInternalBrowsingCustomer(document) {
244      var documentReferrer = document.referrer.toLowerCase();
245      return documentReferrer.indexOf('abercrombie') !== -1 || documentReferrer.indexOf('hollisterco') !== -1;
246    },
247
248    /**
249		 * Detect if quickview is opened
250		 */
251    get isQuickviewOpened() {
252      return $('.product-quickview__modal[data-open="true"]').length > 0;
253    },
254
255    get isPdpPage() {
256      return $('body').is('.product-page-v2');
257    },
258
259    /**
260		 * Detect if exchange quickview is opened
261		 */
262    get isQuickviewExchangesOpened() {
263      return $('.exchanges-quickview__modal[data-open="true"]').length > 0;
264    },
265
266    isKidsProduct: function isKidsProduct($productSection) {
267      return $productSection.hasClass('is-kids-product');
268    },
269
270    getProductBrand: function getProductBrand(productId) {
271      return this.getProductData(productId).productAttrs.brand;
272    },
273
274    /**
275		 * Return the correct product section based on productID
276		 * @param {String} productID The Product ID
277		 * @return {Object} the jquery object of the correct product section
278		 */
279    getProductSection: function getProductSection() {
280      var productSelectorString = '.product-page-v2-modules';
281      return this.isQuickviewOpened ? $('.product-quickview__modal[data-open="true"]').find(productSelectorString) : $(productSelectorString);
282    },
283
284    baseGet: function baseGet(object, path) {
285      var pathArr = path.split('.');
286      var index = 0;
287      var length = pathArr.length;
288      var tempObj = object;
289
290      while (tempObj !== null && typeof tempObj !== 'undefined' && index < length) {
291        tempObj = tempObj[pathArr[index++]] || null;
292      }
293      return index && index === length ? tempObj : null;
294    },
295
296    /**
297		 * Gets the value at `path` of `object`. If the resolved value is
298		 * `undefined`, the `defaultValue` is returned in its place.
299		 *
300		 * @param {Object} object The object to query.
301		 * @param {string} path The path of the property to get.
302		 * @param {*} [defaultValue] The value returned for `undefined` resolved values.
303		 * @returns {*} Returns the resolved value.
304		 * @example
305		 *
306		 * var object = { 'a': { 'b': { 'c': 3 } } };
307		 *
308		 * Utils.getValueFromObject(object, 'a.b.c');
309		 * // => 3
310		 *
311		 * Utils.getValueFromObject(object, 'a.b.c.d', 'default');
312		 * // => 'default'
313		 */
314    getValueFromObject: function getValueFromObject(object, path, defaultValue) {
315      var result = object === null || object === typeof 'undefined' ? null : this.baseGet(object, path);
316      return typeof result === 'undefined' || result === null ? defaultValue : result;
317    },
318
319    getParentProductSection: function getParentProductSection($child) {
320      return $child.parents('.product-page-v2-modules');
321    },
322
323    getANFObject: function getANFObject() {
324      return ANF;
325    },
326
327    getProductData: function getProductData(productId) {
328      return productCatalog[productId] || {};
329    },
330
331    /**
332     * @description Return an object with modelHeight and modelSize based on the selectedModel
333     * @param {String} productId product id
334     * @return {modelSpecs} return modelHeight and modelSize
335     */
336    getModelSpecs: function getModelSpecs(productId) {
337      var productData = this.getProductData(productId);
338      var defaultModelStr = window.selectedModelSegment || this.getValueFromObject(productData, 'productAttrs.ModelData.defaultModel', null);
339      var selectedModel = defaultModelStr && productData.productAttrs.ModelData ? productData.productAttrs.ModelData[defaultModelStr] : null;
340
341      var modelHeight = selectedModel ? selectedModel.height : this.getValueFromObject(productData, 'productAttrs.OFPModelHeight', '');
342      var modelSize = selectedModel ? selectedModel.size : this.getValueFromObject(productData, 'productAttrs.OFPModelSize', '');
343
344      return {
345        modelHeight: modelHeight,
346        modelSize: modelSize
347      };
348    },
349
350    hasFinalSaleEnabled: function hasFinalSaleEnabled() {
351      return window.digitalData.get('flag.has-pdp-final-sale', false);
352    },
353
354    getProductDepartmentId: function getProductDepartmentId(productId) {
355      return this.getProductData(productId).kicId.split('_')[1].split('-')[0];
356    },
357
358    getProductKicId: function getProductKicId(productId) {
359      return this.getProductData(productId).kicId;
360    },
361
362    isJeansProduct: function isJeansProduct(productId) {
363      var jeansDepartmentIds = this.getANFObject().params.storeAttributes.jeansDepartmentIds.split(',');
364      var productDepartmentId = this.getProductDepartmentId(productId);
365      return  jeansDepartmentIds.includes(productDepartmentId);
366    },
367
368    productHasEarlyAccessIndicator: function productHasEarlyAccessIndicator(productId) {
369      var earlyAccessIndicator = this.getValueFromObject(this.getProductData(productId).productAttrs, 'EarlyAccessIndicator', '');
370      return earlyAccessIndicator.toString().toLowerCase() === 'true';
371    },
372
373    hasProductMFEEnabled: function hasProductMFEEnabled() {
374      var hasProductMFEEnabledStoreAttr = this.getANFObject().params.storeAttributes.catalogV2.hasProductMFEEnabled;
375      var hasProductMFEEnabledParam = this.urlSearchParams.get('hasProductMFEEnabled');
376      var isDevEnv = this.getANFObject().params.env.name === 'DEV';
377
378      return hasProductMFEEnabledStoreAttr || (hasProductMFEEnabledParam && isDevEnv);
379    },
380
381    hasPDPMFEBelowTheFold: function hasPDPMFEBelowTheFold() {
382      return this.getANFObject().params.storeAttributes.catalogV2.hasPDPMFEBelowTheFold;
383    },
384
385    isExternalUser: function isExternalUser() {
386      var paramNames = ['cmp', 'source', 'utm_source'];
387      var isExternalVisitor = false;
388      var pdpExternalVisitorEnabledCheck = ANF.params.storeAttributes.catalogV2.hasPDPExternalVisitorEnabled && xSeg.checkPageSegment(xSeg.XSEG_PRODUCT, 'CT');
389
390      for (var i = 0; i < paramNames.length; i++) {
391        if (new URLSearchParams(window.location.search).has(paramNames[i])) {
392          isExternalVisitor = true;
393        }
394      }
395      return pdpExternalVisitorEnabledCheck && isExternalVisitor;
396    },
397
398    hasQuickviewMfeEnabled: function hasQuickviewMfeEnabled() {
399      var hasQuickviewMfeEnabledStoreAttr = this.getANFObject().params.storeAttributes.catalogV2.hasQuickviewMfeEnabled;
400      var hasQuickviewMfeEnabledParam = this.urlSearchParams.get('hasQuickviewMFEEnabled');
401      var isDevEnv = this.getANFObject().params.env.name === 'DEV';
402
403      return hasQuickviewMfeEnabledStoreAttr || (hasQuickviewMfeEnabledParam && isDevEnv);
404    },
405
406    isEyewearProduct: function isEyewearProduct(productAttrsData) {
407      var hasEyewearEnabled = this.getANFObject().params.storeAttributes.catalogV2.hasEyewearEnabled;
408      return !!(hasEyewearEnabled && productAttrsData && (
409        productAttrsData.EyewearDimensionLensWidth ||
410        productAttrsData.EyewearDimensionBridgeWidth ||
411        productAttrsData.EyewearDimensionArmLength
412      ));
413    }
414  };
415
416  Utils.getInstance = function getInstance() {
417    // Gets an instance of the singleton.
418    if (instance === null) {
419      instance = new Utils();
420    }
421    return instance;
422  };
423
424  return Utils.getInstance();
425});
426
427redesign.define('productModules/helpers/imageLoadHelper',['coreClass/ANFImage'],
428  function imageLoadHelper(ANFImage) {
429    'use strict';
430
431    function removeBrokenImageFromArray($productSection, failedImageId) {
432      var imageProcessedArray = publicMembers.getProcessedImageArray($productSection);
433
434      return imageProcessedArray.filter(function removeBrokenImageId(item) {
435        return failedImageId !== item.id;
436      });
437    }
438
439    function removeBrokenImageFromImageObject($productSection, failedImageId, imageType) {
440      var imageDataModel = publicMembers.getImageDataModel($productSection);
441      var imageSetType = imageType;
442
443      if (imageType === 'product') {
444        imageSetType = 'prod';
445      } else if (imageType === 'lifestyle') {
446        imageSetType = 'life';
447      } else if (imageType === 'user') { // ugc images alt text is "user generated #"
448        imageSetType = 'ugc';
449      }
450
451      imageDataModel[imageSetType] = imageDataModel[imageSetType].filter(function removeBrokenImageFromObjectArray(item) {
452        return failedImageId !== item.id;
453      });
454
455      return imageDataModel;
456    }
457
458    var publicMembers = {
459      removeFailedImage: function reomoveFailedImage(failedImageElement, $productSection, imageType, imageId) {
460        var $brokenImage = $(failedImageElement);
461
462        var newImageProcessedArray = removeBrokenImageFromArray($productSection, imageId);
463        var newImageDataModel = removeBrokenImageFromImageObject($productSection, imageId, imageType);
464
465
466        return {
467          imageArray: newImageProcessedArray,
468          imageObject: newImageDataModel,
469          $brokenImage: $brokenImage
470        };
471      },
472      storeImageData: function storeImageData($productSection, processedImageArray, imageDataModel) {
473        $productSection.data('processedImageArray', processedImageArray);
474        $productSection.data('imageDataModel', imageDataModel);
475      },
476      getProcessedImageArray: function getProcessedImageArray($productSection) {
477        return  $productSection.data('processedImageArray');
478      },
479      getImageDataModel: function getImageDataModel($productSection) {
480        return  $productSection.data('imageDataModel');
481      },
482
483      loadImages: function loadImages(images, successCallback, failCallback) {
484        // The object that will be returned in the callback
485        var log = {
486          success: [],
487          error: [],
488          totalImageCount: images.length
489        };
490
491        // Executed everytime an img is successfully or wrongly loaded
492        var verifier = function verifier() {
493          /* total count should be successful loads + error loads.
494            But we dont want to call success if all images failed.
495            inifite slider setup loop caused EPIC-9359 */
496          if (log.success.length + log.error.length === log.totalImageCount && log.error.length !== log.totalImageCount) {
497            successCallback.call(null, log);
498          }
499        };
500
501        // Loop through all the images URLs
502        for (var index = 0; index < images.length; index++) {
503          // Prevent that index has the same value by wrapping it inside an anonymous fn
504          (function setListeners(i) {
505            // Image path providen in the array e.g image.png
506            var el = images[i];
507            var src = el.getAttribute('data-src');
508            var img = new Image();
509
510            img.addEventListener('load', function load() {
511              if (!!el.parent) {
512                el.parent.replaceChild(img, el);
513              } else {
514                el.src = src;
515              }
516              log.success.push(el);
517              verifier();
518            }, false);
519
520            img.addEventListener('error', function error() {
521              log.failedImageElement = el;
522              log.error.push(el);
523              failCallback.call(null, log);
524              verifier();
525            }, false);
526
527            img.src = src;
528          })(index);
529        }
530      },
531
532      getProd1ImageId: function getProd1ImageId(imageSets) {
533        var imageId;
534        if (imageSets && imageSets.prod.length > 0) {
535          imageId = imageSets.prod[0].imageId;
536        } else {
537          imageId = this.getNoImageAvailableAssetImageId();
538        }
539
540        return imageId;
541      },
542
543      getNoImageAvailableAssetUrl: function getNoImageAvailableAssetUrl() {
544        var id = this.getNoImageAvailableAssetImageId();
545
546        return ANFImage.instance()
547          .setImageName(id)
548          .setSizePresetEnabled(false)
549          .url;
550      },
551
552      getNoImageAvailableAssetImageId: function getNoImageAvailableAssetImageId() {
553        var currentBrand = $('header').attr('data-brand');
554        var brandFlag;
555
556        switch (currentBrand) {
557          case 'anf':
558            brandFlag = 1;
559            break;
560          case 'kids':
561            brandFlag = 2;
562            break;
563          default:
564            brandFlag = 3;
565            break;
566        }
567
568        return 'KIC_' + brandFlag + 'XX-XXXX-XXXX-XXX';
569      }
570    };
571
572    return publicMembers;
573  }
574);
575
576redesign.define('productModules/product/productThumbnails',[
577  'anfcore/components/slider',
578  'productPartial/pdp_productThumbnailButton',
579  'productModules/helpers/Utils',
580  'coreClass/ANFImage',
581  'productModules/helpers/imageLoadHelper'
582], function ProductThumbnails(
583  dsSlider,
584  productPartialPdpProductThumbnailButton,
585  Utils,
586  ANFImage,
587  imageLoadHelper
588) {
589  'use strict';
590
591  var thumbnailContainerSelectorClass = '.product-thumbnails__container .product-thumbnails';
592  var productThumbnailWrapperSelectorClass = '.product-thumbnails__container';
593  var productMainImagesWrapperSelectorClass = '.product-main-images__wrapper';
594  var productMainImagesSelectorClass = '.product-main-images';
595  var thumbnailInnerWrapperSelectorClass = '.thumbnail-inner-wrapper';
596  var thumbnailButtonSelectorClass = '.product-thumbnail-button';
597
598  var messageBus = $(ANF);
599  var $newThumbnailsContainer;
600  var $oldThumbnailsContainer;
601
602  function onSwatchChanged(e, data) {
603    var $productSection = data.$productSection;
604    var processedImageArray = data.processedImageArray;
605    $oldThumbnailsContainer = $productSection.find(thumbnailContainerSelectorClass).first();
606    removeHalfLoadingThumbnails();
607
608    imageLoadHelper.storeImageData($productSection, processedImageArray, data.imageDataModel);
609
610    if (processedImageArray.length > 1) {
611      // convert data to html and insert add it to .product-thumbnails__container
612      var thumbnailsData = getThumbnailsData(processedImageArray);
613      var thumbnailsHtml = productPartialPdpProductThumbnailButton.templates.pdp_productThumbnailButton({thumbnails: thumbnailsData});
614      $newThumbnailsContainer = $(thumbnailsHtml)
615        .appendTo($productSection.find(productThumbnailWrapperSelectorClass));
616      // load thumbnails images
617      var $images = $newThumbnailsContainer.find('img');
618      imageLoadHelper.loadImages($images, onThumbnailsImagesLoaded, onThumbnailLoadFailure);
619    } else {
620      removeOldThumbnails($oldThumbnailsContainer);
621      messageBus.trigger('thumbnailSlider:InitComplete');
622    }
623  }
624
625  function getThumbnailsData(imageData) {
626    var thumbnailsData =  [];
627    imageData.forEach(function mapImageData(image, idx) {
628      var altText = ANF.messaging.catalogV2.thumbnailTMNTs[image.type + 'AltImageText'];
629      var thumbnail = {
630        'selected': (parseInt(idx, 10) === 0),
631        'data-src': ANFImage.instance()
632          .setImageName(image.id)
633          .setWidth(60)
634          .url,
635        'alt': altText.replace('{0}', image.index),
636        'imageId': image.id,
637        'imageType': image.type
638      };
639
640      thumbnailsData.push(thumbnail);
641    });
642
643    return thumbnailsData;
644  }
645
646  function onThumbnailsImagesLoaded() {
647    removeOldThumbnails($oldThumbnailsContainer);
648    // fade new one in
649    if ($newThumbnailsContainer) {
650      if (Utils.isQuickviewOpened) {
651        $newThumbnailsContainer.fadeIn(0, onCrossfadeEnd);
652      } else {
653        $newThumbnailsContainer.fadeIn(200, onCrossfadeEnd);
654      }
655    }
656  }
657
658  function onThumbnailLoadFailure(log) {
659    var $failedImage = $(log.failedImageElement);
660    var $thumbnailButton = $failedImage.closest(thumbnailButtonSelectorClass);
661    var failedImageType = $thumbnailButton.data('image-type');
662    var failedImageId = $thumbnailButton.data('image-id');
663    var $productSection = Utils.getParentProductSection($failedImage);
664    var cleanedImageDataObject = imageLoadHelper.removeFailedImage(log.failedImageElement, $productSection, failedImageType, failedImageId);
665
666    $failedImage.closest(thumbnailButtonSelectorClass).remove();
667    imageLoadHelper.storeImageData($productSection, cleanedImageDataObject.imageArray, cleanedImageDataObject.imageObject);
668  }
669
670  function onCrossfadeEnd() {
671    publicMembers.slider = $newThumbnailsContainer;
672    // turn to slider
673    $newThumbnailsContainer.on('beforeChange', onThumbnailsBeforeChange);
674    $newThumbnailsContainer.on('afterChange', onThumbnailsAfterChange);
675    $newThumbnailsContainer.on('init', onSliderInit);
676    $newThumbnailsContainer.on('setPosition', onSliderSetPosition);
677    $newThumbnailsContainer.on('breakpoint', onSliderBreakpoint);
678    initDSSlider($newThumbnailsContainer);
679
680    messageBus.trigger('thumbnailSlider:InitComplete');
681
682    // reset variables
683    $oldThumbnailsContainer = null;
684    $newThumbnailsContainer = null;
685  }
686
687  function onSliderInit(e, slick) {
688    var $nextArrow = slick.$nextArrow;
689    var $prevArrow = slick.$prevArrow;
690    var $slider = slick.$slider;
691
692    if ($nextArrow.hasClass('slick-hidden')) {
693      $slider.removeClass('has-arrows');
694    } else {
695      $slider.addClass('has-arrows');
696      $prevArrow.attr('tabindex', -1);
697    }
698  }
699
700  function onSliderSetPosition(e, slick) {
701    var $slider = slick.$slider;
702    var $slickTrack = $slider.find('.slick-track');
703    // prevent slider moving up when vertical
704    if (!$slider.hasClass('has-arrows') && slick.options.vertical === true) {
705      $slickTrack.css('transform', 'translate3d(0px, 0px, 0px)');
706    }
707  }
708
709  function onThumbnailsBeforeChange(e, slick, currentSlideIndex, nextSlideIndex) {
710    var $slides = slick.$slides;
711    var currentSlide = $slides[currentSlideIndex].querySelector(thumbnailInnerWrapperSelectorClass);
712    var nextSlide = $slides[nextSlideIndex].querySelector(thumbnailInnerWrapperSelectorClass);
713
714    // unselect current slide
715    if (currentSlide) currentSlide.setAttribute('data-state', '');
716
717    // select next slide
718    if (nextSlide) nextSlide.setAttribute('data-state', 'selected');
719  }
720
721  function onThumbnailsAfterChange(e, slick) {
722    var $prevArrow = slick.$prevArrow;
723    var $nextArrow = slick.$nextArrow;
724
725    if ($prevArrow.hasClass('slick-disabled')) {
726      $prevArrow.attr('tabindex', -1);
727    } else {
728      $prevArrow.attr('tabindex', 0);
729    }
730    if ($nextArrow.hasClass('slick-disabled')) {
731      $nextArrow.attr('tabindex', -1);
732    } else {
733      $nextArrow.attr('tabindex', 0);
734    }
735  }
736
737  function onSliderBreakpoint(e, slick, breakpoint) {
738    if (breakpoint) {
739      var $slider = slick.$slider;
740      var $mainImage = slick.getOption('asNavFor');
741      var $thumbnail = $slider.find(thumbnailButtonSelectorClass).first();
742      var slidesToShow = getSlidesToShow($mainImage, $thumbnail);
743
744      var slickSlidesToShowOption = slidesToShow.slidesToShowVertical;
745      if (breakpoint === 540) slickSlidesToShowOption = slidesToShow.slidesToShowHorizontal;
746
747      slick.slickSetOption('slidesToShow', slickSlidesToShowOption);
748      slick.refresh();
749      onSliderInit(e, slick);
750
751      var thumbnails = $slider.find(thumbnailInnerWrapperSelectorClass);
752      thumbnails.attr('data-state', '');
753      thumbnails[0].setAttribute('data-state', 'selected');
754    }
755  }
756
757  function getSlidesToShow($mainImage, $thumbnail) {
758    var slidesToShow = {
759      slidesToShowVertical: 1,
760      slidesToShowHorizontal: 1
761    };
762
763    // this was a painpoint! if either the mainImageWidth and mainImageHeight are negative you get an inifite loop. - NT+JR 3/31/20
764    var paddingForArrowsHorizonal = 92;
765    var mainImageWidth = $mainImage.width() - paddingForArrowsHorizonal;
766    var thumbnailWidth = $thumbnail.width();
767    // default to 1 if Infinity
768    slidesToShow.slidesToShowHorizontal = thumbnailWidth !== 0 ? Math.floor(mainImageWidth / thumbnailWidth) : 1;
769
770    var paddingForArrowsVertical = 80;
771    var mainImageHeight = ($mainImage.width() * 1.25) - paddingForArrowsVertical;
772    var thumbnailHeight = $thumbnail.height();
773    // default to 1 if Infinity
774    slidesToShow.slidesToShowVertical = thumbnailHeight !== 0 ? Math.floor(mainImageHeight / thumbnailHeight) : 1;
775
776    return slidesToShow;
777  }
778
779  function initDSSlider($thumbnails) {
780    var $correspondingMainImages = $thumbnails
781      .parent(productThumbnailWrapperSelectorClass)
782      .siblings(productMainImagesWrapperSelectorClass)
783      .find(productMainImagesSelectorClass)
784      .last();
785    var $thumbnail = $thumbnails.find(thumbnailButtonSelectorClass).first();
786    var slidesToShow = getSlidesToShow($correspondingMainImages, $thumbnail);
787
788    var thumbnailSliderSettings = {
789      arrows: true,
790      asNavFor: $correspondingMainImages,
791      focusOnSelect: true,
792      infinite: false,
793      mobileFirst: true,
794      variableWidth: true,
795      waitForAnimate: false,
796      responsive: [
797        {
798          breakpoint: 540,
799          settings: {
800            slidesToShow: slidesToShow.slidesToShowHorizontal
801          }
802        },
803        {
804          breakpoint: 825,
805          settings: {
806            slidesToShow: slidesToShow.slidesToShowVertical,
807            verticalSwiping: true,
808            variableWidth: false,
809            vertical: true
810          }
811        }
812      ]
813    };
814
815    publicMembers.thumbnailSlider.initializeSlider($thumbnails[0], thumbnailSliderSettings);
816  }
817
818  function removeOldThumbnails($oldthumbnails) {
819    $($oldthumbnails).remove();
820  }
821
822  function removeHalfLoadingThumbnails() {
823    $($newThumbnailsContainer) // stop any animation is currently running on the element then remove
824      .stop(true, true)
825      .remove();
826  }
827
828  var publicMembers = {
829    listen: function listen() {
830      messageBus.on('productMainImage:load productThumbnails:reload', onSwatchChanged);
831    },
832
833    thumbnailSlider: dsSlider.default()
834  };
835
836  return publicMembers;
837});
838
839redesign.define('productPartial/pdp_productImages',['handlebars','dsHelper/concat','wcsHelper/i18n'], function(Handlebars) {
840
841this["ANF"] = this["ANF"] || {};
842this["ANF"]["templates"] = this["ANF"]["templates"] || {};
843
844Handlebars.registerPartial("pdp_productImages", this["ANF"]["templates"]["pdp_productImages"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
845    var stack1;
846
847  return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.isUGC : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.program(4, data, 0),"data":data})) != null ? stack1 : "");
848},"2":function(container,depth0,helpers,partials,data) {
849    var alias1=container.lambda, alias2=container.escapeExpression, alias3=depth0 != null ? depth0 : (container.nullContext || {});
850
851  return "      <div class=\"product-main-images__image product-main-images__image--ugc\" data-orig-role=\"button\"  >\n         <img class=\"product-main-image\" data-lazy=\""
852    + alias2(alias1((depth0 != null ? depth0.src : depth0), depth0))
853    + "\" alt=\""
854    + alias2(helpers.concat.call(alias3,helpers.i18n.call(alias3,helpers.concat.call(alias3,"product.product_alt_",(depth0 != null ? depth0.type : depth0),"img",{"name":"concat","hash":{},"data":data}),{"name":"i18n","hash":{},"data":data})," ",(depth0 != null ? depth0.index : depth0),{"name":"concat","hash":{},"data":data}))
855    + "\" data-image-id=\""
856    + alias2(alias1((depth0 != null ? depth0.imageId : depth0), depth0))
857    + "\" itemprop=\"image\"/>\n      </div>\n";
858},"4":function(container,depth0,helpers,partials,data) {
859    var alias1=container.lambda, alias2=container.escapeExpression, alias3=depth0 != null ? depth0 : (container.nullContext || {});
860
861  return "        <button class=\"product-main-images__image product-main-images__zoom-modal-button\" data-image-type=\""
862    + alias2(alias1((depth0 != null ? depth0.type : depth0), depth0))
863    + "\" tabindex=\"-1\">\n          <img class=\"product-main-image\" data-lazy=\""
864    + alias2(alias1((depth0 != null ? depth0.src : depth0), depth0))
865    + "\" alt=\""
866    + alias2(helpers.concat.call(alias3,helpers.i18n.call(alias3,helpers.concat.call(alias3,"product.product_alt_",(depth0 != null ? depth0.type : depth0),"img",{"name":"concat","hash":{},"data":data}),{"name":"i18n","hash":{},"data":data}),(depth0 != null ? depth0.index : depth0),{"name":"concat","hash":{},"data":data}))
867    + "\" data-image-id=\""
868    + alias2(alias1((depth0 != null ? depth0.imageId : depth0), depth0))
869    + "\" itemprop=\"image\"/>\n        </button>\n";
870},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
871    var stack1;
872
873  return "<div class=\"product-main-images slider js-slider js-main-image loading\">\n"
874    + ((stack1 = helpers.blockHelperMissing.call(depth0,container.lambda((depth0 != null ? depth0.mainImages : depth0), depth0),{"name":"mainImages","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
875    + "</div>\n";
876},"useData":true}));
877
878return this["ANF"];
879
880});
881redesign.define('productModules/product/productMainImage',[
882  'productPartial/pdp_productImages',
883  'anfcore/components/slider',
884  'productModules/helpers/Utils',
885  'productModules/helpers/imageLoadHelper',
886  'coreClass/ANFImage'
887],
888function productMainImage(
889  productPartialPdpProductImages,
890  dsSlider,
891  Utils,
892  imageLoadHelper,
893  ANFImage
894) {
895  'use strict';
896
897  var mainImagesContainerWrapperSelectorClass = '.product-main-images__wrapper';
898  var loadedMainImagesSelectorClass = '.product-main-images:not(:last-of-type)';
899  var nonUGCMainImageClass = '.product-main-images .product-main-images__image:not(.product-main-images__image--ugc)';
900  var loadingClass = 'loading';
901  var productLoadingContainerSelectorClass = '.product-main-images__loading-container';
902  var mainImageZoomModalButtonSelectorClass = '.product-main-images__zoom-modal-button';
903  var mainImageSliderSettings = {
904    accessibility: true,
905    arrows: false,
906    dots: true,
907    dotsClass: 'slick-dots ds-override',
908    hoverArrows: true,
909    infinite: false,
910    lazyLoad: 'progressive',
911    mobileFirst: true,
912    responsive: [
913      {
914        breakpoint: 540,
915        settings: {
916          asNavFor: Utils.isQuickviewOpened ? null : '.product-thumbnails__container .product-thumbnails',
917          dots: Utils.isQuickviewOpened ? true : false,
918          fade: true,
919          waitForAnimate: false
920        }
921      },
922      {
923        breakpoint: 825,
924        settings: {
925          asNavFor: null,
926          dots: false
927        }
928      }
929    ]
930  };
931  // Implementing a queue for handling swatch changes in rapid succession
932  var queue = [];
933  var queueProcessing = false;
934  var noImageAvailableAssetImageId = imageLoadHelper.getNoImageAvailableAssetImageId();
935  var noImgProcessedImageArray = [{
936    id: noImageAvailableAssetImageId,
937    imageId: noImageAvailableAssetImageId,
938    index: 1,
939    isUGC: false,
940    src: imageLoadHelper.getNoImageAvailableAssetUrl(),
941    type: 'prod'
942  }];
943  var mainImageWidth = 800;
944
945  var messageBus = $(ANF);
946
947  function imageLoadHandler(e, data) {
948    // push data for current swatch into queue to handle swatch clicks in rapid succession
949    queue.push({
950      processedImageArray: data.processedImageArray.slice(0),
951      imageDataModel: data.imageDataModel,
952      productId: data.productId,
953      $productSection: data.$productSection,
954      $mainImagesContainerWrapper: data.$productSection.find(mainImagesContainerWrapperSelectorClass)
955    });
956
957    processQueue();
958
959    if (!Utils.isQuickviewOpened) {
960      if (Utils.isExternalUser()) {
961        $('.product-page-user-content__recommendations').addClass('hide');
962        $('.pdp-grid-container').removeClass('hide');
963      }
964    }
965  }
966
967  function processQueue() {
968    if (queueProcessing) {
969      return;
970    }
971
972    if (queue.length) {
973      queueProcessing = true;
974      var currentQueueObj = queue.pop();
975      queue = [];
976
977      if (currentQueueObj.processedImageArray.length < 1) {
978        currentQueueObj.processedImageArray = noImgProcessedImageArray;
979      }
980      addNewImages(currentQueueObj);
981    }
982  }
983
984  function addNewImages(currentQueueObj) {
985    var obj = currentQueueObj;
986    obj.processedImageArray.forEach(function addImageSrc(imageData) {
987      var imgData = imageData;
988      imgData.src = ANFImage.instance()
989        .setImageName(imgData.id)
990        .setWidth(mainImageWidth)
991        .url;
992    });
993
994    // need jquery object of the hbs output to listen for load/error on each image to be added
995    obj.$imagesMarkup = $(productPartialPdpProductImages.templates.pdp_productImages({mainImages: obj.processedImageArray}));
996    currentQueueObj.$mainImagesContainerWrapper.append(obj.$imagesMarkup);
997
998    postFadeProcess(obj);
999    initSlider(obj);
1000  }
1001
1002  function postFadeProcess(currentQueueObj) {
1003    var $productSection = currentQueueObj.$productSection;
1004    currentQueueObj.$productSection.find(loadedMainImagesSelectorClass).remove();
1005
1006    // on reload this fires the thumbies reload
1007    messageBus.trigger('productMainImage:firstDownloadComplete', $productSection);
1008
1009    $productSection.find(productLoadingContainerSelectorClass).removeClass(loadingClass); // remove for mobile
1010    currentQueueObj.$imagesMarkup.removeClass(loadingClass); // remove for desktop
1011
1012    if (!Utils.isQuickviewOpened) {
1013      window.setTimeout(function detailsImageLoadTimeout() { // to move trigger response to the end of the JS queue
1014        messageBus.trigger('productPageReviews:updateImage', [$productSection]);
1015      }, 0);
1016    }
1017    queueProcessing = false;
1018    processQueue();
1019  }
1020
1021  function imageFailedLoadHandler(sliderObj, failedImage) {
1022    var slickIndex = $(failedImage).closest('.slick-slide').attr('data-slick-index');
1023    sliderObj.$slider.slick('slickRemove', slickIndex);
1024    sliderObj.$slider.slick('slickGoTo', slickIndex);
1025  }
1026
1027  function initSlider(currentQueueObj) {
1028    var $container = currentQueueObj.$imagesMarkup;
1029    $container.on('afterChange', onSlideChange);
1030    $container.on('init', onSlideInit);
1031    $container.on('lazyLoadError', function lazyLoadErrorDataPassThrough(_e, sliderObj, $img) {
1032      imageFailedLoadHandler(sliderObj, $img, currentQueueObj.$productSection);
1033    });
1034    $container.on('lazyLoaded', function lazyLoadedFunction(_e, slick, $img) {
1035      if ($img.closest('.slick-slide').data('slick-index') === 0) {
1036        $img.fadeIn(100, function isfirstImageLoaded() {
1037          if (Utils.isQuickviewOpened) {
1038            // push this trigger to the back of the JS stack, so the quickview load sequence can begin and not be held up by magnify.
1039            window.setTimeout(function startMagnifyImages() {
1040              messageBus.trigger('quickviewImages:mainImageLoaded', slick.$slider);
1041            }, 0);
1042          } else {
1043            $('.complementary-products-container').fadeIn(100);
1044          }
1045        });
1046      } else {
1047        $img.addClass('loaded');
1048      }
1049    });
1050
1051    dsSlider.default().initializeSlider($container[0], mainImageSliderSettings);
1052  }
1053
1054  function onSlideChange(event, slick, currentSlide) {
1055    var $currentSlickSlide = $($(slick.$slides).get(currentSlide));
1056    $(ANF).trigger('productMainImage:sliderAfterChange', $currentSlickSlide);
1057  }
1058  // This function will fire again if we end up removing a slide from the Main Image Slider
1059  function onSlideInit() {
1060    $(ANF).trigger('productMainImage:sliderInit');
1061  }
1062
1063  function mainImageClickHandler(e) {
1064    var $selectedImage = $(e.currentTarget);
1065    messageBus.trigger('productMainImage:mainImageClicked', [{
1066      idx: $selectedImage.closest('.slick-slide').attr('data-slick-index'),
1067      $productSection: $selectedImage.closest('.product-page-v2-modules'),
1068      image: $selectedImage.find('img'),
1069      imageButton: $selectedImage.find(mainImageZoomModalButtonSelectorClass)
1070    }]);
1071  }
1072
1073  var publicMembers = {
1074    listen: function listen() {
1075      messageBus.on('productMainImage:load productMainImage:reload productPageMainImages:modelSelected', imageLoadHandler);
1076    },
1077    bindEvents: function bindEvents() {
1078      $(mainImagesContainerWrapperSelectorClass).on('click', nonUGCMainImageClass, mainImageClickHandler);
1079    }
1080  };
1081
1082  return publicMembers;
1083});
1084
1085redesign.define('productModules/helpers/breakpoints',[], function BreakpointsMain() {
1086  'use strict';
1087
1088  /**
1089   * A convenience way to track breakpoint and window resize event
1090   * Built-in to the global ANF object and already run on page
1091   * @example
1092   * // Strings for different screen size
1093   * 'small_phone' 'phone' 'tablet' 'small_desktop' 'desktop' 'large_desktop' 'max_desktop'
1094   * // To get the current screen size
1095   * console.log(ANF.breakpoints.screen)
1096   **/
1097
1098  function Breakpoints() {
1099    this.screen = null;
1100
1101    this.options = [
1102      {
1103        maxWidth: 359,
1104        name: 'small_phone'
1105      },
1106      {
1107        maxWidth: 539,
1108        name: 'phone'
1109      },
1110      {
1111        maxWidth: 699,
1112        name: 'tablet'
1113      },
1114      {
1115        maxWidth: 824,
1116        name: 'small_desktop'
1117      },
1118      {
1119        maxWidth: 1024,
1120        name: 'desktop'
1121      },
1122      {
1123        maxWidth: 1499,
1124        name: 'large_desktop'
1125      },
1126      {
1127        maxWidth: 100000,
1128        name: 'max_desktop'
1129      }
1130    ];
1131
1132    this.screens = this.options.map(function map(obj, idx, array) {
1133      var minWidth;
1134      var maxWidth;
1135
1136      maxWidth = obj.maxWidth;
1137
1138      if (idx === 0) {
1139        minWidth = 0;
1140      } else {
1141        minWidth = array[idx - 1].maxWidth + 1;
1142      }
1143
1144      return [minWidth, maxWidth, obj.name];
1145    });
1146
1147    this.getCurrentScreen = function getCurrentScreen(width) {
1148      var currentScreenData;
1149      var	currentScreenType;
1150
1151      currentScreenData = this.screens.filter(function filter(element) {
1152        if (element[0] <= width && width <= element[1]) {
1153          return true;
1154        }
1155        return false;
1156      });
1157
1158      try {
1159        currentScreenType = currentScreenData[0][2];
1160      } catch (event) {
1161        currentScreenType = this.screens[this.screens.length - 1][2];
1162      }
1163
1164      if (currentScreenType !== this.screen) {
1165        this.screen = currentScreenType;
1166      }
1167    };
1168
1169    this.getCurrentScreen(window.innerWidth, true);
1170
1171    return this;
1172  }
1173
1174  var breakpoints = new Breakpoints();
1175
1176  ANF.breakpoints = breakpoints;
1177
1178  return breakpoints;
1179});
1180
1181redesign.define('productPartial/pdp_productImagesZoom',['handlebars'], function(Handlebars) {
1182
1183this["ANF"] = this["ANF"] || {};
1184this["ANF"]["templates"] = this["ANF"]["templates"] || {};
1185
1186Handlebars.registerPartial("pdp_productImagesZoom", this["ANF"]["templates"]["pdp_productImagesZoom"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
1187    var alias1=container.lambda, alias2=container.escapeExpression;
1188
1189  return "    <li class=\"product-zoom__image loading\" data-collection=\""
1190    + alias2(alias1((depth0 != null ? depth0.collectionId : depth0), depth0))
1191    + "\" tabindex=\"-1\">\n      <img data-src=\""
1192    + alias2(alias1((depth0 != null ? depth0.src : depth0), depth0))
1193    + "\" data-collection=\""
1194    + alias2(alias1((depth0 != null ? depth0.collectionId : depth0), depth0))
1195    + "\"\n        alt=\""
1196    + alias2(alias1((depth0 != null ? depth0.altText : depth0), depth0))
1197    + "\" />\n    </li>\n";
1198},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
1199    var stack1;
1200
1201  return "<div class=\"product-zoom__thumbnails\">\n</div>\n<ul class=\"product-zoom__images\">\n"
1202    + ((stack1 = helpers.blockHelperMissing.call(depth0,container.lambda((depth0 != null ? depth0.zoomImages : depth0), depth0),{"name":"zoomImages","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
1203    + "</ul>\n";
1204},"useData":true}));
1205
1206return this["ANF"];
1207
1208});
1209redesign.define('productPartial/pdp_mobileZoomImage',['handlebars'], function(Handlebars) {
1210
1211this["ANF"] = this["ANF"] || {};
1212this["ANF"]["templates"] = this["ANF"]["templates"] || {};
1213
1214Handlebars.registerPartial("pdp_mobileZoomImage", this["ANF"]["templates"]["pdp_mobileZoomImage"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
1215    var alias1=container.lambda, alias2=container.escapeExpression;
1216
1217  return "<img id=\"zoom-img\" class=\"loading\" src=\""
1218    + alias2(alias1((depth0 != null ? depth0.src : depth0), depth0))
1219    + "\" alt=\""
1220    + alias2(alias1((depth0 != null ? depth0.alt : depth0), depth0))
1221    + "\" />";
1222},"useData":true}));
1223
1224return this["ANF"];
1225
1226});
1227redesign.define('productPartial/pdp_zoomThumbnails',['handlebars','dsPartial/button','dsPartial/thumbnail'], function(Handlebars) {
1228
1229this["ANF"] = this["ANF"] || {};
1230this["ANF"]["templates"] = this["ANF"]["templates"] || {};
1231
1232Handlebars.registerPartial("pdp_zoomThumbnails", this["ANF"]["templates"]["pdp_zoomThumbnails"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
1233    var stack1;
1234
1235  return ((stack1 = container.invokePartial(partials.button,depth0,{"name":"button","hash":{"variant":"borderless-button","type":"button"},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
1236},"2":function(container,depth0,helpers,partials,data) {
1237    var stack1;
1238
1239  return ((stack1 = container.invokePartial(partials.thumbnail,depth0,{"name":"thumbnail","hash":{"selected":false,"selectedText":(depth0 != null ? depth0.Selected : depth0),"alt":(depth0 != null ? depth0.altText : depth0),"src":(depth0 != null ? depth0.src : depth0)},"data":data,"indent":"            ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
1240},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
1241    var stack1;
1242
1243  return "<div class='zoom-thumbnail-list slider'>\n"
1244    + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.thumbImages : depth0),{"name":"each","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
1245    + "</div>";
1246},"usePartial":true,"useData":true}));
1247
1248return this["ANF"];
1249
1250});
1251redesign.define('productModules/product/productZoom',[
1252  'productModules/helpers/breakpoints',
1253  'anfcore/components/modal',
1254  'anfcore/components/slider',
1255  'productModules/helpers/imageLoadHelper',
1256  'anfUtil/testFramework',
1257  'coreClass/ANFImage',
1258  'productPartial/pdp_productImagesZoom',
1259  'productPartial/pdp_mobileZoomImage',
1260  'productPartial/pdp_zoomThumbnails',
1261  'productModules/helpers/Utils'
1262], function ProductZoom(
1263  breakpoints,
1264  modal,
1265  slider,
1266  imageLoadHelper,
1267  test,
1268  ANFImage,
1269  productPartialPdpProductImagesZoom,
1270  productPartialPdpMobileZoomImage,
1271  productPartialPdpZoomThumbnails,
1272  Utils
1273) {
1274  'use strict';
1275
1276  // Constants
1277  var $window = $(window);
1278  var dsModal = modal.default();
1279  var dsSlider = slider.default();
1280  var messageBus = $(ANF);
1281  var zoomImagesContainerSelectorClass = '.product-zoom__images';
1282  var zoomImageWrapperSelectorClass = '.product-zoom__image';
1283  var zoomModalContainerSelectorClass = '.product-zoom__modal';
1284  var zoomThumbnailInnerWrapperSelector = '.thumbnail-inner-wrapper';
1285  var zoomThumbnailSlideSelector = '.slide';
1286  var zoomThumbWrapperSelectorClass = '.product-zoom__thumbnails .thumbnail-inner-wrapper';
1287  var zoomThumbWrapperElement = '<div class="product-zoom__thumbnails"></div>';
1288  var mobileImageWidth = 800;
1289  var imageWidth = 1900;
1290  var zoomThumbWidth = 60;
1291  // end Constants
1292
1293  var publicMembers = {
1294    bindEvents: function bindEvents() {
1295      $(document).on('click touchstart', '.product-zoom__modal .slick-slide .slide', thumbnailSelectEventHandler);
1296    },
1297
1298    listen: function listen() {
1299      messageBus.on('productMainImage:mainImageClicked', initZoomModal);
1300    }
1301  };
1302
1303  function initZoomModal(_e, data) {
1304    var $productSection = data.$productSection;
1305    var productId = $productSection.attr('data-productid');
1306    var collectionId = Utils.getProductData(productId).collection;
1307    var $zoomModalContentBlock = $productSection.find('.product-zoom__modal .modal-block .modal-content');
1308    var $imageButton = data.imageButton;
1309    var zoomModal;
1310
1311    var zoomImageLoaderObject = {};
1312    zoomImageLoaderObject[productId] = {};
1313    zoomImageLoaderObject[productId].productSection = $productSection;
1314    zoomImageLoaderObject[productId].parentCollectionId = collectionId;
1315
1316    if (isMobile()) {
1317      zoomModal = renderMobileZoom(data, collectionId, $zoomModalContentBlock, productId);
1318    } else {
1319      zoomImageLoaderObject[productId] = prepareZoomImagesForLoad(data, zoomImageLoaderObject[productId]);
1320      zoomModal = openDesktopZoomModal(zoomImageLoaderObject[productId]);
1321      $zoomModalContentBlock.html(zoomThumbWrapperElement);
1322
1323      if (zoomImageLoaderObject[productId].imageDataSrcArray.zoomImages.length > 1) {
1324        handleZoomThumbnailsLoad(zoomImageLoaderObject[productId], $zoomModalContentBlock);
1325      }
1326      downloadImages(zoomImageLoaderObject[productId], $zoomModalContentBlock, $(zoomModal), data.idx);
1327    }
1328
1329    zoomModal.addEventListener('dsModal:Close', function restoreImageFocus() {
1330      $window.off('resize.zoom');
1331      $imageButton.focus();
1332    }, {once: true});
1333
1334    setTimeout(function showZoomTimeout() {
1335      // TODO: remove after image presentation test over
1336      $window.trigger('analytics.miscProductFeature', {
1337        'type': 'PDP Image',
1338        'action': 'click'
1339      });
1340    }, 0);
1341  }
1342
1343  function openDesktopZoomModal(zoomImageLoaderObject) {
1344    var zoomModal = dsModal.openModal('product-zoom__' + zoomImageLoaderObject.parentCollectionId);
1345
1346    $window.on('resize.zoom', onResizeThumbnailSliderUpdate);
1347
1348    return zoomModal;
1349  }
1350
1351  function prepareZoomImagesForLoad(data, zoomImageLoaderObject) {
1352    var renderedHtml;
1353    var $currentProductSection = data.$productSection;
1354    var newZoomImageLoaderObject = zoomImageLoaderObject;
1355    var collectionId = zoomImageLoaderObject.parentCollectionId;
1356    var imageDataSrcArray = {
1357      zoomImages: [],
1358      thumbImages: []
1359    };
1360
1361    $currentProductSection.data('processedImageArray').forEach(function zoomImageDataModelCuration(image) {
1362      // we dont add UGC images to Zoom
1363      if (image.isUGC) {
1364        return false;
1365      }
1366      var zoomImageSrc = ANFImage.instance()
1367        .setImageName(image.imageId)
1368        .setWidth(imageWidth)
1369        .url;
1370
1371      var zoomThumnbailSrc = ANFImage.instance()
1372        .setImageName(image.imageId)
1373        .setWidth(zoomThumbWidth)
1374        .url;
1375
1376      var zoomImageObject = {
1377        src: zoomImageSrc,
1378        collectionId: collectionId,
1379        isOFP: false
1380      };
1381      var zoomThumbImageObject = {
1382        src: zoomThumnbailSrc,
1383        isOFP: false
1384      };
1385
1386      if (image.type === 'model') {
1387        zoomImageObject.isOFP = true;
1388        zoomImageObject.altText = ANF.messaging.product.PDP_TEXT_MODEL + ' ' + image.index;
1389        zoomThumbImageObject.altText = ANF.messaging.product.PDP_TEXT_MODEL + ' ' + image.index;
1390      } else if (image.type === 'life') {
1391        zoomImageObject.altText = ANF.messaging.product.PDP_TEXT_LIFESTYLE + ' ' + image.index;
1392        zoomThumbImageObject.altText = ANF.messaging.product.PDP_TEXT_LIFESTYLE + ' ' + image.index;
1393      } else {
1394        zoomImageObject.altText = ANF.messaging.product.PDP_TEXT_PRODUCT + ' ' + image.index;
1395        zoomThumbImageObject.altText = ANF.messaging.product.PDP_TEXT_PRODUCT + ' ' + image.index;
1396      }
1397
1398      imageDataSrcArray.zoomImages.push(zoomImageObject);
1399      imageDataSrcArray.thumbImages.push(zoomThumbImageObject);
1400
1401      return true;
1402    });
1403
1404    renderedHtml = productPartialPdpProductImagesZoom.templates.pdp_productImagesZoom(imageDataSrcArray);
1405
1406    newZoomImageLoaderObject.imagesLoaded = false;
1407    newZoomImageLoaderObject.$renderedHtml = $(renderedHtml);
1408    // include the thumbnail html, for some reason $renderedHtml has 3 items in the array. 1st is zoom images 2nd is a text node? 3rd is thumbnail container
1409    newZoomImageLoaderObject.modalContent = newZoomImageLoaderObject.$renderedHtml[0].outerHTML + newZoomImageLoaderObject.$renderedHtml[2].outerHTML;
1410    newZoomImageLoaderObject.imageDataSrcArray = imageDataSrcArray;
1411    newZoomImageLoaderObject.parentCollectionId = collectionId;
1412
1413    return newZoomImageLoaderObject;
1414  }
1415
1416  function downloadImages(zoomImageLoaderObject, $zoomModalContentBlock, $zoomModal, index) {
1417    var newZoomImageLoaderObject = zoomImageLoaderObject;
1418
1419    newZoomImageLoaderObject.loadedImageCount = 0;
1420
1421    $zoomModalContentBlock.append(newZoomImageLoaderObject.modalContent);
1422
1423    $zoomModalContentBlock.find('.product-zoom__image img').each(function downloadZoomImageLoop() {
1424      var $currImgSrc = $(this).attr('src', $(this).data('src'));
1425      $currImgSrc.one('load', function zoomImageLoad() {
1426        imageLoaded(newZoomImageLoaderObject, $(this).parent(), $zoomModal, index);
1427      });
1428      bindImageErrorEvent($currImgSrc);
1429    });
1430  }
1431
1432  function imageLoaded(zoomImageLoaderObject, $zoomImageContainer, $zoomModal, index) {
1433    var newZoomImageLoaderObject = zoomImageLoaderObject;
1434    newZoomImageLoaderObject.loadedImageCount++;
1435    $zoomImageContainer.removeClass('loading');
1436
1437    if (newZoomImageLoaderObject.loadedImageCount >= newZoomImageLoaderObject.imageDataSrcArray.zoomImages.length) {
1438      newZoomImageLoaderObject.imagesLoaded = true;
1439      scrollToCorrespondingImage($zoomModal, index);
1440      initWaypoints($zoomModal);
1441    }
1442  }
1443
1444  function renderMobileZoom(data, collectionId, $zoomModalContentBlock) {
1445    var $imgClicked = data.image;
1446    var imgUrl = ANFImage.instance()
1447      .setImageName($imgClicked.data().imageId)
1448      .setWidth(mobileImageWidth)
1449      .url;
1450
1451    var zoomImageDataModel = {
1452      isProdFlatImage: false,
1453      src: imgUrl,
1454      alt: $imgClicked.attr('src').indexOf('prod') > -1 ? 'prod' : 'model'
1455    };
1456
1457    var mobileZoomImage = productPartialPdpMobileZoomImage.templates.pdp_mobileZoomImage(zoomImageDataModel);
1458
1459    $zoomModalContentBlock.html(mobileZoomImage);
1460
1461    $(zoomModalContainerSelectorClass).on('dsModal:Open', function zoomDSModalOpen() {
1462      var $currentZoomImg = $('#zoom-img');
1463      $currentZoomImg.load(function zoomImageLoad() {
1464        $(this)[0].scrollIntoView({
1465          behavior: 'auto',
1466          block: 'center',
1467          inline: 'center'
1468        });
1469        $(this).removeClass('loading');
1470      });
1471      bindImageErrorEvent($currentZoomImg);
1472    });
1473    var zoomModal = dsModal.openModal('product-zoom__' + collectionId);
1474
1475    $('#product-zoom__' + collectionId ).focus();
1476
1477    return zoomModal;
1478  }
1479
1480  function handleZoomThumbnailsLoad(zoomImageLoaderObject, $zoomModalContentBlock) {
1481    var newZoomImageLoaderObject = zoomImageLoaderObject;
1482    newZoomImageLoaderObject.thumbnailContent = generateZoomThumbTemplate(newZoomImageLoaderObject);
1483    renderZoomThumbnails($zoomModalContentBlock, newZoomImageLoaderObject);
1484    initZoomThumbnailSlider(newZoomImageLoaderObject);
1485  }
1486
1487  function generateZoomThumbTemplate(zoomImageLoaderObject) {
1488    return productPartialPdpZoomThumbnails.templates.pdp_zoomThumbnails(zoomImageLoaderObject.imageDataSrcArray);
1489  }
1490
1491  function renderZoomThumbnails($zoomModalContentBlock, zoomImageLoaderObject) {
1492    var $zoomThumbnailContentBlock = $zoomModalContentBlock.find('.product-zoom__thumbnails');
1493    $zoomThumbnailContentBlock.html(zoomImageLoaderObject.thumbnailContent);
1494  }
1495
1496  function initZoomThumbnailSlider(zoomImageLoaderObject) {
1497    var viewportHeight = window.innerHeight;
1498    var $thumbnailListContainer = $('.product-zoom__modal[data-open=true] .zoom-thumbnail-list');
1499    var thumbnailHeight = 85;
1500    var thumbnailCount = Math.floor(viewportHeight / thumbnailHeight);
1501    var newZoomImageLoaderObject =  zoomImageLoaderObject;
1502
1503    var sliderSettings = {
1504      arrows: true,
1505      infinite: false,
1506      slidesToShow: thumbnailCount,
1507      vertical: true,
1508      respondTo: 'window'
1509    };
1510
1511    newZoomImageLoaderObject.loadedThumbnailImageCount = 0;
1512
1513    $thumbnailListContainer.children().each(function zoomThumbnailLoop() {
1514      $(this).find('img').on('load', function zoomThumbnailLoad() {
1515        newZoomImageLoaderObject.loadedThumbnailImageCount++;
1516
1517        if (newZoomImageLoaderObject.loadedThumbnailImageCount >= newZoomImageLoaderObject.imageDataSrcArray.thumbImages.length) {
1518          dsSlider.initializeSlider($thumbnailListContainer[0], sliderSettings);
1519        }
1520      });
1521      bindImageErrorEvent($(this).find('img'));
1522    });
1523  }
1524
1525  function scrollToCorrespondingImage($modal, imageIdx) {
1526    var $targetZoomedImage = $modal.find(zoomImagesContainerSelectorClass + ' img').eq(imageIdx);
1527    var imagePosition = $targetZoomedImage.position();
1528
1529    // only scroll to the image if it is on the page.
1530    if (test.type.defined(imagePosition)) {
1531      $modal.scrollTop(imagePosition.top);
1532
1533      $targetZoomedImage.closest(zoomImageWrapperSelectorClass).focus();
1534
1535      selectActiveThumbnail($modal, imageIdx);
1536    }
1537  }
1538
1539  function selectActiveThumbnail($modal, imageIdx) {
1540    var $zoomThumbs = $modal.find(zoomThumbWrapperSelectorClass);
1541    $zoomThumbs.attr('data-state', '');
1542    $zoomThumbs.eq(imageIdx).attr('data-state', 'selected');
1543    $zoomThumbs.eq(imageIdx).closest(zoomThumbnailSlideSelector).focus();
1544  }
1545
1546  function initWaypoints($modal) {
1547    var Waypoint = Waypoint || window.Waypoint;
1548    var $zoomImages = $modal.find(zoomImagesContainerSelectorClass).children();
1549
1550    $zoomImages.each(function zoomImageWaypointDestroyLoop() {
1551      var $image = $(this);
1552      var waypointContext = Waypoint.Context.findByElement($image.context);
1553
1554      if (waypointContext) {
1555        waypointContext.destroy();
1556      }
1557    });
1558
1559    $zoomImages.waypoint({
1560      handler: waypointHandler,
1561      offset: '55%',
1562      context: zoomModalContainerSelectorClass
1563    });
1564  }
1565
1566  function onResizeThumbnailSliderUpdate() {
1567    var $zoomModal =  $('.product-zoom__modal[data-open=true]');
1568    var viewportHeight = window.innerHeight;
1569    var $thumbnailListContainer = $zoomModal.find('.zoom-thumbnail-list');
1570    var thumbnailHeight = 85;
1571    var thumbnailCount = Math.floor(viewportHeight / thumbnailHeight);
1572    var activeThumbIndex = $thumbnailListContainer.find('.thumbnail-inner-wrapper[data-state="selected"]').closest('.slick-slide').index();
1573
1574    $thumbnailListContainer.slick('slickSetOption', 'slidesToShow', thumbnailCount);
1575    $thumbnailListContainer.slick('refresh');
1576
1577    // reselect the active thumbnail after the refresh, since refresh whipes that state
1578    selectActiveThumbnail($zoomModal, activeThumbIndex);
1579  }
1580
1581  function waypointHandler(direction) {
1582    var idx = $(this.element).index();
1583    var $modal = $(this.element).closest(zoomModalContainerSelectorClass);
1584
1585    idx = wayPointGetIndex(direction, idx);
1586    selectActiveThumbnail($modal, idx);
1587  }
1588
1589  function wayPointGetIndex(direction, idx) {
1590    var currentIdex = idx;
1591    if (direction === 'up') {
1592      currentIdex -= 1;
1593      return currentIdex;
1594    }
1595
1596    return currentIdex;
1597  }
1598
1599  function thumbnailSelectEventHandler(e) {
1600    var $clickedThumbnail = $(e.target);
1601    var $modal = $clickedThumbnail.closest(zoomModalContainerSelectorClass);
1602    var $zoomThumbs = $modal.find(zoomThumbWrapperSelectorClass);
1603    var targetIndex = $zoomThumbs.index($clickedThumbnail.find(zoomThumbnailInnerWrapperSelector));
1604
1605    scrollToCorrespondingImage($modal, targetIndex);
1606  }
1607
1608  function bindImageErrorEvent($image) {
1609    $image.one('error', function zoomImageLoadError() {
1610      var imageLoadErrorFallbackUrl = imageLoadHelper.getNoImageAvailableAssetUrl();
1611      var imagePresets = this.src.split('?')[1];
1612      $(this).data('src', imageLoadErrorFallbackUrl + '?' + imagePresets);
1613      $(this).attr('src', imageLoadErrorFallbackUrl + '?' + imagePresets);
1614    });
1615  }
1616
1617  function isMobile() {
1618    return breakpoints && (breakpoints.screen === 'phone' || breakpoints.screen === 'small_phone' || breakpoints.screen === 'tablet') && ANF.params.env.isMobile === 'true';
1619  }
1620
1621  return publicMembers;
1622});
1623
1624redesign.define('coreModulesHelpers/StringUtils',[],function () {
1625  'use strict';
1626
1627  var instance = null;
1628
1629  // Matches non-punctuation characters except apostrophe for capitalization.
1630  var CAPITALIZE_REG = /[^\u0000-\u0040\u005B-\u0060\u007B-\u007F]+('s)?/g;
1631
1632  // Regex matching camelCase.
1633  var CAMELIZE_REG = /(^|_)([^_]+)/g;
1634
1635  function StringUtils() {
1636    if (instance !== null) {
1637      throw new Error('Cannot instantiate more than one StringUtils, use StringUtils.getInstance()');
1638    }
1639
1640    this.initialize();
1641  }
1642
1643  StringUtils.prototype = {
1644    initialize: function () {
1645      // Initializes the singleton.
1646    },
1647
1648    /**
1649     * Truncate string by number of words
1650     * @param {String} str The original string
1651     * @param {Number} limit The number of words to keep
1652     * @param {String} after The appended text after the truncated copy
1653     * @return {String} The truncated text
1654     */
1655    truncateOnWord: function (str, limit, after) {
1656      // clean up str
1657      var content = str.trim();
1658      // Convert the content into an array of words
1659      // Remove any words above the limit
1660      content = content.split(' ').slice(0, limit);
1661      // Convert the array of words back into a string
1662      // If there's content to add after it, add it
1663      content = content.join(' ') + (after ? after : '');
1664      // Return the content
1665      return content;
1666    },
1667
1668    /** *
1669     * @method capitalize([lower] = false, [all] = false)
1670     * @returns String
1671     * @short Capitalizes the first character of the string.
1672     * @extra If [lower] is true, the remainder of the string will be downcased.
1673     *        If [all] is true, all words in the string will be capitalized.
1674     *
1675     * @example
1676     *
1677     *   'hello'.capitalize()           -> 'Hello'
1678     *   'HELLO'.capitalize(true)       -> 'Hello'
1679     *   'hello kitty'.capitalize()     -> 'Hello kitty'
1680     *   'hEllO kItTy'.capitalize(true, true) -> 'Hello Kitty'
1681     *
1682     * @param {boolean} [lower]
1683     * @param {boolean} [all]
1684     *
1685     ***/
1686    capitalize: function (str, lower, all) {
1687      return this.stringCapitalize(str, lower, all);
1688    },
1689
1690    /** *
1691     * @method camelize([upper] = true)
1692     * @returns String
1693     * @short Converts string to camel case.
1694     * @extra If [upper] is true, the string will be UpperCamelCase.
1695     *
1696     * @example
1697     *
1698     *   'caps_lock'.camelize()             -> 'CapsLock'
1699     *   'capsLock'.camelize()              -> 'CapsLock'
1700     *   'MozBorderRadius'.camelize(false)  -> 'mozBorderRadius'
1701     *
1702     * @param {boolean} [upper]
1703     *
1704     ***/
1705    camelize: function (str, upper) {
1706      return this.stringCamelize(str, upper);
1707    },
1708
1709    stringCamelize: function (str, upper) {
1710      str = this.stringUnderscore(str);
1711      var _this = this;
1712      return str.replace(CAMELIZE_REG, function (match, pre, word, index) {
1713        var cap = upper !== false || index > 0;
1714        return cap ? _this.stringCapitalize(word, true) : word;
1715      });
1716    },
1717
1718    stringUnderscore: function (str) {
1719      return str
1720        .replace(/[-\s]+/g, '_')
1721        .replace(/([A-Z\d]+)([A-Z][a-z])/g, '$1_$2')
1722        .replace(/([a-z\d])([A-Z])/g, '$1_$2')
1723        .toLowerCase();
1724    },
1725
1726    stringCapitalize: function (str, downcase, all) {
1727      if (downcase) {
1728        str = str.toLowerCase();
1729      }
1730      return all ? str.replace(CAPITALIZE_REG, this.simpleCapitalize) : this.simpleCapitalize(str);
1731    },
1732
1733    simpleCapitalize: function (str) {
1734      return str.charAt(0).toUpperCase() + str.slice(1);
1735    }
1736  };
1737
1738  StringUtils.getInstance = function () {
1739    // Gets an instance of the singleton.
1740    if (instance === null) {
1741      instance = new StringUtils();
1742    }
1743    return instance;
1744  };
1745
1746  return StringUtils.getInstance();
1747});
1748
1749redesign.define('productModules/product/productImageLoader',[
1750  'coreServices/url',
1751  'coreModulesHelpers/StringUtils',
1752  'anfUtil/testFramework',
1753  'productModules/helpers/imageLoadHelper',
1754  'productModules/helpers/Utils'
1755],
1756function productImageLoader(urlService, StringUtils, test, imageLoadHelper, Utils) {
1757  'use strict';
1758
1759  var quickviewModalProductSectionSelectorClass = '.product-quickview__content .product-page-v2-modules';
1760  var productSectionSelectorClass = '.product-page-v2-modules';
1761  var productIdAttributeName = 'productid';
1762  var messageBus = $(ANF);
1763
1764  var isReload = false;
1765
1766  function getValidatedModelSegments(productDataObject) {
1767    if (
1768      test.type.not.defined(productDataObject.productAttrs, false) ||
1769      test.type.not.defined(productDataObject.productAttrs.ModelData, false)
1770    ) {
1771      return false;
1772    }
1773
1774    var imageDataObj = productDataObject.imageSets;
1775    var modelDataObj = productDataObject.productAttrs.ModelData;
1776    var verifiedModelSegments = [];
1777
1778    $.each(modelDataObj, function pimModelDataLoop(key) {
1779      var segment = key.split('Model')[1];
1780
1781      // Check if image data and model data exist
1782      if (key.indexOf('default') < 0 && modelDataObj[key] && imageDataObj['model' + segment]) {
1783        // the variable key here is 'ModelA'
1784        verifiedModelSegments.push(key);
1785      }
1786    });
1787
1788    return verifiedModelSegments;
1789  }
1790
1791  function reorderImageArray(productDataObject, firstImageSet, modelSegment) {
1792    var imageDataModel = productDataObject.imageSets;
1793    var orderedImageArray = [];
1794
1795    // store model group name
1796    var modelGroupName = modelSegment ? StringUtils.camelize(modelSegment, false) : 'model';
1797    var imageTypes = [modelGroupName, 'life', 'prod', 'ugc'];
1798
1799    // make sure the data arrays exist before trying to concat them together
1800    for (var i = 0; i < imageTypes.length; i++) {
1801      if (!imageDataModel[imageTypes[i]]) {
1802        imageDataModel[imageTypes[i]] = [];
1803      }
1804    }
1805
1806    if (firstImageSet.includes('model')) {
1807      orderedImageArray = orderedImageArray.concat(imageDataModel[modelGroupName], imageDataModel.prod, imageDataModel.ugc, imageDataModel.life);
1808    } else if (firstImageSet.includes('life')) {
1809      orderedImageArray = orderedImageArray.concat(imageDataModel.prod, imageDataModel[modelGroupName], imageDataModel.ugc, imageDataModel.life);
1810    } else if (firstImageSet.includes('ugc')) {
1811      orderedImageArray = orderedImageArray.concat(imageDataModel.ugc, imageDataModel.prod, imageDataModel[modelGroupName], imageDataModel.life);
1812    } else {
1813      orderedImageArray = orderedImageArray.concat(imageDataModel.prod, imageDataModel[modelGroupName], imageDataModel.ugc, imageDataModel.life);
1814    }
1815
1816    return orderedImageArray;
1817  }
1818
1819  function reorderImageSetToMatchDefaultModel(productDataObject, processedImageArray, isQuickview) {
1820    var imageDataModel = productDataObject.imageSets;
1821    var reorderedImageArray = processedImageArray;
1822
1823    if (isQuickview) {
1824      return processedImageArray;
1825    }
1826
1827    var verifiedModelSegments = getValidatedModelSegments(productDataObject);
1828
1829    if (verifiedModelSegments.length > 1) {
1830      var productModelData = productDataObject.productAttrs.ModelData;
1831      var selectedModelString = window.selectedModelSegment || '';
1832      var defaultModelSegment;
1833      var modelImageSegment;
1834
1835      if (verifiedModelSegments.includes(productModelData.defaultModel)) {
1836        defaultModelSegment = productModelData.defaultModel;
1837      } else {
1838        defaultModelSegment = verifiedModelSegments[0];
1839      }
1840
1841      productModelData.verifiedDataFlag = true;
1842      productModelData.availableModelImageSetSegments = verifiedModelSegments.slice();
1843
1844      // check to see if the selected model exisits and we have data for it
1845      if (imageDataModel[StringUtils.camelize(selectedModelString, false)] && productModelData[window.selectedModelSegment]) {
1846        modelImageSegment = window.selectedModelSegment;
1847      } else {
1848        modelImageSegment = defaultModelSegment;
1849        window.selectedModelSegment = defaultModelSegment;
1850      }
1851
1852      reorderedImageArray = reorderImageArray(productDataObject, window.firstImageSetType, modelImageSegment);
1853    } else {
1854      window.selectedModelSegment = '';
1855    }
1856
1857    return reorderedImageArray;
1858  }
1859
1860  function prepareImageDataModel(productDataObject) {
1861    var imageIndexObj = {};
1862
1863    $.each(productDataObject.imageSets, function preparingImageDataOuterEach(i, subArray) {
1864      $.each(subArray, function preparingImageDataInnerEach(n, img) {
1865        var typeExec = /(prod|life|ugc|model)([a-zA-Z]?)/g.exec(img.id) || ['prod', 'prod']; // When using fallback image, hardcode type and index group to prod
1866        var imgType = typeExec[1];
1867        var imgIdxGroup = typeExec[0];
1868
1869        img.isUGC = img.id.indexOf('ugc') > 0;
1870        img.imageId = img.id;
1871        imageIndexObj[imgIdxGroup + 'Idx'] = (imageIndexObj[imgIdxGroup + 'Idx'] || 0) + 1; // If index is null set to 0 + 1
1872        img.index = imageIndexObj[imgIdxGroup + 'Idx'];
1873        img.type = imgType;
1874      });
1875    });
1876
1877    productDataObject.imageDataModelPrepared = true;
1878  }
1879
1880  function getFaceoutImageSetType(url) {
1881    var faceoutImageSetType;
1882
1883    $.each(urlService.deconstruct(url).search, function urlParamLoop() {
1884      if (this.name === 'faceout') {
1885        faceoutImageSetType = this.value;
1886        return;
1887      }
1888    });
1889    return faceoutImageSetType;
1890  }
1891
1892  function getFirstImageSetType(url) {
1893    // check first from URL, then window.firstImageSetType
1894    var firstImageSetType;
1895    var faceoutVarFromUrl = getFaceoutImageSetType(url);
1896
1897    if (faceoutVarFromUrl) {
1898      firstImageSetType = faceoutVarFromUrl;
1899    } else if (window.firstImageSetType) {
1900      firstImageSetType = window.firstImageSetType;
1901    } else {
1902      firstImageSetType = 'prod';
1903    }
1904
1905    return firstImageSetType;
1906  }
1907
1908  function orderAndRouteImages(productDataObject, productId, $productSection, firstImageSetType, isQuickview) {
1909    var orderedImageArray = reorderImageArray(productDataObject, firstImageSetType);
1910    imageLoadRouter(orderedImageArray, productDataObject, productId, $productSection, isQuickview);
1911  }
1912
1913  function loadHandler(e, data) {
1914    var isQuickview = data.isQuickview || Utils.isQuickviewOpened;
1915    var $productSection = data.$productSection;
1916
1917    isReload = e.type === 'productPageImages:reload';
1918
1919    if (!isQuickview && Utils.hasProductMFEEnabled()) {
1920      return;
1921    }
1922
1923    if (!$productSection) {
1924      $productSection = isQuickview ? $(quickviewModalProductSectionSelectorClass) : $(productSectionSelectorClass);
1925    }
1926
1927    var productId = $productSection.data(productIdAttributeName);
1928    var productDataObject = Utils.getProductData(productId);
1929
1930    // If imageSets is empty add the "image not found" asset
1931    if ($.isEmptyObject(productDataObject.imageSets)) {
1932      productDataObject.imageSets = {};
1933      productDataObject.imageSets.prod = [{
1934        id: imageLoadHelper.getNoImageAvailableAssetImageId()
1935      }];
1936    }
1937
1938    var firstImageSetType = getFirstImageSetType(data.URL, $productSection);
1939
1940    window.firstImageSetType = window.firstImageSetType !== firstImageSetType ? firstImageSetType : window.firstImageSetType;
1941
1942    // if the imageDataModel hasn't yet been prepared (i.e. this is a fresh swatch), prepare it.
1943    if (!productDataObject.imageDataModelPrepared) {
1944      prepareImageDataModel(productDataObject);
1945    }
1946
1947    orderAndRouteImages(productDataObject, productId, $productSection, firstImageSetType, isQuickview);
1948  }
1949
1950  function imageLoadRouter(orderedImageArray, productDataObject, productId, $productSection, isQuickview) {
1951    var reorderedImageArray = reorderImageSetToMatchDefaultModel(productDataObject, orderedImageArray, isQuickview);
1952
1953    var imageLoaderObject = {
1954      processedImageArray: reorderedImageArray,
1955      imageDataModel: productDataObject.imageSets,
1956      productId: productId,
1957      $productSection: $productSection,
1958      isQuickview: isQuickview
1959    };
1960
1961    if (isReload) {
1962      messageBus.one('productMainImage:firstDownloadComplete', function messageBusFunction() {
1963        messageBus.trigger('productThumbnails:reload', imageLoaderObject);
1964      });
1965
1966      messageBus.trigger('productMainImage:reload', imageLoaderObject);
1967    } else {
1968      if (isQuickview && ($('.product-quickview__modal').attr('data-open') === 'false')) {
1969        $('.product-quickview__modal .product-quickview__content').empty();
1970        return;
1971      }
1972
1973      messageBus.trigger('productMainImage:load', imageLoaderObject);
1974    }
1975  }
1976
1977  var publicMembers = {
1978    listen: function listen() {
1979      messageBus.on('productPageImages:load', loadHandler);
1980      messageBus.on('productPageImages:reload', loadHandler);
1981    },
1982    reorderImageArray: reorderImageArray
1983  };
1984
1985  return publicMembers;
1986});
1987
1988redesign.define('productPartial/pdp_modelSelectorButton',['handlebars','dsPartial/button','dsHelper/concat','dsPartial/button-state'], function(Handlebars) {
1989
1990this["ANF"] = this["ANF"] || {};
1991this["ANF"]["templates"] = this["ANF"]["templates"] || {};
1992
1993Handlebars.registerPartial("pdp_modelSelectorButton", this["ANF"]["templates"]["pdp_modelSelectorButton"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
1994    var stack1, alias1=container.lambda;
1995
1996  return "    <span class=\"model-specs model-selector__button__model-specs\">\n        <span class=\"model-specs__height\">"
1997    + ((stack1 = alias1((depth0 != null ? depth0.modelHeight : depth0), depth0)) != null ? stack1 : "")
1998    + "</span>\n        <span class=\"model-specs__separator\">|</span>\n        <span class=\"model-specs__size\">"
1999    + ((stack1 = alias1((depth0 != null ? depth0.modelSize : depth0), depth0)) != null ? stack1 : "")
2000    + "</span>\n    </span>\n"
2001    + ((stack1 = container.invokePartial(partials["button-state"],depth0,{"name":"button-state","hash":{"active":true,"aria-label":(depth0 != null ? depth0.buttonLabel : depth0),"label":(depth0 != null ? depth0.buttonLabel : depth0),"state":"initial"},"data":data,"indent":"    ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
2002},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2003    var stack1;
2004
2005  return ((stack1 = container.invokePartial(partials.button,depth0,{"name":"button","hash":{"data-
2005prop":helpers.concat.call(depth0 != null ? depth0 : (container.nullContext || {}),"data-modal=",(depth0 != null ? depth0.modalID : depth0),{"name":"concat","hash":{},"data":data}),"class-list":"model-selector__button js-open-toaster","current-state":"initial","variant":"borderless-button","value":(depth0 != null ? depth0.buttonLabel : depth0),"type":"button"},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
2006},"usePartial":true,"useData":true}));
2007
2008return this["ANF"];
2009
2010});
2011redesign.define('productPartial/pdp_modelSelector',['handlebars','dsPartial/toaster','dsPartial/modal','dsPartial/button'], function(Handlebars) {
2012
2013this["ANF"] = this["ANF"] || {};
2014this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2015
2016Handlebars.registerPartial("pdp_modelSelector", this["ANF"]["templates"]["pdp_modelSelector"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
2017    var stack1;
2018
2019  return ((stack1 = container.invokePartial(partials.modal,depth0,{"name":"modal","hash":{"class-list":"model-selector__modal ds-override","variant":"headerless","id":(depth0 != null ? depth0.modalID : depth0),"title":"Models"},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
2020},"2":function(container,depth0,helpers,partials,data) {
2021    var stack1;
2022
2023  return "			<ul class=\"model-selector__model-card-list\">\n"
2024    + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.models : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2025    + "			</ul>\n";
2026},"3":function(container,depth0,helpers,partials,data) {
2027    var stack1;
2028
2029  return "				<li class=\"model-selector__model-card-container "
2030    + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.isSelected : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2031    + " \" data-segment=\""
2032    + container.escapeExpression(container.lambda((depth0 != null ? depth0.segment : depth0), depth0))
2033    + "\">\n"
2034    + ((stack1 = container.invokePartial(partials.button,depth0,{"name":"button","hash":{"class-list":"button ds-override model-selector__model-card no-linkify","variant":"borderless-button","type":"button"},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2035    + "				</li>\n";
2036},"4":function(container,depth0,helpers,partials,data) {
2037    return "selected";
2038},"6":function(container,depth0,helpers,partials,data) {
2039    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
2040
2041  return "						<img src=\""
2042    + alias2(alias1((depth0 != null ? depth0.src : depth0), depth0))
2043    + "\" alt=\""
2044    + alias2(alias1((depth0 != null ? depth0.name : depth0), depth0))
2045    + " wearing "
2046    + ((stack1 = alias1((depth0 != null ? depth0.size : depth0), depth0)) != null ? stack1 : "")
2047    + "\"/>\n						<div class=\"model-card__model-info\">\n							<div class=\"h4 model-card__name\">"
2048    + alias2(alias1((depth0 != null ? depth0.name : depth0), depth0))
2049    + "</div>\n							<div class=\"model-specs model-card__model-demensions\">\n								<span class=\"model-specs__height\">"
2050    + ((stack1 = alias1((depth0 != null ? depth0.height : depth0), depth0)) != null ? stack1 : "")
2051    + "</span>\n								<span class=\"model-specs__separator\">|</span>\n								<span class=\"model-specs__size\">"
2052    + ((stack1 = alias1((depth0 != null ? depth0.size : depth0), depth0)) != null ? stack1 : "")
2053    + "</span>\n							</div>\n						</div>\n";
2054},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2055    var stack1;
2056
2057  return "<div class=\"model-selector__toaster-container scope-1892\">\n"
2058    + ((stack1 = container.invokePartial(partials.toaster,depth0,{"name":"toaster","hash":{"class-list":"model-selector__toaster","direction":(depth0 != null ? depth0.toasterOpenDirection : depth0)},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2059    + "</div>\n";
2060},"usePartial":true,"useData":true}));
2061
2062return this["ANF"];
2063
2064});
2065redesign.define('productModules/product/productModelSelector',[
2066  'productModules/helpers/Utils',
2067  'productModules/product/productImageLoader',
2068  'coreClass/ANFImage',
2069  'productPartial/pdp_modelSelectorButton',
2070  'productPartial/pdp_modelSelector'
2071], function ProductModelSelector(
2072  Utils,
2073  imageLoader,
2074  ANFImage,
2075  productPartialPdpModelSelectorButton,
2076  productPartialPdpModelSelector
2077) {
2078  'use strict';
2079
2080  var messageBus = $(ANF);
2081
2082  var $button;
2083  var $buttonOverlay;
2084  var $toaster;
2085  var $productSection;
2086  var productId;
2087
2088  var publicMembers = {
2089    listen: function listen() {
2090      messageBus.on('productMainImage:load', onImageDataChanged);
2091      messageBus.on('productMainImage:reload', onImageDataChanged);
2092    },
2093
2094    bindEvents: function bindEvents() {
2095      $('.product-page-v2-modules').on('click', '.model-selector__model-card-list .model-selector__model-card-container', modelSelected);
2096      $('.product-page-v2-modules').on('click', 'button[data-modal*="model-selector-toaster"]', openM
2096odelToaster);
2097    }
2098  };
2099
2100  function onImageDataChanged(eventObj, eventData) {
2101    if (Utils.isQuickviewOpened) {
2102      return;
2103    }
2104
2105    // reset data and view
2106    $productSection = eventData.$productSection;
2107    productId = eventData.productId;
2108
2109    if ($button) {
2110      $button.remove();
2111      $button = null;
2112    }
2113
2114    if ($toaster) {
2115      $toaster.remove();
2116      $toaster = null;
2117    }
2118
2119    if ($buttonOverlay) {
2120      $buttonOverlay.remove();
2121      $buttonOverlay = null;
2122    }
2123
2124    messageBus.off('productMainImage:sliderInit', onSliderInitMainImage);
2125    messageBus.off('productMainImage:sliderAfterChange', onSliderAfterChangeMainImage);
2126
2127    var productModelDataObj = Utils.getProductData(productId).productAttrs.ModelData;
2128
2129    if (productModelDataObj && productModelDataObj.verifiedDataFlag) {
2130      var modelSelectorDataHBS = getModelSelectorDataHBS();
2131
2132      // add pdp_modelSelector.hbs to the DOM
2133      var buttonTemplate = productPartialPdpModelSelectorButton.templates.pdp_modelSelectorButton(modelSelectorDataHBS);
2134      var toasterTemplate = productPartialPdpModelSelector.templates.pdp_modelSelector(modelSelectorDataHBS);
2135
2136      $productSection.find('.product-main-images__wrapper').append(buttonTemplate);
2137      $productSection.append(toasterTemplate);
2138
2139      $button = $productSection.find('.model-selector__button');
2140      $buttonOverlay = $productSection.find('.model-selector-button--overlay');
2141      $toaster = $productSection.find('.model-selector__toaster');
2142
2143      // need to init DS js everytime to bind button and toaster
2144      ANF.globalV2.designsystem.init();
2145
2146      messageBus.on('productMainImage:sliderInit', onSliderInitMainImage);
2147      messageBus.on('productMainImage:sliderAfterChange', onSliderAfterChangeMainImage);
2148    }
2149  }
2150
2151  function onSliderInitMainImage() {
2152    if (Utils.isQuickviewOpened) {
2153      return;
2154    }
2155
2156    var mainImageType = $productSection.find('.product-main-images .slick-current .product-main-images__image').data('image-type');
2157    showHideButton(mainImageType === 'model');
2158  }
2159
2160  function onSliderAfterChangeMainImage(e, currentImageSlide) {
2161    if (Utils.isQuickviewOpened) {
2162      return;
2163    }
2164
2165    var mainImageType = $(currentImageSlide).find('.product-main-images__image').data('image-type');
2166    showHideButton(mainImageType === 'model');
2167  }
2168
2169  function showHideButton(isButtonShown) {
2170    if (isButtonShown) {
2171      $button.stop(true, true).fadeTo(500, 0.92);
2172      // add class to move the slider dots to the right if on mobile
2173      $productSection.find('.product-main-images .slick-dots').addClass('right-align');
2174    } else {
2175      $button.stop(true, true).fadeOut(500);
2176      $productSection.find('.product-main-images .slick-dots').removeClass('right-align');
2177    }
2178  }
2179
2180  function updateModelButtonInfo(defaultModel, productData) {
2181    var currentModel = Utils.getProductData(productData.productid).productAttrs.ModelData[defaultModel];
2182
2183    $button.find('.model-specs__height').html(currentModel.height);
2184    $button.find('.model-specs__size').html(currentModel.size);
2185
2186    $buttonOverlay.find('.model-specs__height').html(currentModel.height);
2187    $buttonOverlay.find('.model-specs__size').html(currentModel.size);
2188  }
2189
2190  function getModelSelectorDataHBS() {
2191    var productData = Utils.getProductData(productId);
2192    var defaultModelStr = window.selectedModelSegment || Utils.getValueFromObject(productData, 'productAttrs.ModelData.defaultModel', void 0);
2193    var selectedModel = productData.productAttrs.ModelData[defaultModelStr];
2194
2195    return {
2196      productId: productId,
2197      buttonLabel: 'Change Model',
2198      modelHeight: selectedModel.height,
2199      modelSize: selectedModel.size,
2200      modalID: 'model-selector-toaster__' + productId,
2201      toasterOpenDirection: window.innerWidth >= 700 ? 'from-left' : 'from-bottom',
2202      models: buildModelCardData()
2203    };
2204  }
2205
2206  function buildModelCardData() {
2207    var productData = Utils.getProductData(productId);
2208    var tempArray = [];
2209    var productModelDataObj = productData.productAttrs.ModelData;
2210    var verifiedModelSegments = productData.productAttrs.ModelData.availableModelImageSetSegments.slice(0);
2211
2212    for (var i = 0; i < verifiedModelSegments.length; i++) {
2213      var modelCard = productModelDataObj[verifiedModelSegments[i]];
2214      var modelSegmentLetter = verifiedModelSegments[i].split('Model')[1];
2215
2216      // we are using the second model image for this feature per business requirements hence the below [1]
2217      var imageSrc = ANFImage.instance()
2218        .setImageName(productData.imageSets['model' + modelSegmentLetter][1].id)
2219        .setWidth(96)
2220        .url;
2221
2222      modelCard.src = imageSrc;
2223      modelCard.segment = verifiedModelSegments[i];
2224      modelCard.isSelected = window.selectedModelSegment.indexOf(modelCard.segment) > -1;
2225
2226      tempArray = tempArray.concat(modelCard);
2227    }
2228
2229    return tempArray;
2230  }
2231
2232  function openModelToaster() {
2233    $(window).trigger('analytics.miscProductFeature', {'type': 'Change Model Button', 'message': 'Click'});
2234  }
2235
2236  function modelSelected(e) {
2237    var $selectedModel = $(e.currentTarget);
2238    var selectedModelSegment = window.selectedModelSegment = $selectedModel.attr('data-segment');
2239    $productSection = Utils.getParentProductSection($selectedModel);
2240    var productData = $productSection.data();
2241
2242    $productSection.find('.model-selector__toaster .model-selector__model-card-container.selected').removeClass('selected');
2243    $selectedModel.addClass('selected');
2244
2245    window.firstImageSetType = 'model';
2246
2247    var reorderedImageArray = imageLoader.reorderImageArray(Utils.getProductData(productData.productid), 'model', selectedModelSegment);
2248    var imageLoaderObject = {
2249      processedImageArray: reorderedImageArray,
2250      imageDataModel: productData.imageDataModel,
2251      productId: productData.productid,
2252      $productSection: $productSection
2253    };
2254
2255    updateModelButtonInfo(selectedModelSegment, productData);
2256
2257    messageBus.trigger('productThumbnails:reload', imageLoaderObject);
2258    messageBus.trigger('productPageMainImages:modelSelected', imageLoaderObject);
2259
2260    $(window).trigger('analytics.miscProductFeature', {'type': 'Model Image Click', 'action': $selectedModel.data('segment').split('Model')[1], 'message': $selectedModel.closest('ul').children().length});
2261  }
2262
2263  return publicMembers;
2264});
2265
2266redesign.define('productModules/helpers/featureSwitchHelper',[
2267  'productModules/helpers/Utils'
2268],
2269function FeatureSwitchHelper(Utils) {
2270  'use strict';
2271
2272  var messageBus = $(ANF);
2273
2274  var publicMembers = {
2275    featureTestSwitchValue: function featureTestSwitchValue(testValue, testSwitchName) {
2276      var storeAttribute = testValue || 0;
2277      var optimizely = window[testSwitchName] || false;
2278
2279      switch (storeAttribute) {
2280        case 1:
2281          return optimizely;
2282        case 2:
2283          return true;
2284        default:
2285          return false;
2286      }
2287    },
2288
2289    checkFeatureSwitchAndSplitTest: function checkFeatureSwitchAndSplitTest(featureAndSplitTestKey, cb) {
2290      var deferredResult = new $.Deferred();
2291      var featureFlagKey = 'flag.' + featureAndSplitTestKey;
2292      var splitTestKey = 'test.' + featureAndSplitTestKey;
2293      if (window.digitalData.get(featureFlagKey, false ) || window.digitalData.get(splitTestKey, false)) {
2294        deferredResult.resolve(true);
2295      } else {
2296        window.digitalData.subscribe(splitTestKey, function checkTestSegment(segment) {
2297          if (typeof segment !== 'undefined') {
2298            this.unsubscribe();
2299            deferredResult.resolve(segment);
2300          }
2301        });
2302      }
2303
2304      if (cb) {
2305        deferredResult.promise()
2306          .then(function heckSegment(isEnabled) {
2307            if (isEnabled) cb();
2308          });
2309      }
2310
2311      return deferredResult.promise();
2312    },
2313
2314    styleFitDesc: function styleFitDescSwitcher() {
2315      publicMembers.checkFeatureSwitchAndSplitTest('pdp-style-fit-desc-enabled', function styleFitDesc() {
2316        messageBus.trigger('styleFitDesc:init');
2317      });
2318    },
2319
2320    shortDescriptorSplitTest: function shortDescriptorSplitTest() {
2321      var subscriptionTimeout = null;
2322      if (window.digitalData.get('test.pdpHyperlinkDescriptor', false)) {
2323        messageBus.trigger('shortDescriptorTest:init', window.digitalData.get('test.pdpHyperlinkDescriptor', false));
2324      } else {
2325        var subscription = window.digitalData.subscribe('test.pdpHyperlinkDescriptor', function checkTestSegment(segment) {
2326          if (typeof segment !== 'undefined') {
2327            this.unsubscribe();
2328            clearTimeout(subscriptionTimeout);
2329            messageBus.trigger('shortDescriptorTest:init', segment);
2330          }
2331        });
2332
2333        subscriptionTimeout = setTimeout( function setSubscrptionTimeout() {
2334          subscription.unsubscribe();
2335        }, 5000);
2336      }
2337    },
2338
2339    stylitics: function styliticsSwitcher() {
2340      if (window.digitalData.get('flag.pdp-classic-outfitting-solution', false)) {
2341        messageBus.trigger('styliticsClassic:init');
2342      }
2343
2344      this.checkFeatureSwitchAndSplitTest('pdp-hotspots-outfitting-solution', function hasStyliticsV3() {
2345        if (!Utils.hasPDPMFEBelowTheFold()) {
2346          messageBus.trigger('styliticsV3:init');
2347        }
2348      });
2349    }
2350  };
2351
2352  return publicMembers;
2353});
2354
2355redesign.define('productServices/product/headerHeightCalculator',[],function HeaderHeightCalculator() {
2356  'use strict';
2357
2358  var headerPrimary = 'header.rs-header:not(:hidden)';
2359  var globalMessagingSystem = '.rs-nav__gms:not(:hidden)';// ESPOT above/below header
2360  var banner = '.intl-banner:not(:hidden)'; // Banner that may or may not exist
2361  var breadcrumb = '.upper-breadcrumb:not(:hidden)';
2362  var brandTabs = '.rs-nav__tabs-container:not(hidden)';
2363  var anfPasId = ANF.params.storeAttributes.pasList.anfPasId;
2364  var holPasId = ANF.params.storeAttributes.pasList.holPasId;
2365  var $rsHeaderWrapper = $('.rs-nav__wrapper');
2366
2367  // Returns the height of the header plus espots
2368  function getFullHeaderHeight(passId) {
2369    var gmsTotalHeight = 0;
2370
2371    // for multiple gms messages
2372    $.each($(globalMessagingSystem), function each(index, value) {
2373      gmsTotalHeight += $(value).height();
2374
2375      if (index === 0) {
2376        gmsTotalHeight -= $(window).scrollTop(); // if we have scrolled but not enough to hide top gms banner
2377      }
2378    });
2379    var defaultHeight = $(headerPrimary).height() + $(banner).height() + $(breadcrumb).height() + $(brandTabs).height();
2380    if (passId === anfPasId || $rsHeaderWrapper.length) {
2381      return defaultHeight + gmsTotalHeight;
2382    } else if (passId === holPasId) {
2383      return defaultHeight + $(globalMessagingSystem).height();
2384    }
2385
2386    return 0;
2387  }
2388
2389  var publicMembers = {
2390
2391    // Returns the height of the header section above the nav
2392    getFixedHeaderThresholdHeight: function getFixedHeaderThresholdHeight(passId, withBreadcrumb) {
2393      var breadcrumbHeight = withBreadcrumb ? $(breadcrumb).height() : 0;
2394      var initHeight = $(globalMessagingSystem).height() + $(banner).height() + $(brandTabs).height();
2395      if (passId === anfPasId || $rsHeaderWrapper.length) {
2396        return breadcrumbHeight + initHeight;
2397      } else if (passId === holPasId) {
2398        return initHeight;
2399      }
2400
2401      return 0;
2402    },
2403    // Returns the height of the header that will remain on the page when the user scrolls (the sticky header)
2404    getCondensedHeaderHeight: function getCondensedHeaderHeight() {
2405      return $(brandTabs).height() || 0;
2406    },
2407
2408    // Returns the current total height of all things header, should be the thing modules need most often
2409    // only sticky portion will be used if user is scrolled passed
2410    getCurrentHeaderHeight: function getCurrentHeaderHeight(passId) {
2411      var currentHeaderHeight = getFullHeaderHeight(passId);
2412      var fixedHeaderThresholdHeight = this.getFixedHeaderThresholdHeight(passId, false);
2413      var scrollTop = $(window).scrollTop();
2414      if (scrollTop > fixedHeaderThresholdHeight) { // if we're beyond the threshold at which the header should be fixed
2415        currentHeaderHeight = this.getCondensedHeaderHeight();
2416      }
2417      return currentHeaderHeight;
2418    }
2419  };
2420
2421  return publicMembers;
2422});
2423
2424redesign.define('productPartial/pdp_addToBagNotification',['handlebars','wcsHelper/i18n','dsPartial/icon-block','coreParti
2424al/freeShippingProgress','corePartial/checkoutButton','dsPartial/button'], function(Handlebars) {
2425
2426this["ANF"] = this["ANF"] || {};
2427this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2428
2429Handlebars.registerPartial("pdp_addToBagNotification", this["ANF"]["templates"]["pdp_addToBagNotification"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
2430    return "      <span class=\"product-page__atb-notification-warning\" data-property=\"GLB_ATB_NOTIFICATION_WARNING\">"
2431    + container.escapeExpression(helpers.i18n.call(depth0 != null ? depth0 : (container.nullContext || {}),"product.GLB_ATB_NOTIFICATION_WARNING",{"name":"i18n","hash":{},"data":data}))
2432    + "</span>\n";
2433},"3":function(container,depth0,helpers,partials,data) {
2434    var stack1;
2435
2436  return ((stack1 = container.invokePartial(partials.freeShippingProgress,depth0,{"name":"freeShippingProgress","data":data,"indent":"    ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
2437},"5":function(container,depth0,helpers,partials,data) {
2438    var stack1;
2439
2440  return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.props : depth0)) != null ? stack1.showCheckoutButton : stack1),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
2441},"6":function(container,depth0,helpers,partials,data) {
2442    var stack1;
2443
2444  return ((stack1 = container.invokePartial(partials.checkoutButton,depth0,{"name":"checkoutButton","data":data,"indent":"      ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
2445},"8":function(container,depth0,helpers,partials,data) {
2446    var stack1;
2447
2448  return "    "
2449    + ((stack1 = helpers.i18n.call(depth0 != null ? depth0 : (container.nullContext || {}),"product.GLB_VIEWBAG",{"name":"i18n","hash":{},"data":data})) != null ? stack1 : "")
2450    + "\n";
2451},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2452    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
2453
2454  return "<div class=\"product-page__atb-notification scope-1892\">\n  <span class=\"product-page__atb-notification-added h2\" data-property=\"GLB_ITEM_ADDED_TO_BAG\">"
2455    + container.escapeExpression(helpers.i18n.call(alias1,"product.GLB_ITEM_ADDED_TO_BAG",{"name":"i18n","hash":{},"data":data}))
2456    + "</span>\n  <div class=\"atb-notification-warning-wrapper\">\n"
2457    + ((stack1 = container.invokePartial(partials["icon-block"],depth0,{"name":"icon-block","hash":{"data-icon":"clock"},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2458    + "  </div>\n\n"
2459    + ((stack1 = helpers["with"].call(alias1,(depth0 != null ? depth0.freeShippingMessage : depth0),{"name":"with","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2460    + "\n"
2461    + ((stack1 = helpers["with"].call(alias1,(depth0 != null ? depth0.checkoutButton : depth0),{"name":"with","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2462    + "\n"
2463    + ((stack1 = container.invokePartial(partials.button,depth0,{"name":"button","hash":{"data-property":"GLB_VIEWBAG","class-list":"product-page__atb-notification-cta ds-override","href":(depth0 != null ? depth0.cartUrl : depth0),"variant":"secondary"},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2464    + "</div>\n";
2465},"usePartial":true,"useData":true}));
2466
2467return this["ANF"];
2468
2469});
2470redesign.define('productPartial/pdp_detailsAccordionContent',['handlebars','wcsHelper/i18n','wcsHelper/siteRegion','dsPartial/button'], function(Handlebars) {
2471
2472this["ANF"] = this["ANF"] || {};
2473this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2474
2475Handlebars.registerPartial("pdp_detailsAccordionContent", this["ANF"]["templates"]["pdp_detailsAccordionContent"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
2476    var stack1;
2477
2478  return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.imported : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
2479},"2":function(container,depth0,helpers,partials,data) {
2480    return "    <span>"
2481    + container.escapeExpression(helpers.i18n.call(depth0 != null ? depth0 : (container.nullContext || {}),"product.DETAILS_ACCORDION.PDP_DETAILS_IMPORTED_TEXT",{"name":"i18n","hash":{},"data":data}))
2482    + "</span>\n";
2483},"4":function(container,depth0,helpers,partials,data) {
2484    var stack1;
2485
2486  return "  <div class=\"anf-cares\">\n    <hr>\n    <p class=\"text-small\">\n        <span>"
2487    + ((stack1 = helpers.i18n.call(depth0 != null ? depth0 : (container.nullContext || {}),"product.DETAILS_ACCORDION.PDP_ACCORDION_DETAILS_CARES_PAGE",{"name":"i18n","hash":{},"data":data})) != null ? stack1 : "")
2488    + " </span>\n    </p>\n  </div>\n";
2489},"6":function(container,depth0,helpers,partials,data) {
2490    var stack1;
2491
2492  return "  <p class=\"let-us-know below-links text-small\">\n    <span class=\"title let-us-know__label\">\n      "
2493    + container.escapeExpression(helpers.i18n.call(depth0 != null ? depth0 : (container.nullContext || {}),"product.DETAILS_ACCORDION.GLB_LETUSKNOW",{"name":"i18n","hash":{},"data":data}))
2494    + "\n    </span>\n"
2495    + ((stack1 = container.invokePartial(partials.button,depth0,{"name":"button","hash":{"current-state":"initial","variant":"button-as-link","type":"button"},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2496    + "  </p>\n";
2497},"7":function(container,depth0,helpers,partials,data) {
2498    return "      <span data-state=\"initial\" data-hidden=\"false\">\n        "
2499    + container.escapeExpression(helpers.i18n.call(depth0 != null ? depth0 : (container.nullContext || {}),"product.DETAILS_ACCORDION.PDP_ARE_THESE_DETAILS_HELPFUL_LABEL",{"name":"i18n","hash":{},"data":data}))
2500    + "\n      </span>\n";
2501},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2502    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.escapeExpression, alias3=container.lambda;
2503
2504  return "<div class=\"details-info\">\n  <div class=\"h2 details-header\" data-property=\"GLB_DETAILS\">"
2505    + alias2(helpers.i18n.call(alias1,"product.DETAILS_ACCORDION.GLB_DETAILS",{"name":"i18n","hash":{},"data":data}))
2506    + "</div>\n  <div class=\"product-title\">"
2507    + alias2(alias3((depth0 != null ? depth0.productName : depth0), depth0))
2508    + "</div>\n  <p class=\"details__description\" itemprop=\"description\">\n    "
2509    + ((stack1 = alias3((depth0 != null ? depth0.longDescription : depth0), depth0)) != null ? stack1 : "")
2510    + "\n"
2511    + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.isChinaSite : depth0),{"name":"unless","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2512    + "  </p>\n</div>\n<div class=\"fabric-care\">\n  <div class=\"fabric-care__container\">\n    <div class=\"h4 fiber-content__label\"></div>\n    <ul class=\"fabric-care__list bullet-list\"></ul>\n  </div>\n</div>\n<hr>\n\n<p class=\"details__store-item-number text-small\" data-property=\"CAT_STOREITEMNUMBER\">\n    <span class=\"details__store-item-title\">"
2513    + alias2(helpers.i18n.call(alias1,"product.DETAILS_ACCORDION.CAT_STOREITEMNUMBER",{"name":"i18n","hash":{},"data":data}))
2514    + " </span>\n    <span class=\"number\">"
2515    + alias2(alias3((depth0 != null ? depth0.storeItemNumber : depth0), depth0))
2516    + "</span>\n</p>\n\n<p class=\"details__web-item-number text-small\" data-property=\"CAT_WEBITEMNUMBER\">\n    <span class=\"details__web-item-title\">"
2517    + alias2(helpers.i18n.call(alias1,"product.DETAILS_ACCORDION.CAT_WEBITEMNUMBER",{"name":"i18n","hash":{},"data":data}))
2518    + " </span>\n    <span class=\"number\">"
2519    + alias2(alias3((depth0 != null ? depth0.webItemNumber : depth0), depth0))
2520    + "</span>\n</p>\n\n"
2521    + ((stack1 = helpers.siteRegion.call(alias1,{"name":"siteRegion","hash":{"is":"EU"},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2522    + "\n"
2523    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showForsee : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
2524},"usePartial":true,"useData":true}));
2525
2526return this["ANF"];
2527
2528});
2529redesign.define('productPartial/pdp_garmentMeasurements',['handlebars','wcsHelper/i18n','dsPartial/tooltip'], function(Handlebars) {
2530
2531this["ANF"] = this["ANF"] || {};
2532this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2533
2534Handlebars.registerPartial("pdp_garmentMeasurements", this["ANF"]["templates"]["pdp_garmentMeasurements"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
2535    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.escapeExpression;
2536
2537  return "    <div class=\"hr above-garment-measurements\"></div>\n\n    <div class=\"garment-header\" data-variant=\"\">\n        <h3 class=\"h3\">"
2538    + alias2(helpers.i18n.call(alias1,"product.GARMENT_MEASUREMENT_LABELS.GARMENT_MEASUREMENTS",{"name":"i18n","hash":{},"data":data}))
2539    + "</h3>\n        <h4 class=\"h4\">"
2540    + alias2(helpers.i18n.call(alias1,"product.GARMENT_MEASUREMENT_LABELS.GARMENT_MEASUREMENTS",{"name":"i18n","hash":{},"data":data}))
2541    + "</h4>\n"
2542    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.baseSize : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2543    + "    </div>\n\n    <ul>\n"
2544    + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.measurements : depth0),{"name":"each","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2545    + "    </ul>\n\n";
2546},"2":function(container,depth0,helpers,partials,data) {
2547    var alias1=container.escapeExpression;
2548
2549  return "            <p class=\"garment-taken-from\">\n                <span>"
2550    + alias1(helpers.i18n.call(depth0 != null ? depth0 : (container.nullContext || {}),"product.GARMENT_MEASUREMENT_LABELS.BASE_MEASUREMENT_SIZE",{"name":"i18n","hash":{},"data":data}))
2551    + " "
2552    + alias1(container.lambda((depth0 != null ? depth0.baseSize : depth0), depth0))
2553    + "</span>\n            </p>\n";
2554},"4":function(container,depth0,helpers,partials,data) {
2555    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
2556
2557  return "            <li>\n                <div class=\"measurement-wrapper\">\n                    <span class=\"garment-label\">"
2558    + alias2(alias1((depth0 != null ? depth0.garmentLabel : depth0), depth0))
2559    + ":</span>\n                    <div class=\"garment-tooltip__wrapper\">\n"
2560    + ((stack1 = container.invokePartial(partials.tooltip,depth0,{"name":"tooltip","hash":{"variant":"small","reference-point":"parent","position":"top-right","id":(depth0 != null ? depth0.tooltipId : depth0)},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2561    + "                    </div>\n                </div>\n                <span class=\"garment-value\">"
2562    + alias2(alias1((depth0 != null ? depth0.garmentValue : depth0), depth0))
2563    + "\"</span>\n            </li>\n";
2564},"5":function(container,depth0,helpers,partials,data) {
2565    var alias1=container.lambda, alias2=container.escapeExpression;
2566
2567  return "                            <h3 class=\"h3\">"
2568    + alias2(alias1((depth0 != null ? depth0.tooltipHeader : depth0), depth0))
2569    + "</h3>\n                            <span>"
2570    + alias2(alias1((depth0 != null ? depth0.tooltipBody : depth0), depth0))
2571    + "</span>\n";
2572},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2573    var stack1;
2574
2575  return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.measurements : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
2576},"usePartial":true,"useData":true}));
2577
2578return this["ANF"];
2579
2580});
2581redesign.define('productPartial/reviews/pdp_noReviewsData',['handlebars'], function(Handlebars) {
2582
2583this["ANF"] = this["ANF"] || {};
2584this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2585
2586Handlebars.registerPartial("reviews/pdp_noReviewsData", this["ANF"]["templates"]["reviews/pdp_noReviewsData"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2587    return "<p class=\"reviews-no-results\" data-prop=\"PDP_NO_SEARCH_REVIEWS\">"
2588    + container.escapeExpression(container.lambda((depth0 != null ? depth0.label : depth0), depth0))
2589    + "</p>";
2590},"useData":true}));
2591
2592return this["ANF"];
2593
2594});
2595redesign.define('productPartial/quickview/pdp_quickviewPreload',['handlebars','dsPartial/loader'], function(Handlebars) {
2596
2597this["ANF"] = this["ANF"] || {};
2598this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2599
2600Handlebars.registerPartial("quickview/pdp_quickviewPreload", this["ANF"]["templates"]["quickview/pdp_quickviewPreload"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2601    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
2602
2603  return "<section class=\"product-page-v2-modules quickview-preload\" data-product-brand=\""
2604    + alias2(alias1((depth0 != null ? depth0.productBrand : depth0), depth0))
2605    + "\">\n  <section class=\"product-page__main-container scope-1892\">\n\n    <section class=\"product-page-images\">\n      <div class=\"product-thumbnails__container\"></div>\n\n      <div class=\"product-main-images__wrapper\">\n        <div class=\"product-main-images\">\n          "
2606    + ((stack1 = alias1((depth0 != null ? depth0.img : depth0), depth0)) != null ? stack1 : "")
2607    + "\n        </div>\n      </div>\n    </section>\n\n    <section class=\"product-page__info-container\">\n      <div class=\"product-page__info\">\n\n        <div class=\"product-page-info__title\">\n          <p class=\"short-description\">"
2608    + alias2(alias1((depth0 != null ? depth0.shortDescription : depth0), depth0))
2609    + "&nbsp;</p>\n          <div class=\"product-name product-name-font-size pdp-product-name\" data-brand=\""
2610    + alias2(alias1((depth0 != null ? depth0.productBrand : depth0), depth0))
2611    + "\">\n            <h1>"
2612    + ((stack1 = alias1((depth0 != null ? depth0.productName : depth0), depth0)) != null ? stack1 : "")
2613    + "</h1>\n          </div>\n        </div>\n\n        <div class=\"product-price-v2\">\n          <div class=\"product-price-v2__inner\">\n            "
2614    + ((stack1 = alias1((depth0 != null ? depth0.productPrice : depth0), depth0)) != null ? stack1 : "")
2615    + "\n          </div>\n        </div>\n        <div class=\"loader-container\">\n"
2616    + ((stack1 = container.invokePartial(partials.loader,depth0,{"name":"loader","hash":{"label":"loading...","variant":"spinner"},"data":data,"indent":"          ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2617    + "        </div>\n\n        <div class=\"product-page__atb-saves-wrapper\">\n          <div class=\"atb-wrapper\">\n\n            <div class=\"drop-down js-drop-down product-quantity-dropdown ds-override \" data-brand=\""
2618    + alias2(alias1((depth0 != null ? depth0.productBrand : depth0), depth0))
2619    + "\">\n              <select data-filled=\"true\" name=\"quantity\" id=\"product-quantity-dropdown-preload\" disabled>\n                <optgroup label=\"Qty\">\n                  <option value=\"1\">1</option>\n                </optgroup>\n              </select>\n              <label for=\"product-quantity-dropdown-preload\" class=\"placeholder\" data-property=\"GLB_QTY\">"
2620    + alias2(alias1((depth0 != null ? depth0.qtyLabel : depth0), depth0))
2621    + " </label>
2621\n              <span class=\"float-label\" data-property=\"GLB_QTY\">"
2622    + alias2(alias1((depth0 != null ? depth0.qtyLabel : depth0), depth0))
2623    + "</span>\n              <span class=\"arrow-icon\" aria-hidden=\"true\"></span>\n            </div>\n\n            <button class=\"button ds-override primary-button\" type=\"button\" disabled data-brand=\""
2624    + alias2(alias1((depth0 != null ? depth0.productBrand : depth0), depth0))
2625    + "\">\n              "
2626    + alias2(alias1((depth0 != null ? depth0.atbLabel : depth0), depth0))
2627    + "\n            </button>\n          </div>\n        </div>\n      </div>\n    </section>\n  </section>\n</section>";
2628},"usePartial":true,"useData":true}));
2629
2630return this["ANF"];
2631
2632});
2633redesign.define('productPartial/reviews/pdp_reviewFitSection',['handlebars','dsPartial/review-summary-content','dsPartial/icon-block'], function(Handlebars) {
2634
2635this["ANF"] = this["ANF"] || {};
2636this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2637
2638Handlebars.registerPartial("reviews/pdp_reviewFitSection", this["ANF"]["templates"]["reviews/pdp_reviewFitSection"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
2639    var stack1;
2640
2641  return ((stack1 = container.invokePartial(partials["review-summary-content"],depth0,{"name":"review-summary-content","fn":container.program(2, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
2642},"2":function(container,depth0,helpers,partials,data) {
2643    var stack1;
2644
2645  return ((stack1 = container.invokePartial(partials["icon-block"],depth0,{"name":"icon-block","hash":{"data-icon":"size"},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
2646},"3":function(container,depth0,helpers,partials,data) {
2647    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
2648
2649  return "            <div class=\"review-recommendation review-recommendation-fit\">\n                <span class=\"review-recommendation-most-recommended-pre\" data-property=\"GLB_MOST_RECOMMEND\">"
2650    + alias2(alias1(((stack1 = ((stack1 = (depth0 != null ? depth0.content : depth0)) != null ? stack1.fitRec : stack1)) != null ? stack1.fitRecText : stack1), depth0))
2651    + "</span>\n                <b class=\"recommendation-value\">"
2652    + alias2(alias1((depth0 != null ? depth0.fitRecommendation : depth0), depth0))
2653    + "</b>\n            </div>\n";
2654},"5":function(container,depth0,helpers,partials,data) {
2655    var stack1;
2656
2657  return ((stack1 = container.invokePartial(partials["review-summary-content"],depth0,{"name":"review-summary-content","fn":container.program(6, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
2658},"6":function(container,depth0,helpers,partials,data) {
2659    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
2660
2661  return "        <div class=\"review-recommendation review-recommendation-percentage\" data-property=\"GLB_RECOMMEND_THIS_ITEM\">\n            <b class=\"recommendation-value\">"
2662    + alias2(alias1((depth0 != null ? depth0.recommendedPercentage : depth0), depth0))
2663    + "% </b>"
2664    + alias2(alias1(((stack1 = ((stack1 = (depth0 != null ? depth0.content : depth0)) != null ? stack1.fitRec : stack1)) != null ? stack1.recPercentageText : stack1), depth0))
2665    + "\n        </div>\n";
2666},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2667    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
2668
2669  return ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showFitRecommendation : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2670    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showPercentage : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
2671},"usePartial":true,"useData":true}));
2672
2673return this["ANF"];
2674
2675});
2676redesign.define('productPartial/sizeGuide/pdp_sizeGuideCharts',['handlebars','wcsHelper/sizeGuide_tableCellClassNames','wcsHelper/sizeGuide_formatMeasurementUnit','wcsHelper/sizeGuide_zipRowData'], function(Handlebars) {
2677
2678this["ANF"] = this["ANF"] || {};
2679this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2680
2681Handlebars.registerPartial("sizeGuide/pdp_sizeGuideCharts", this["ANF"]["templates"]["sizeGuide/pdp_sizeGuideCharts"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data,blockParams,depths) {
2682    var stack1, alias1=container.lambda, alias2=container.escapeExpression, alias3=depth0 != null ? depth0 : (container.nullContext || {});
2683
2684  return "  <h3 class=\"size-guide__title h2\">"
2685    + alias2(alias1((depth0 != null ? depth0.name : depth0), depth0))
2686    + "</h3>\n  <p class=\"size-guide__description\">"
2687    + alias2(alias1((depth0 != null ? depth0.description : depth0), depth0))
2688    + "</p>\n\n  <div class=\"size-guide__table-scroll-wrapper\">\n    <div class=\"size-guide__table-scroll\">\n\n      <table class=\"size-guide__guide "
2689    + alias2(alias1(((stack1 = (data && data.root)) && stack1.defaultUnitClass), depth0))
2690    + "\">\n        <caption class=\"visually-hidden\">\n          "
2691    + ((stack1 = alias1(((stack1 = (depth0 != null ? depth0.header : depth0)) != null ? stack1.name : stack1), depth0)) != null ? stack1 : "")
2692    + "\n          "
2693    + alias2(alias1((depth0 != null ? depth0.name : depth0), depth0))
2694    + "\n          "
2695    + alias2(alias1(((stack1 = (data && data.root)) && stack1.sizeChartHeader), depth0))
2696    + "\n        </caption>
2696\n\n        <span class=\"size-guide__table-shadow size-guide__table-shadow-left size-guide__table-shadow--hide\"></span>\n\n        <thead>\n          <tr>\n            <th scope=\"col \"class=\"size-guide__primary-column\">\n                "
2697    + ((stack1 = alias1(((stack1 = (depth0 != null ? depth0.header : depth0)) != null ? stack1.name : stack1), depth0)) != null ? stack1 : "")
2698    + "\n            </th>\n\n"
2699    + ((stack1 = helpers.each.call(alias3,((stack1 = ((stack1 = (depth0 != null ? depth0.sizes : depth0)) != null ? stack1["0"] : stack1)) != null ? stack1.types : stack1),{"name":"each","hash":{},"fn":container.program(2, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"blockParams":blockParams})) != null ? stack1 : "")
2700    + "          </tr>\n        </thead>\n\n        <tbody>\n"
2701    + ((stack1 = helpers.each.call(alias3,(depth0 != null ? depth0.sizes : depth0),{"name":"each","hash":{},"fn":container.program(7, data, 1, blockParams, depths),"inverse":container.noop,"data":data,"blockParams":blockParams})) != null ? stack1 : "")
2702    + "        </tbody>\n\n        <span class=\"size-guide__table-shadow size-guide__table-shadow-right size-guide__table-shadow--hide\"></span>\n      </table>\n\n    </div>\n  </div>\n";
2703},"2":function(container,depth0,helpers,partials,data) {
2704    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
2705
2706  return "              <th scope=\"col\" class=\""
2707    + container.escapeExpression(helpers.sizeGuide_tableCellClassNames.call(alias1,(depth0 != null ? depth0.unit : depth0),(depth0 != null ? depth0.country : depth0),((stack1 = (data && data.root)) && stack1.defaultRegion),{"name":"sizeGuide_tableCellClassNames","hash":{},"data":data}))
2708    + "\">"
2709    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.country : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2710    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.measurement : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2711    + "</th>\n";
2712},"3":function(container,depth0,helpers,partials,data) {
2713    return container.escapeExpression(container.lambda((depth0 != null ? depth0.country : depth0), depth0));
2714},"5":function(container,depth0,helpers,partials,data) {
2715    var stack1;
2716
2717  return ((stack1 = container.lambda((depth0 != null ? depth0.measurement : depth0), depth0)) != null ? stack1 : "")
2718    + " "
2719    + container.escapeExpression(helpers.sizeGuide_formatMeasurementUnit.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.unit : depth0),{"name":"sizeGuide_formatMeasurementUnit","hash":{},"data":data}));
2720},"7":function(container,depth0,helpers,partials,data,blockParams,depths) {
2721    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
2722
2723  return ((stack1 = helpers.each.call(alias1,helpers.sizeGuide_zipRowData.call(alias1,((stack1 = blockParams[0][0]) != null ? stack1.types : stack1),{"name":"sizeGuide_zipRowData","hash":{},"data":data,"blockParams":blockParams}),{"name":"each","hash":{},"fn":container.program(8, data, 2, blockParams, depths),"inverse":container.noop,"data":data,"blockParams":blockParams})) != null ? stack1 : "");
2724},"8":function(container,depth0,helpers,partials,data,blockParams,depths) {
2725    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
2726
2727  return "              <tr "
2728    + ((stack1 = helpers["if"].call(alias1,(depths[1] != null ? depths[1].hasAltBackground : depths[1]),{"name":"if","hash":{},"fn":container.program(9, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"blockParams":blockParams})) != null ? stack1 : "")
2729    + ">\n"
2730    + ((stack1 = helpers.unless.call(alias1,blockParams[0][1],{"name":"unless","hash":{},"fn":container.program(11, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"blockParams":blockParams})) != null ? stack1 : "")
2731    + "\n"
2732    + ((stack1 = helpers.each.call(alias1,blockParams[0][0],{"name":"each","hash":{},"fn":container.program(13, data, 1, blockParams, depths),"inverse":container.noop,"data":data,"blockParams":blockParams})) != null ? stack1 : "")
2733    + "              </tr>\n";
2734},"9":function(container,depth0,helpers,partials,data) {
2735    return "class=\"alt-background-color\"";
2736},"11":function(container,depth0,helpers,partials,data,blockParams) {
2737    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
2738
2739  return "                  <th class=\"size-guide__primary-column\" scope=\"row\" rowspan=\""
2740    + alias2(alias1(((stack1 = ((stack1 = ((stack1 = ((stack1 = blockParams[2][0]) != null ? stack1.types : stack1)) != null ? stack1["0"] : stack1)) != null ? stack1.values : stack1)) != null ? stack1.length : stack1), depth0))
2741    + "\">\n                      "
2742    + alias2(alias1(((stack1 = blockParams[2][0]) != null ? stack1.size : stack1), depth0))
2743    + "\n                  </th>\n";
2744},"13":function(container,depth0,helpers,partials,data,blockParams) {
2745    var stack1, alias1=container.escapeExpression;
2746
2747  return "                  <td class=\""
2748    + alias1(helpers.sizeGuide_tableCellClassNames.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.unit : depth0),(depth0 != null ? depth0.country : depth0),((stack1 = (data && data.root)) && stack1.defaultRegion),{"name":"sizeGuide_tableCellClassNames","hash":{},"data":data}))
2749    + "\">\n                      "
2750    + alias1(container.lambda(((stack1 = blockParams[0][0]) != null ? stack1.value : stack1), depth0))
2751    + "\n                  </td>\n";
2752},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
2753    var stack1;
2754
2755  return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.sizeCharts : depth0),{"name":"each","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"blockParams":blockParams})) != null ? stack1 : "");
2756},"useData":true,"useDepths":true,"useBlockParams":true}));
2757
2758return this["ANF"];
2759
2760});
2761redesign.define('productPartial/sizeGuide/pdp_sizeGuideImages',['handlebars'], function(Handlebars) {
2762
2763this["ANF"] = this["ANF"] || {};
2764this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2765
2766Handlebars.registerPartial("sizeGuide/pdp_sizeGuideImages", this["ANF"]["templates"]["sizeGuide/pdp_sizeGuideImages"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
2767    var alias1=container.lambda, alias2=container.escapeExpression;
2768
2769  return "    <div class='size-guide-image'>\n        <img src='"
2770    + alias2(alias1((depth0 != null ? depth0.src : depth0), depth0))
2771    + "' data-image-id='"
2772    + alias2(alias1((depth0 != null ? depth0.imageId : depth0), depth0))
2773    + "' alt='"
2774    + alias2(alias1((depth0 != null ? depth0.altText : depth0), depth0))
2775    + "' itemprop='image'/>\n    </div>\n";
2776},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2777    var stack1;
2778
2779  return ((stack1 = helpers.blockHelperMissing.call(depth0,container.lambda((depth0 != null ? depth0.images : depth0), depth0),{"name":"images","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
2780},"useData":true}));
2781
2782return this["ANF"];
2783
2784});
2785redesign.define('productPartial/sizeGuide/pdp_sizeGuideRegionSelector',['handlebars','dsPartial/drop-down'], function(Handlebars) {
2786
2787this["ANF"] = this["ANF"] || {};
2788this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2789
2790Handlebars.registerPartial("sizeGuide/pdp_sizeGuideRegionSelector", this["ANF"]["templates"]["sizeGuide/pdp_sizeGuideRegionSelector"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2791    var stack1;
2792
2793  return "<div class='size-guide__region-selector'>\n"
2794    + ((stack1 = container.invokePartial(partials["drop-down"],depth0,{"name":"drop-down","hash":{"brand":(depth0 != null ? depth0.productBrand : depth0),"options":(depth0 != null ? depth0.options : depth0),"data-property":(depth0 != null ? depth0.dataProperty : depth0),"value":(depth0 != null ? depth0.value : depth0),"label":(depth0 != null ? depth0.label : depth0),"id":(depth0 != null ? depth0.id : depth0),"class-list":(depth0 != null ? depth0.classList : depth0)},"data":data,"indent":"  ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2795    + "</div>\n";
2796},"usePartial":true,"useData":true}));
2797
2798return this["ANF"];
2799
2800});
2801redesign.define('productPartial/sizeGuide/pdp_sizeGuideUnitToggle',['handlebars','dsPartial/toggle'], function(Handlebars) {
2802
2803this["ANF"] = this["ANF"] || {};
2804this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2805
2806Handlebars.registerPartial("sizeGuide/pdp_sizeGuideUnitToggle", this["ANF"]["templates"]["sizeGuide/pdp_sizeGuideUnitToggle"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2807    var stack1;
2808
2809  return "<div class='size-guide__unit-toggle-wrapper'>\n\n  <div class=\"visually-hidden\" id=\"size-guide-legend\" data-property=\"SIZE_GUIDE_UNIT_TOGGLE_LABEL\">\n    "
2810    + container.escapeExpression(container.lambda(((stack1 = (data && data.root)) && stack1.toggleLabel), depth0))
2811    + "\n  </div>\n\n"
2812    + ((stack1 = container.invokePartial(partials.toggle,depth0,{"name":"toggle","hash":{"brand":(depth0 != null ? depth0.productBrand : depth0),"labelled-by":"size-guide-legend","class-list":(depth0 != null ? depth0.classList : depth0),"toggle-block":(depth0 != null ? depth0.toggleBlock : depth0)},"data":data,"indent":"  ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2813    + "</div>\n";
2814},"usePartial":true,"useData":true}));
2815
2816return this["ANF"];
2817
2818});
2819redesign.define('productPartial/pdp_productSizeMessaging',['handlebars'], function(Handlebars) {
2820
2821this["ANF"] = this["ANF"] || {};
2822this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2823
2824Handlebars.registerPartial("pdp_productSizeMessaging", this["ANF"]["templates"]["pdp_productSizeMessaging"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2825    var stack1, alias1=container.lambda;
2826
2827  return "<h3 class=\"size-messaging__header\">"
2828    + ((stack1 = alias1((depth0 != null ? depth0.header : depth0), depth0)) != null ? stack1 : "")
2829    + "</h3>\n<div class=\"size-messaging__subtitle\">"
2830    + ((stack1 = alias1((depth0 != null ? depth0.subtitle : depth0), depth0)) != null ? stack1 : "")
2831    + "</div>\n<div class=\"size-messaging__message-body\">"
2832    + ((stack1 = alias1((depth0 != null ? depth0.messaging : depth0), depth0)) != null ? stack1 : "")
2833    + "</div>";
2834},"useData":true}));
2835
2836return this["ANF"];
2837
2838});
2839redesign.define('productPartial/stylitics/pdp_styliticsWidget',['handlebars','wcsHelper/i18n'], function(Handlebars) {
2840
2841this["ANF"] = this["ANF"] || {};
2842this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2843
2844Handlebars.registerPartial("stylitics/pdp_styliticsWidget", this["ANF"]["templates"]["stylitics/pdp_styliticsWidget"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2845    var alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.escapeExpression;
2846
2847  return "<h2 class=\"stylitics-title h1\" data-property=\"PDP_STYLITICS-WIDGET-TITLE\">\n  "
2848    + alias2(helpers.i18n.call(alias1,"product.PDP_STYLITICS_WIDGET_TITLE",{"name":"i18n","hash":{},"data":data}))
2849    + "\n</h2>\n<span class=\"stylitics-subtitle\">\n  "
2850    + alias2(helpers.i18n.call(alias1,"product.PDP_STYLITICS_WIDGET_SUBTITLE",{"name":"i18n","hash":{},"data":data}))
2851    + "\n</span>\n<span class=\"stylitics-mobile-tip\">\n  "
2852    + alias2(helpers.i18n.call(alias1,"product.PDP_STYLITICS_WIDGET_MOBILE_TIP",{"name":"i18n","hash":{},"data":data}))
2853    + "\n</span>\n<div id=\"stylitics-widget\" data-aui=\"stylitics\"></div>";
2854},"useData":true}));
2855
2856return this["ANF"];
2857
2858});
2859redesign.define('productPartial/stylitics/pdp_styliticsWidgetIcons',['handlebars','dsPartial/icon-block'], function(Handlebars) {
2860
2861this["ANF"] = this["ANF"] || {};
2862this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2863
2864Handlebars.registerPartial("stylitics/pdp_styliticsWidgetIcons", this["ANF"]["templates"]["stylitics/pdp_styliticsWidgetIcons"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
2865    return "";
2866},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2867    var stack1;
2868
2869  return ((stack1 = container.invokePartial(partials["icon-block"],depth0,{"name":"icon-block","hash":{"data-icon":(depth0 != null ? depth0.iconKey : depth0)},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2870    + "\n";
2871},"usePartial":true,"useData":true}));
2872
2873return this["ANF"];
2874
2875});
2876redesign.define('productPartial/pdp_measurements',['handlebars','dsPartial/tooltip'], function(Handlebars) {
2877
2878this["ANF"] = this["ANF"] || {};
2879this["ANF"]["templates"] = this["ANF"]["templates"] || {};
2880
2881Handlebars.registerPartial("pdp_measurements", this["ANF"]["templates"]["pdp_measurements"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
2882    var stack1;
2883
2884  return "    <div class=\"measurements\">\n        <ul>\n"
2885    + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.measurements : depth0),{"name":"each","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
2886    + "        </ul>\n    </div>\n";
2887},"2":function(container,depth0,helpers,partials,data) {
2888    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
2889
2890  return "                <li>\n                    <div class=\"measurement-wrapper\">
2890\n                        <span class=\"measurement-label\">"
2891    + alias2(alias1((depth0 != null ? depth0.lensMeasurementsLabel : depth0), depth0))
2892    + ":</span>\n                        <div class=\"measurement-tooltip__wrapper\">\n"
2893    + ((stack1 = container.invokePartial(partials.tooltip,depth0,{"name":"tooltip","hash":{"variant":"small","reference-point":"parent","position":"top-right","id":(depth0 != null ? depth0.tooltipId : depth0)},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
2894    + "                        </div>\n                    </div>\n                    <span class=\"measurement-value\">"
2895    + alias2(alias1((depth0 != null ? depth0.lensMeasurementsValue : depth0), depth0))
2896    + " mm</span>\n                </li>\n";
2897},"3":function(container,depth0,helpers,partials,data) {
2898    var alias1=container.lambda, alias2=container.escapeExpression;
2899
2900  return "                                <h3 class=\"h3\">"
2901    + alias2(alias1((depth0 != null ? depth0.tooltipHeader : depth0), depth0))
2902    + "</h3>\n                                <span>"
2903    + alias2(alias1((depth0 != null ? depth0.tooltipBody : depth0), depth0))
2904    + "</span>\n";
2905},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
2906    var stack1;
2907
2908  return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.measurements : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
2909},"usePartial":true,"useData":true}));
2910
2911return this["ANF"];
2912
2913});
2914redesign.define('productServices/product/template',[
2915  'productPartial/pdp_addToBagNotification',
2916  'productPartial/pdp_detailsAccordionContent',
2917  'productPartial/pdp_garmentMeasurements',
2918  'productPartial/reviews/pdp_noReviewsData',
2919  'productPartial/quickview/pdp_quickviewPreload',
2920  'productPartial/reviews/pdp_reviewFitSection',
2921  'productPartial/sizeGuide/pdp_sizeGuideCharts',
2922  'productPartial/sizeGuide/pdp_sizeGuideImages',
2923  'productPartial/sizeGuide/pdp_sizeGuideRegionSelector',
2924  'productPartial/sizeGuide/pdp_sizeGuideUnitToggle',
2925  'productPartial/pdp_productSizeMessaging',
2926  'dsPartial/error-message',
2927  'productPartial/stylitics/pdp_styliticsWidget',
2928  'productPartial/stylitics/pdp_styliticsWidgetIcons',
2929  'productPartial/pdp_measurements'
2930], function TemplateService(
2931  productPartialPdpAddToBagNotification,
2932  productPartialPdpDetailsAccordionContent,
2933  productPartialPdpGarmentMeasurements,
2934  productPartialReviewsPdpNoReviewsData,
2935  productPartialQuickviewPdpQuickviewPreload,
2936  productPartialReviewsPdpReviewFitSection,
2937  productPartialSizeGuidePdpSizeGuideCharts,
2938  productPartialSizeGuidePdpSizeGuideImages,
2939  productPartialSizeGuidePdpSizeGuideRegionSelector,
2940  productPartialSizeGuidePdpSizeGuideUnitToggle,
2941  productPartialPdpProductSizeMessaging,
2942  dsPartialErrorMessage,
2943  productPartialPdpStyliticsWidget,
2944  productPartialPdpStyliticsWidgetIcons,
2945  productPartialPdpMeasurements
2946) {
2947  'use strict';
2948
2949  /*
2950   * Keep this alphabetized
2951   */
2952  var templateMap = {
2953    addToBagNotification: productPartialPdpAddToBagNotification.templates.pdp_addToBagNotification,
2954    detailsAccordion: productPartialPdpDetailsAccordionContent.templates.pdp_detailsAccordionContent,
2955    errorMessage: dsPartialErrorMessage.templates['error-message'],
2956    garmentMeasurements: productPartialPdpGarmentMeasurements.templates.pdp_garmentMeasurements,
2957    measurements: productPartialPdpMeasurements.templates.pdp_measurements,
2958    noReviewsData: productPartialReviewsPdpNoReviewsData.templates['reviews/pdp_noReviewsData'],
2959    productSizeMessaging: productPartialPdpProductSizeMessaging.templates.pdp_productSizeMessaging,
2960    quickviewPreload: productPartialQuickviewPdpQuickviewPreload.templates['quickview/pdp_quickviewPreload'],
2961    reviewFitSection: productPartialReviewsPdpReviewFitSection.templates['reviews/pdp_reviewFitSection'],
2962    sizeGuideCharts: productPartialSizeGuidePdpSizeGuideCharts.templates['sizeGuide/pdp_sizeGuideCharts'],
2963    sizeGuideImages: productPartialSizeGuidePdpSizeGuideImages.templates['sizeGuide/pdp_sizeGuideImages'],
2964    sizeGuideRegionSelector: productPartialSizeGuidePdpSizeGuideRegionSelector.templates['sizeGuide/pdp_sizeGuideRegionSelector'],
2965    sizeGuideUnitToggle: productPartialSizeGuidePdpSizeGuideUnitToggle.templates['sizeGuide/pdp_sizeGuideUnitToggle'],
2966    styliticsWidget: productPartialPdpStyliticsWidget.templates['stylitics/pdp_styliticsWidget'],
2967    styliticsWidgetIcon: productPartialPdpStyliticsWidgetIcons.templates['stylitics/pdp_styliticsWidgetIcons']
2968  };
2969
2970  function renderTemplate(name, data) {
2971    return templateMap[name](data);
2972  }
2973
2974  return {
2975    renderTemplate: renderTemplate
2976  };
2977});
2978
2979redesign.define('productIntegrations/stylitics',[
2980  'productServices/product/headerHeightCalculator',
2981  'anfUtil/constants',
2982  'productModules/helpers/Utils',
2983  'productServices/product/template'
2984],
2985function Stylitics(headerHeightCalculator, coreConstants, Utils, templateService) {
2986  'use strict';
2987
2988  var messageBus = $(ANF);
2989  var quickviewButtonClass = 'product-quickview__button';
2990  var styliticsItemPanel = '.stylitics-widget-item-container';
2991  var jumpLinkButtonSelectorClass = '.stylitics-jumplink';
2992  var widgetWrapperSelectorClass = '.stylitics-widget-wrapper';
2993  var containerSelector = '.stylitics-container-js';
2994  var widgetTargetIdSelector = '#stylitics-widget';
2995
2996  var styliticsBrandToThemeBrand = {
2997    'ANF': 'anf',
2998    'HCo.': 'hol',
2999    'ANF-Kids': 'kids',
3000    'Glh': 'gh',
3001    'st': 'st'
3002  };
3003
3004  function loadStylitics() {
3005    var $productSection = $('.product-page-v2-modules');
3006    var $styliticsWidgetWrapper = $(widgetWrapperSelectorClass);
3007
3008    $styliticsWidgetWrapper.prepend($(templateService.renderTemplate('styliticsWidget')));
3009    var styliticsWidgetJSUrl = '//widget.stylitics.com/v2/widget.js';
3010
3011    window.$LAB.script(styliticsWidgetJSUrl).wait(function styliticsRetrieved() {
3012      initStylitics($productSection);
3013    });
3014
3015    messageBus.on('productPageInfo:swatchSelected mfe:SwatchSelected', handleWidgetRefresh);
3016  }
3017
3018  function initStylitics($productSection) {
3019    var productId = $productSection.data('productid');
3020    var productData = Utils.getProductData(productId);
3021
3022    var options = {
3023      api: {
3024        total: 3,
3025        item_number: productData.kicId
3026      },
3027      display: {
3028        cols: 3,
3029        ctaText: coreConstants.anf('messaging.catalogV2.STYLITICS.widgetCTAText') || '',
3030        outfitBg: 'transparent',
3031        clickToReveal: true
3032      }
3033    };
3034    var brandMap = {
3035      'anf': 'abercrombie',
3036      'kids': 'abercrombie',
3037      'hol': 'hollister',
3038      'gh': 'hollister',
3039      'st': 'hollister'
3040    };
3041    var brand = $('header').data('brand');
3042    var styliticsBrand = brandMap[brand];
3043
3044    if (brand === 'gh') {
3045      options.api.tags = 'gillyhicks_outfit';
3046    }
3047
3048    // The StyliticsWidget comes from a script loaded for a 3rd party post page load.
3049    /* eslint-disable-next-line no-undef */
3050    var styliticsWidget = new StyliticsWidget(styliticsBrand, 'stylitics-widget', options);
3051
3052    $(widgetTargetIdSelector).data('widget-instance', styliticsWidget);
3053    styliticsWidget.load(onLoadCustom);
3054  }
3055
3056  function onLoadCustom(outfits) {
3057    toggleCustomComponents(outfits);
3058    setupQuickviewButtons(outfits);
3059    $(ANF).trigger('stylitics:initIntersectObserver');
3060    $(ANF).trigger('stylitics:wireAnalyticTriggers');
3061    return outfits;
3062  }
3063
3064  function toggleCustomComponents(outfits) {
3065    var $jumpLinkButton = $(jumpLinkButtonSelectorClass);
3066    var $widgetContainer = $(containerSelector);
3067
3068    if (outfits.length > 2) {
3069      $jumpLinkButton.removeClass('hide');
3070      $widgetContainer.removeClass('hide');
3071    } else {
3072      $jumpLinkButton.addClass('hide');
3073      $widgetContainer.addClass('hide');
3074    }
3075  }
3076
3077  function setupQuickviewButtons(outfits) {
3078    $.each(outfits, function quickviewLinkOutfitLoop(i, outfit) {
3079      $.each(outfit.items, function outfitItemLoop(idx, item) {
3080        var $itemCTAPanel = $(styliticsItemPanel + '[data-item-id="' + item.item_id + '"]');
3081        if (item.hasOwnProperty('other_client_item_ids')) {
3082          var itemIdObject = item.other_client_item_ids;
3083          $itemCTAPanel.addClass(quickviewButtonClass);
3084          $itemCTAPanel.attr({
3085            'data-collectionid': itemIdObject.hasOwnProperty('collection_ids') ? itemIdObject.collection_ids[0] : 0,
3086            'data-seq': itemIdObject.hasOwnProperty('csequence_ids') ? itemIdObject.csequence_ids[0] : 0,
3087            'data-productid': itemIdObject.hasOwnProperty('product_ids') ? itemIdObject.product_ids[0] : 0,
3088            'data-product-brand': styliticsBrandToThemeBrand[item.brand]
3089          });
3090        }
3091      });
3092    });
3093  }
3094
3095  function handleWidgetRefresh(_e, $selectedSwatch, $productSection, productId) {
3096    if (!Utils.isQuickviewOpened) {
3097      var selectedKIC = Utils.getProductData(productId).kicId;
3098      var $widgetTarget = $(widgetTargetIdSelector);
3099      var styliticsWidget = $widgetTarget.data('widget-instance');
3100
3101      var currentHeight = $widgetTarget.height();
3102      $widgetTarget.height(currentHeight);
3103
3104      styliticsWidget.refresh(selectedKIC, function styliticsSwatchRefresh(outfits) {
3105        $widgetTarget.height('auto');
3106        onLoadCustom(outfits);
3107      });
3108    }
3109  }
3110
3111  var publicMembers = {
3112    'listen': function listen() {
3113      messageBus.on('styliticsClassic:init', loadStylitics);
3114    }
3115  };
3116
3117  return publicMembers;
3118});
3119
3120redesign.define('productIntegrations/styliticsAnalytics',[],
3121  function StyliticsAnalytics() {
3122    'use strict';
3123
3124    var jumplinkSelectorClass = '.stylitics-jumplink';
3125    var widgetIdSelector = '#stylitics-widget';
3126    var outfitInnerWrapperSelectorClass = '.stylitics-widget-outfit-inner';
3127
3128    return function StytlicsAnalyticsClosure(productIntersectionObserver) {
3129      function wireIntersectionObserver() {
3130        var $styliticsWidget = $(widgetIdSelector);
3131        var styliticsWidgetObserver = new productIntersectionObserver.IntersectionObserver(
3132          function productIntersectionObserverCallback(entries) {
3133            for (var i = 0, len = entries.length; i < len; i++) {
3134              var styliticsWidget = entries[i];
3135
3136              if (styliticsWidget.isIntersecting) {
3137                styliticsWidgetObserver.unobserve(styliticsWidget.target);
3138                $(window).trigger('analytics.scrollReachIndicator', {'name': 'Scrolled to Stylitics Module'});
3139              }
3140            }
3141          },
3142          {
3143            threshold: 1
3144          }
3145        );
3146        styliticsWidgetObserver.observe($styliticsWidget[0]);
3147      }
3148
3149      function viewMoreOutfitsClickTrigger() {
3150        $(window).trigger('analytics.miscFeatureSessionCap', {'type': 'Stylitics', 'action': 'click', 'message': 'shop this link'});
3151      }
3152
3153      function jumplinkClickAnalyticTrigger() {
3154        $(window).trigger('analytics.miscFeature', {type: 'Stylitics', action: 'click', message: 'how to style this'});
3155      }
3156
3157      function wireUserInteractionTriggers() {
3158        $(widgetIdSelector).on('click', outfitInnerWrapperSelectorClass, viewMoreOutfitsClickTrigger);
3159      }
3160
3161      var publicMembers = {
3162        'listen': function listen() {
3163          $(ANF).on('stylitics:wireAnalyticTriggers', wireUserInteractionTriggers);
3164          $(ANF).on('stylitics:initIntersectObserver', wireIntersectionObserver);
3165        },
3166        'bindEvents': function bindEvents() {
3167          $(jumplinkSelectorClass).on('click select', jumplinkClickAnalyticTrigger);
3168        }
3169      };
3170
3171      return publicMembers;
3172    };
3173  }
3174);
3175
3176redesign.define('productModules/helpers/productIntersectionObserver',[], function productIntersectionObserver() {
3177  'use strict';
3178
3179  var helpers = {
3180    create: function create(getName, getValue, isConfigurable) {
3181      if (Object.hasOwnProperty(this, getName) && Object.getOwnPropertyDescriptor(this, getName).configurable) {
3182        delete this[getName];
3183      }
3184
3185      Object.defineProperty(this, getName, {
3186        get: getValue,
3187        configurable: isConfigurable || false
3188      });
3189    }
3190  };
3191
3192  return helpers;
3193});
3194
3195redesign.define('productIntegrations/styliticsV3',[
3196  'productModules/helpers/Utils',
3197  'productServices/product/template'
3198],
3199function StyliticsV3(Utils, templateService) {
3200  'use strict';
3201
3202  var messageBus = $(ANF);
3203  var widgetWrapperSelector = '.stylitics-widget-wrapper';
3204  var containerSelector = '.stylitics-container-js';
3205  var widgetCtaEyeIconContainerSelector = '.stylitics-view-items-cta-icon';
3206  var productSectionSelector = '.product-page-v2-modules';
3207  var styliticsModalBadgeContainerSelector = '.stylitics-bundle-badge-modal';
3208  var styliticsModalBadgeContentClass = 'stylitics-modal-badge-js';
3209  var styliticsBadgeContainerSelector = '.stylitics-bundle-badge';
3210  var styliticsBadgeContentClass = 'stylitics-bundle-badge-js';
3211  var widgetTargetIdSelector = '#stylitics-widget';
3212  var viewItemsButton = '.stylitics-view-items-button';
3213  var brandMap = {
3214    'anf': 'abercrombie',
3215    'kids': 'abercrombie',
3216    'hol': 'hollister',
3217    'gh': 'hollister',
3218    'st': 'hollister'
3219  };
3220
3221  var styliticsBrandToThemeBrand = {
3222    'ANF': 'anf',
3223    'HCo.': 'hol',
3224    'ANF-Kids': 'kids',
3225    'Glh': 'gh',
3226    'st': 'st'
3227  };
3228
3229  function listen() {
3230    messageBus.on('styliticsV3:init', loadStylitics);
3231  }
3232
3233  function loadStylitics() {
3234    if (Utils.isExternalUser()) {
3235      return;
3236    }
3237
3238    var $productSection = $(productSectionSelector);
3239    var $styliticsWidgetWrapper = $(widgetWrapperSelector);
3240    var $widgetContainer = $(containerSelector);
3241
3242    if ($styliticsWidgetWrapper.length === 0 || $widgetContainer.length === 0) {
3243      return;
3244    }
3245    if (Utils.getANFObject().params.env.region === 'EU') {
3246      $styliticsWidgetWrapper.addClass('hide-price');
3247    }
3248
3249    var styliticsWidgetJSUrl = '//web-assets.stylitics.com/v3-hotspots/latest/hotspots.release.js';
3250    $styliticsWidgetWrapper.prepend($(templateService.renderTemplate('styliticsWidget')));
3251    window.$LAB.script(styliticsWidgetJSUrl).wait(function styliticsRetrieved() {
3252      initStylitics($productSection);
3253    });
3254
3255    messageBus.on('productPageInfo:swatchSelected mfe:SwatchSelected', handleWidgetRefresh);
3256  }
3257
3258  function initStylitics($productSection) {
3259    var productId = $productSection.data('productid');
3260    var params = buildParameters(productId);
3261    var productData = Utils.getProductData(productId);
3262
3263    var showStylitics = shouldShowStylitics(productData.kicId);
3264
3265    if ($(widgetTargetIdSelector).length === 0) {
3266      return;
3267    }
3268
3269    /* eslint-disable-next-line no-undef */
3270    var styliticsWidget = new StyliticsHotspotsWidget(params.styliticsBrand, 'stylitics-widget', params.options);
3271
3272    $(widgetTargetIdSelector).data('widget-instance-v3', styliticsWidget);
3273
3274    styliticsWidget.on('mount', 'bundle', onLoadSingleBundle);
3275    styliticsWidget.on('mount', 'bundles', sendBundlesMfe);
3276    styliticsWidget.on('mount', 'item', replaceImages);
3277    styliticsWidget.override('click', 'item', handleStyliticsItemClick);
3278    if (showStylitics) {
3279      styliticsWidget.start();
3280    }
3281  }
3282
3283  function shouldShowStylitics(selectedKIC) {
3284    var departmentId = selectedKIC.split(/[_-]/)[1];
3285    var dressOrRomperDepartment = '359';
3286    var hideStyliticsHcoDressesAndRompers = window.digitalData.get('test.hideStyliticsHcoDressesAndRompers') === true;
3287
3288    return !(hideStyliticsHcoDressesAndRompers && departmentId === dressOrRomperDepartment);
3289  }
3290
3291  function buildParameters(productId) {
3292    var productData = Utils.getProductData(productId);
3293    var options = {
3294      api: {
3295        min: 3,
3296        max: 3,
3297        item_number: productData.kicId
3298      },
3299      display: {
3300        clickableCarouselDots: true,
3301        swipeableCarouselDots: true,
3302        disableMnM: true,
3303        bundleBackgroundColor: 'transparent'
3304      },
3305      price: {
3306        hideDoubleZeroCents: true
3307      },
3308      customer: {
3309        locale: Utils.getANFObject().params.storeAttributes.STYLITICS_LOCALE
3310      },
3311      text: {
3312        viewDetailsCTA: Utils.getANFObject().messaging.product.PDP_STYLITICS_WIDGET_CTA
3313      }
3314    };
3315    var brand = $('header').data('brand');
3316    var styliticsBrand = brandMap[brand];
3317    if (brand === 'gh') {
3318      options.api.tags = 'gillyhicks_outfit';
3319    }
3320
3321    if (Utils.getANFObject().params.env.region === 'UK') {
3322      styliticsBrand += '_uk';
3323    }
3324
3325    if (Utils.getANFObject().params.env.region === 'EU') {
3326      styliticsBrand += '_eu';
3327    }
3328
3329    return {
3330      styliticsBrand: styliticsBrand,
3331      options: options
3332    };
3333  }
3334
3335  function onLoadSingleBundle(outfit) {
3336    var hasModelBadge = outfit.bundle['on-model-image'];
3337
3338    setupCtaButton(outfit.element);
3339
3340    if (hasModelBadge) {
3341      var text = Utils.getANFObject().messaging.product.PDP_STYLITICS_WIDGET_BADGE_TEXT;
3342      var $element = $(outfit.element);
3343
3344      cardBadgeSetup($element, text);
3345      modalBadgeSetup($element, text);
3346    }
3347  }
3348
3349  function sendBundlesMfe(outfits) {
3350    var $widgetContainer = $(containerSelector);
3351
3352    if ($widgetContainer.length === 0) {
3353      return;
3354    }
3355
3356    var canPost = typeof window !== 'undefined' && window.postMessage && window.addEventListener;
3357
3358    if (canPost) {
3359      window.digitalData.set('bundles', outfits.bundles);
3360    }
3361
3362    if (outfits.bundles.length > 2) {
3363      $widgetContainer.removeClass('hide');
3364    } else {
3365      $widgetContainer.addClass('hide');
3366    }
3367  }
3368
3369  function replaceImages(data) {
3370    var originalUrl = data.item.client_original_image_url; // "https://img.abercrombie.com/is/image/anf/KIC_154-2052-0663-900_prod1"
3371
3372    var $img = $(data.element).find('.stylitics-item-image');
3373    var imageURL = originalUrl + '?policy=product-small';
3374
3375    $img.attr('data-src', imageURL);
3376  }
3377
3378  function handleStyliticsItemClick(data) {
3379    var itemClicked = data.item.other_client_item_ids;
3380    var quickviewData = {
3381      productId: itemClicked.product_ids[0],
3382      collectionId: itemClicked.collection_ids[0],
3383      seq: itemClicked.csequence_ids[0],
3384      imageId: data.item.remote_id + '_prod1',
3385      productName: data.item.name,
3386      productBrand: styliticsBrandToThemeBrand[data.item.brand],
3387      returnFocus: getReturnFocus(data.element),
3388      faceout: 'prod',
3389      isStylitics: true
3390    };
3391
3392    window.dispatchEvent(new CustomEvent('quickview:openModal', {detail: quickviewData}));
3393  }
3394
3395  function getReturnFocus(element) {
3396    var $returnFocus = $(element);
3397
3398    if ($returnFocus.hasClass('stylitics-overlay-container')) {
3399      $returnFocus = $returnFocus.closest('.stylitics-bundle-container').find('.stylitics-cta');
3400    } else if ($returnFocus.hasClass('stylitics-item-container')) {
3401      $returnFocus = $returnFocus.find('.stylitics-cta-link');
3402    }
3403
3404    return $returnFocus;
3405  }
3406
3407  function triggerViewLook() {
3408    $(window).trigger('styliticsV3Item:viewLook');
3409  }
3410
3411  function setupCtaButton(element) {
3412    var $viewItemsButton = $(viewItemsButton);
3413    $viewItemsButton.unbind().on('click', triggerViewLook);
3414
3415    var $ctaEyeIconContainer = $(element).find(widgetCtaEyeIconContainerSelector);
3416    var brand = $('header').data('brand');
3417    var iconKey = brandMap[brand] === 'abercrombie' ? 'eye-anf' : 'eye-hco';
3418    var $eyeIcon = $(templateService.renderTemplate('styliticsWidgetIcon', { iconKey: iconKey }));
3419
3420    $ctaEyeIconContainer.find('svg').remove();
3421    $ctaEyeIconContainer.append($eyeIcon);
3422  }
3423
3424  function modalBadgeSetup($element, text) {
3425    var $badgeContainer = $element.find(styliticsModalBadgeContainerSelector);
3426    var $badgeContent = $('<span></span>');
3427
3428    $badgeContent.text(text);
3429    $badgeContent.addClass(styliticsModalBadgeContentClass);
3430    $badgeContainer.empty();
3431    $badgeContainer.append($badgeContent);
3432  }
3433
3434  function cardBadgeSetup($element, text) {
3435    var $badgeContainer = $element.find(styliticsBadgeContainerSelector);
3436    var $badgeContent = $('<span></span>');
3437
3438    $badgeContent.text(text);
3439    $badgeContent.addClass(styliticsBadgeContentClass);
3440    $badgeContainer.empty();
3441    $badgeContainer.append($badgeContent);
3442  }
3443
3444  function handleWidgetRefresh(_e, $selectedSwatch, $productSection, productId) {
3445    if (!Utils.isQuickviewOpened) {
3446      var selectedKIC = Utils.getProductData(productId).kicId;
3447      var $widgetTarget = $(widgetTargetIdSelector);
3448      var styliticsWidget = $widgetTarget.data('widget-instance-v3');
3449
3450      var showStylitics = shouldShowStylitics(selectedKIC);
3451
3452      if (styliticsWidget && showStylitics) {
3453        styliticsWidget.refresh({ api: { item_number: selectedKIC }});
3454      }
3455
3456      if (!styliticsWidget && showStylitics) {
3457        restartModule();
3458      }
3459    }
3460  }
3461
3462  function restartModule() {
3463    var $productSection = $(productSectionSelector);
3464    $(widgetTargetIdSelector).empty();
3465    initStylitics($productSection);
3466  }
3467
3468  var publicMembers = {
3469    'listen': listen
3470  };
3471
3472  return publicMembers;
3473});
3474
3475redesign.define('productIntegrations/styliticsV3Analytics',[],
3476  function StyliticsV3Analytics() {
3477    'use strict';
3478
3479    var widgetTargetIdSelector = '#stylitics-widget';
3480
3481    function trackItemAddToBag(e, itemData) {
3482      var styliticsWidget = $(widgetTargetIdSelector).data('widget-instance-v3');
3483      if (styliticsWidget && typeof styliticsWidget.trackAddItemToCart === 'function') {
3484        styliticsWidget.trackAddItemToCart(itemData.kicId);
3485      }
3486    }
3487
3488    var publicMembers = {
3489      'listen': function listen() {
3490        $(ANF).on('styliticsV3Item:addToBag', trackItemAddToBag);
3491      }
3492    };
3493
3494    return publicMembers;
3495  });
3496
3497redesign.define('productSections/product/productPageImages',[
3498  'coreSectionHelpers',
3499  'productModules/product/productThumbnails',
3500  'productModules/product/productMainImage',
3501  'productModules/product/productZoom',
3502  'productModules/product/productModelSelector',
3503  'productModules/product/productImageLoader',
3504  'coreServices/window',
3505  'productModules/helpers/featureSwitchHelper',
3506  'productIntegrations/stylitics',
3507  'productIntegrations/styliticsAnalytics',
3508  'productModules/helpers/productIntersectionObserver',
3509  'productIntegrations/styliticsV3',
3510  'productIntegrations/styliticsV3Analytics'
3511], function ProductPageImages(
3512  coreSectionHelpers,
3513  thumbnails,
3514  mainImage,
3515  zoom,
3516  productModelSelector,
3517  imageLoader,
3518  windowService,
3519  featureSwitchHelper,
3520  stylitics,
3521  styliticsAnalytics,
3522  productIntersectionObserver,
3523  styliticsV3,
3524  styliticsV3Analytics
3525) {
3526  'use strict';
3527
3528  var messageBus = $(ANF);
3529
3530  var privateMembers = {
3531    'DEFAULT_MODULES': {
3532      '.product-thumbnails': thumbnails,
3533      '.product-main-images': mainImage,
3534      'productZoom': zoom,
3535      '.model-selector': productModelSelector,
3536      'productImages': imageLoader,
3537      'stylitics': stylitics,
3538      'styltitcsAnalytics': styliticsAnalytics(productIntersectionObserver),
3539      'styliticsV3': styliticsV3,
3540      'styliticsV3Analytics': styliticsV3Analytics
3541    },
3542    'GLOBAL_SCOPE': '',
3543    'parentPage': '',
3544    'MODULES': {}
3545  };
3546
3547  return function productImages(settings) {
3548    privateMembers.GLOBAL_SCOPE = settings.scope;
3549    privateMembers.parentPage = settings.parentPage;
3550    privateMembers.MODULES = privateMembers.DEFAULT_MODULES;
3551
3552    if (typeof settings.modules === 'object') {
3553      $.extend(true, privateMembers.MODULES, settings.modules);
3554    }
3555
3556    return {
3557      init: function productPageImagesInit() {
3558        coreSectionHelpers.init({
3559          'modules': privateMembers.MODULES,
3560          'scope': privateMembers.GLOBAL_SCOPE
3561        });
3562      },
3563      subscribe: function productPageImagesSubscribe(settingsObject) {
3564        var options = $.extend({}, privateMembers, settingsObject);
3565        messageBus.on('productPageMain:init', options.parentPage.productPageImages.productPageImagesLoad);
3566      },
3567      productPageImagesLoad: function productPageImagesLoad() {
3568        messageBus.trigger('productPageImages:load', { URL: windowService.location.get(), isQuickview: false });
3569        featureSwitchHelper.stylitics();
3570      }
3571    };
3572  };
3573});
3574
3575redesign.define('productSections/product/productPageReviews',[
3576  'coreSectionHelpers'
3577], function ProductPageReviews(coreSectionHelpers) {
3578  'use strict';
3579
3580  var privateMembers = {
3581    'GLOBAL_SCOPE': '',
3582    'MODULES': {},
3583    'parentPage': ''
3584  };
3585
3586  return function scope(settings) {
3587    privateMembers.GLOBAL_SCOPE = settings.scope;
3588    privateMembers.parentPage = settings.parentPage;
3589
3590    if (typeof settings.modules === 'object') {
3591      $.extend(true, privateMembers.MODULES, settings.modules);
3592    }
3593
3594    var messageBus = $(ANF);
3595
3596    return {
3597      'init': function init() {
3598        coreSectionHelpers.init({
3599          'scope': privateMembers.GLOBAL_SCOPE
3600        });
3601      },
3602      'subscribe': function subscribe() {
3603        messageBus.on('productPageMain:init', privateMembers.parentPage.productPageReviews.productPageReviewsLoad);
3604        messageBus.on('productPageMain:init', privateMembers.parentPage.productPageReviews.productPageReviewsSummaryLoad);
3605      },
3606      'productPageReviewsLoad': function productPageReviewsLoad() {
3607        messageBus.trigger('productPageReviews:load');
3608      }
3609    };
3610  };
3611});
3612
3613redesign.define('productModules/product/productSizes',[
3614  'productModules/helpers/Utils',
3615  'coreServices/window',
3616  'coreServices/url',
3617  'dsPartial/icon-block'
3618], function ProductSizes(
3619  Utils,
3620  windowService,
3621  urlService,
3622  dsPartialIconBlock
3623) {
3624  'use strict';
3625
3626  var messageBus = $(ANF);
3627  var productSectionSelectorClass = '.product-page-v2-modules';
3628  var productAttrClass = '.product-attrs__attr';
3629  var productSizeAttrClass = '.js-product-attributes-inline .product-sizes .product-attrs__attr input';
3630  var productUrgencyMsgClass = '.product-urgency-message';
3631  var skus = '.product-page__skus';
3632  var inventoryBackorderableStatus = 'Backorderable';
3633  var inventoryAvailableStatus = 'Available';
3634  var productWrap = '.product-page__swatches-attributes';
3635  var selectedSkuParameterName = 'sizeValue';
3636  var errorContainerSelectorClass = '.validator-container';
3637  var ajaxErrorClass = 'atb-ajax-error';
3638  var quickviewPrimaryActionContainerClass = '.quick-view__primary-action-wrapper';
3639  var quickviewProductInfoContainerSelectorClass = '.product-quickview__modal[data-open="true"] .product-page__info-container';
3640  var partNumberSelector = 'input[name="partNumber"]';
3641  var productPageFormSelectorClass = '.product-page-add-to-bag__container';
3642  var quickviewErrorClass = 'qv-error';
3643  var inputSelector = 'input';
3644  var fadeSpeed = 100;
3645  var fadeEasing = 'linear';
3646  var checked = 'checked';
3647  var pageUrl = windowService.location.getHref();
3648  var productPagePrimarySizeList = '.product-page__swatches-attributes .product-sizes-primary ul li';
3649  var productPageATBButtonSelectorClass = '.product-page-add-to-bag__button';
3650  var showUrgencyMessageClass = 'product-urgency-message__show';
3651  var productSizesSelectorClass = '.product-sizes';
3652  var productSizesCurrentSelectedClass = '.product-sizes__name__current-selected';
3653  var selectedClass = 'selected';
3654
3655  function sizeOnLoad() {
3656    var selectedSku = urlService.deconstruct(pageUrl)
3657      .search
3658      .reduce(function selectedSkuParameterReducer(acum, queryStringValueInstance) {
3659        return queryStringValueInstance.name === selectedSkuParameterName ?
3660          queryStringValueInstance.value :
3661          acum;
3662      }, '');
3663
3664    // if there is a selected sku in the url,
3665    if (selectedSku && selectedSku.length > 0) {
3666      var $skus = $(skus);
3667      var $selectedSkuOption  = $skus.children('option[value="' + selectedSku + '"]');
3668
3669      if ($selectedSkuOption.length) {
3670        var $product = $selectedSkuOption.closest(productWrap);
3671        var sizePrimary = $selectedSkuOption.data('size-primary');
3672        var $sizePrimaryTile = $product.find(productAttrClass + ' [name^="size-primary"][value="' + sizePrimary + '"]');
3673        var sizeSecondary = $selectedSkuOption.data('size-secondary');
3674        var $sizeSecondaryTile = $product.find(productAttrClass + ' [name^="size-secondary"][value="' + sizeSecondary + '"]');
3675
3676        if ($sizePrimaryTile.length) {
3677          $sizePrimaryTile.prop(checked, true).closest(productAttrClass).addClass('selected');
3678        }
3679
3680        if ($sizeSecondaryTile.length) {
3681          $sizeSecondaryTile.prop(checked, true).closest(productAttrClass).addClass('selected');
3682        }
3683
3684        messageBus.trigger('productMultipleAttributeFilter.attributeUpdate');
3685      }
3686    }
3687
3688    // if single size
3689    var $sizeList = Utils.isQuickviewOpened ? $('.product-quickview__modal[data-open="true"]').find(productPagePrimarySizeList) : $(productPagePrimarySizeList);
3690    if ($sizeList.length === 1) {
3691      var $input = $sizeList.find('input');
3692      $input.attr('checked', '');
3693      displaySelected($input, true);
3694    }
3695  }
3696
3697  function skuChangeHandler(e, data) {
3698    var sku = data.sku || '';
3699    var $skuContainer = data.skuContainer;
3700    var $targetSku;
3701    var inventory;
3702    var inventoryStatus;
3703
3704    $targetSku = $skuContainer.find(skus).children('option[value="' + sku + '"]');
3705    inventory = $targetSku.data('inventory');
3706    inventoryStatus = $targetSku.data('inventory-status');
3707
3708    updateUrgencyMessage(inventory, inventoryStatus, $skuContainer, $targetSku);
3709  }
3710
3711  function updateUrgencyMessage(inventory, inventoryStatus, $skuContainer, $targetSku) {
3712    var urgencyMessageCount = ANF.params.storeAttributes.catalogV2.UrgencyMessageCount;
3713    var $productUrgencyMsg = $skuContainer.find(productUrgencyMsgClass);
3714    var $urgencyScreenReaderMsg = $productUrgencyMsg.find('.urgency-message__sku_screen-reader-text');
3715    var message;
3716    if (inventoryStatus === inventoryBackorderableStatus) {
3717      $productUrgencyMsg.addClass(showUrgencyMessageClass);
3718      message = ANF.messaging.catalog.BACKORDER_URGENCY_MESSAGE;
3719    } else if (inventory < urgencyMessageCount && inventory > 0 && inventoryStatus === inventoryAvailableStatus) {
3720      // If there are less then 5 of a product in stock, display urgent message.
3721
3722      if (!$productUrgencyMsg.hasClass('show')) {
3723        $productUrgencyMsg.addClass('fadein').removeClass('fadeout hide default-hidden');
3724        setTimeout(function timeoutBump() {
3725          $productUrgencyMsg.removeClass('fadein').addClass('bump');
3726
3727          setTimeout(function timeoutShow() {
3728            $productUrgencyMsg.removeClass('bump').addClass('show');
3729            $urgencyScreenReaderMsg.html(message);
3730          }, 500);
3731        }, 500);
3732      } else {
3733        $productUrgencyMsg.removeClass('show hide').addClass('bump');
3734
3735        if ($skuContainer.closest('.product-page__info-container').hasClass('is_stuck')) {
3736          setTimeout(function timeoutShow() {
3737            $productUrgencyMsg.removeClass('bump').addClass('show');
3738          }, 650);
3739        } else {
3740          setTimeout(function timeoutShow() {
3741            $productUrgencyMsg.removeClass('bump').addClass('show');
3742            $urgencyScreenReaderMsg.html(message);
3743          }, 500);
3744        }
3745      }
3746
3747      message = addSizeToUrgencyMessage($skuContainer, $targetSku);
3748    } else {
3749      if (!$productUrgencyMsg.hasClass('hide')) {
3750        $productUrgencyMsg.removeClass('show').addClass('fadeout');
3751        setTimeout(function timeoutHide() {
3752          $productUrgencyMsg.removeClass('fadeout').addClass('hide');
3753          $urgencyScreenReaderMsg.html('');
3754        }, 450);
3755      }
3756
3757      message = $productUrgencyMsg.find('.icon-block-heading').text();
3758    }
3759
3760    var iconBlockSettings = {
3761      'data-icon': 'clock',
3762      'icon-block-optional-content': {
3763        'icon-block-heading': message
3764      }
3765    };
3766
3767    var template = dsPartialIconBlock.templates['icon-block'](iconBlockSettings);
3768    $productUrgencyMsg.find('.urgency-message-content').html(template);
3769  }
3770
3771  function addSizeToUrgencyMessage($skuContainer, $targetSku) {
3772    var message = ANF.messaging.catalog.STOCK_URGENCY_MESSAGE;
3773    var skuData = $targetSku.data();
3774    var size = skuData.urgencyPrimary;
3775
3776    if (skuData.urgencySecondary && $skuContainer.find('.product-sizes-secondary').length > 0) {
3777      size += ' X ' + skuData.urgencySecondary;
3778    }
3779
3780    if ($skuContainer.closest('.product-page-sticky-size-tile__container').length === 0) {
3781      $(window).trigger('analytics.miscProductFeature', {'type': 'low inventory message', 'action': 'SKU level', 'message': size});
3782    }
3783
3784    return message.replace(/\{(.*)\}/, size);
3785  }
3786
3787  function sizeTileClickHandler(e) {
3788    var $selectedSizeTile = $(e.currentTarget).parents('.product-attrs__attr');
3789    if (!$selectedSizeTile.hasClass('unavailable')) {
3790      selectProductAttrHandler($selectedSizeTile);
3791      displaySelected($selectedSizeTile);
3792    }
3793  }
3794
3795  function stickySizeTileSelectedHandler(e, data) {
3796    selectProductAttrHandler(data.$selectedTile);
3797  }
3798
3799  function selectProductAttrHandler($selectedSizeTile) {
3800    // get the size tile in the pdp, and the tile in the sticky tray
3801    var sizeValue = $selectedSizeTile.find(inputSelector).data('size');
3802    var $sizes = $selectedSizeTile
3803      .parents(productSectionSelectorClass)
3804      .find('input[data-size="' + sizeValue + '"]')
3805      .closest(productAttrClass);
3806
3807    // resolve product section and active form
3808    var $productSection = $selectedSizeTile.closest(productSectionSelectorClass);
3809    var $atbForm = $productSection.find(productPageFormSelectorClass).add(quickviewPrimaryActionContainerClass);
3810
3811    handleSizeTileSelection($sizes);
3812
3813    // clear the error message when a size tile is selected.
3814    $atbForm.find(errorContainerSelectorClass).fadeOut(fadeSpeed, fadeEasing);
3815    $atbForm.removeClass(ajaxErrorClass);
3816    $atbForm.find(productPageATBButtonSelectorClass).removeAttr('disabled');
3817
3818    $(quickviewProductInfoContainerSelectorClass).removeClass(quickviewErrorClass);
3819
3820    triggerAttributeClicked($selectedSizeTile, $productSection);
3821    dataBridgeSkuUpdateHandler($productSection);
3822  }
3823
3824  function handleSizeTileSelection($selectedSizes) {
3825    var sizeTiles = $selectedSizes.closest(productSizesSelectorClass).find(productAttrClass);
3826
3827    // remove all selectedClass and set all prop "checked" to false
3828    sizeTiles.removeClass(selectedClass);
3829    sizeTiles.find('input').prop('checked', false);
3830
3831    // add selectedClass and set prop "checked" to true for selectedSize tile
3832    $selectedSizes.addClass(selectedClass);
3833    $selectedSizes.find('input').prop('checked', true);
3834  }
3835
3836  function displaySelected($el) {
3837    var $input = $el;
3838
3839    if ($el.prop('tagName') !== 'INPUT') $input = $el.find('input');
3840
3841    var selectedText = $input.parent().find('.tile-text').html();
3842    var sizeSizeCurrentSelectedSelector = productSizesCurrentSelectedClass;
3843
3844    var $productSizesName = $input.closest(productSizesSelectorClass).prev();
3845    var $sizeCurrentSelected = $($productSizesName.find(sizeSizeCurrentSelectedSelector)[0]);
3846
3847    $sizeCurrentSelected.text(selectedText);
3848  }
3849
3850  function triggerAttributeClicked($selectedSizeTile, $productSection) {
3851    var attributeData = {
3852      selectedAttribute: $selectedSizeTile,
3853      $productSection: $productSection
3854    };
3855    messageBus.trigger('productMultipleAttributeFilter:attributeClicked', attributeData);
3856  }
3857
3858  function dataBridgeSkuUpdateHandler($productSection) {
3859    var shortSku = $productSection.find(partNumberSelector).val() || null;
3860    var productId = $productSection.attr('data-productid');
3861    var kic = Utils.getProductData(productId).kicId;
3862
3863    try {
3864      var productData = {
3865        kic: kic,
3866        shortSku: shortSku,
3867        productId: productId
3868      };
3869      window.digitalData.trigger('productInfo.sizeSelected', productData);
3870    } catch (error) {
3871      // DataBridge Error while doing "productInfo.sizeSelected:"
3872    }
3873  }
3874
3875  var publicMembers = {
3876    listen: function listen() {
3877      messageBus.on('productSize:updateUrgencyMessage', skuChangeHandler);
3878      messageBus.on('productPageInfo:load', sizeOnLoad);
3879      messageBus.on('stickySizeTileSelected', stickySizeTileSelectedHandler);
3880    },
3881    bindEvents: function bindEvents() {
3882      $(document).on('click', productSizeAttrClass, sizeTileClickHandler);
3883    }
3884  };
3885
3886  return publicMembers;
3887});
3888
3889redesign.define('productModules/helpers/ProductMFEAdapter',[
3890  'productModules/helpers/Utils',
3891  'globalServices/startGuestSession'
3892],
3893function ProductMFEAdapter(Utils, guestSession) {
3894  'use strict';
3895
3896  function callGuestSession() {
3897    guestSession.deferredInit().done(function guestSessionSuccess() {
3898      var guestSessionSuccessEvent = new CustomEvent('crs:guestSessionSuccess');
3899      window.dispatchEvent(guestSessionSuccessEvent);
3900    }).fail(function guestSessionFail() {
3901      var guestSessionFailEvent = new CustomEvent('crs:guestSessionFail');
3902      window.dispatchEvent( guestSessionFailEvent);
3903    });
3904  }
3905
3906  var publicMembers = {
3907    attributeUpdate: function attributeUpdate(data) {
3908      var attributeUpdateEvent = new CustomEvent('crs:attributeUpdate', { detail: data });
3909      !Utils.isQuickviewOpened && window.dispatchEvent(attributeUpdateEvent);
3910    },
3911    swatchUpdate: function swatchUpdate(data) {
3912      var swatchUpdateEvent = new CustomEvent('crs:swatchUpdate', { detail: data });
3913      !Utils.isQuickviewOpened && window.dispatchEvent(swatchUpdateEvent);
3914    },
3915
3916    listen: function listen() {
3917      window.addEventListener('mfe:callGuestSession', callGuestSession);
3918    }
3919  };
3920
3921  return publicMembers;
3922});
3923
3924redesign.define('productModules/product/productMultipleAttributeFilter',[
3925  'coreServices/ariaLiveSetterService',
3926  'productModules/helpers/Utils',
3927  'productModules/helpers/ProductMFEAdapter'
3928], function productMultipleAttributeFilter(ariaLiveSetterService, Utils, ProductMFEAdapter) {
3929  'use strict';
3930
3931  var skuContainer = '.product-page__skus';
3932  var swatchesSizesContainerSelectorClass = '.product-page__swatches-attributes';
3933  var tileContainerClass = '.product-attrs__attr';
3934  var selectedTileInputSelectorClass = 'input:checked';
3935  var productParentPageContainerSelectorClass = '.product-page-v2-modules';
3936  var stickySizeTileContainerSelectorClass = '.product-page-sticky-size-tile__container';
3937  var productFormSectionSelector = '.product-page-add-to-bag__container';
3938
3939  var messageBus = $(ANF);
3940
3941  // This will hold all combinations of skuDefiningProperties and whether that sku has inventory
3942  var skuAvailabilityByCollection = {};
3943
3944  // This will hold all combinations of skuDefiningProperties and what shortSku has those properties
3945  var definedSkusByCollection = {};
3946
3947  // This is used to generate permutations. The algorithm is using it is O(n!), so
3948  // don't let this list get any longer than a few properties
3949  var skuDefiningProperties = ['kic', 'sizePrimary', 'sizeSecondary'];
3950
3951  function setupSkuData(_e, productSection) {
3952    var $skuParentContainer = $(productSection).find(swatchesSizesContainerSelectorClass);
3953    var collection = $(productSection).find(productFormSectionSelector).children('input[name=collection]').val();
3954
3955    var skus = $skuParentContainer
3956      .find(skuContainer + ' option')
3957      .get() // converts jquery object to plain array
3958      .map(skuElementToData);
3959
3960    skuAvailabilityByCollection[collection] = skus.reduce(createSkuAvailabilityObject, {});
3961    definedSkusByCollection[collection] = skus.reduce(createDefinedSkuObject, {});
3962  }
3963
3964  function skuElementToData(sku) {
3965    return $.extend({}, sku.dataset, {'shortSku': sku.value});
3966  }
3967
3968  function permutationsForDefiningProperties(sku) {
3969    // Remove unused properties, usually secondary size
3970    var skuProperties = skuDefiningProperties
3971      .filter(function removeUndefined(property) { return !!sku[property]; })
3972      .map(function getValue(property) { return sku[property]; });
3973
3974    var permuted = [];
3975    permute(skuProperties, skuProperties.length, function permuteAnon(arr) {
3976      permuted.push(arr.slice());
3977    });
3978
3979    return permuted;
3980  }
3981
3982  function createSkuAvailabilityObject(acc, sku) {
3983    var permuted = permutationsForDefiningProperties(sku);
3984
3985    permuted.forEach( function permuteForLoop(permutation) {
3986      setNested(permutation, acc, sku.inventory > 0);
3987    });
3988
3989    return acc;
3990  }
3991
3992  function createDefinedSkuObject(acc, sku) {
3993    var permuted = permutationsForDefiningProperties(sku);
3994
3995    permuted.forEach( function permuteForLoop(permutation) {
3996      setNested(permutation, acc, sku.shortSku);
3997    });
3998
3999    return acc;
4000  }
4001
4002  // Takes an array and generates all permutations of the items in it
4003  function permute(arr, len, cb) {
4004    if (len === 1) {
4005      cb(arr);
4006    } else {
4007      for (var i = 0; i < len; i++) {
4008        permute(arr, len - 1, cb);
4009
4010        if (len % 2 === 0) {
4011          swap(arr, i, len - 1);
4012        } else {
4013          swap(arr, 0, len - 1);
4014        }
4015      }
4016    }
4017
4018    // http://jira/browse/EPIC-9604 Jira to revisit this to adhere to "no-param-reassign" ESLint rule
4019    function swap(paramArr, a, b) {
4020      var tmp = paramArr[a];
4021      paramArr[a] = paramArr[b];
4022      paramArr[b] = tmp;
4023    }
4024  }
4025
4026  // Allows setting a value on an object with an array of property names
4027  // Example:
4028  // setNested(['a', 'b', 'c'], {}, true)
4029  //  => { a: { b: { c: true } } }
4030  function setNested(path, object, value) {
4031    var lastIndex = path.length - 1;
4032    var nested = object;
4033
4034    for (var i = 0; i < path.length; i++) {
4035      var key = path[i];
4036      var newValue = value;
4037      var existing = nested[key];
4038
4039      if (i !== lastIndex) {
4040        newValue = existing || {};
4041      }
4042
4043      nested[key] = newValue;
4044      nested = nested[key];
4045    }
4046
4047    return object;
4048  }
4049
4050  // Gets a value out of an object with an array of property names
4051  function getNested(path, object) {
4052    if (!object || path.length === 0) {
4053      return object;
4054    } else if (path.length === 1) {
4055      return object[path[0]];
4056    }
4057    return getNested(path.slice(1), object[path[0]]);
4058  }
4059
4060  // Searches recursively through an object tree to find if any key/value pair is true
4061  // Returns as soon as it finds one.
4062  function findNestedTrue(node) {
4063    if (typeof node === 'boolean') {
4064      return node;
4065    }
4066
4067    if (typeof node === 'object') {
4068      var children = Object.keys(node);
4069
4070      for (var i = 0; i < children.length; i++) {
4071        var foundTrue = findNestedTrue(node[children[i]]);
4072        if (foundTrue) {
4073          return true;
4074        }
4075      }
4076
4077      return false;
4078    }
4079
4080    return false;
4081  }
4082
4083  function findIsSkuAvailable(skuAvailability, criteria, singleSearch) {
4084    var path = Object.keys(criteria).map(function getFilters(key) {
4085      return criteria[key];
4086    });
4087
4088    var state = getNested(path, skuAvailability);
4089
4090    if (typeof state === 'boolean') {
4091      return state;
4092    } else if (singleSearch || !state) {
4093      return false;
4094    }
4095    return findNestedTrue(state);
4096  }
4097
4098  var publicMembers = {
4099    initFilter: function initFilter() {
4100      // set up skus data for each product on the page
4101      var isQuickview = Utils.isQuickviewOpened;
4102
4103      if (!isQuickview && Utils.hasProductMFEEnabled()) {
4104        return;
4105      }
4106
4107      $(productParentPageContainerSelectorClass).each(setupSkuData);
4108    },
4109
4110    renderBuyGridTiles: function renderBuyGridTiles($skuParentContainer, skuAvailability, selectedTileData) {
4111      // Focus gets moved around when setting elements' disabled attribute, so we need to reset it
4112      var savedFocusedElement = document.activeElement;
4113
4114      // If a selected combo is actually unavailable, we need to determine availability just by KIC
4115      var verifiedSelection = findIsSkuAvailable(skuAvailability, selectedTileData) ?
4116        selectedTileData : { 'kic': selectedTileData.kic };
4117
4118      var tiles = $skuParentContainer.find(tileContainerClass);
4119      tiles.each(function renderTile(_idx, tile) {
4120        var input = $(tile).find('input')[0];
4121        var tileType = input.name.split('_')[0]; // handles tray tiles
4122        var tileOptions = $.extend({}, verifiedSelection);
4123        tileOptions[tileType] = input.value;
4124
4125        var skuHasInventory = findIsSkuAvailable(skuAvailability, tileOptions);
4126
4127        if (!skuHasInventory) {
4128          if (tileType === 'kic') {
4129            tile.setAttribute('data-state', 'disabled');
4130          } else {
4131            $(tile).removeClass('selected');
4132            input.checked = false;
4133            input.setAttribute('disabled', 'disabled');
4134          }
4135        } else if (tileType === 'kic') {
4136          tile.setAttribute('data-state', 'default');
4137        } else {
4138          input.removeAttribute('disabled');
4139        }
4140      });
4141
4142      savedFocusedElement.focus();
4143    },
4144
4145    attributeUpdate: function attributeUpdate(_e, data) {
4146      var $selectedAttr = data.selectedAttribute || $();
4147      var $productSection = data.$productSection;
4148      var $skuParentContainer = $productSection.find(swatchesSizesContainerSelectorClass);
4149      var $skuContainer = $skuParentContainer.find(skuContainer);
4150      var $selectedSkuArray = $skuParentContainer.find(selectedTileInputSelectorClass);
4151
4152      var productId = $selectedAttr.find('input').attr('data-productid') || $productSection.attr('data-productid');
4153      var collection = $productSection.find(productFormSectionSelector).children('input[name=collection]').val();
4154
4155      var skuAvailability = skuAvailabilityByCollection[collection];
4156      var filterOptions = {};
4157
4158      var $skuOption;
4159      var skuSelected = null;
4160
4161      $.each($selectedSkuArray,  function selectedSkuArrayLoop(_idx, input) {
4162        // Exclude the duplicates in sticky tray, if they exist
4163        if (!$(input).closest(stickySizeTileContainerSelectorClass).length) {
4164          var tileType = input.name.split('_')[0]; // handles qv tiles
4165          filterOptions[tileType] = input.value;
4166        }
4167      });
4168
4169      publicMembers.renderBuyGridTiles($skuParentContainer, skuAvailability, filterOptions);
4170
4171      var selectedIsQualifiedSku = findIsSkuAvailable(skuAvailability, filterOptions, true);
4172      $productSection.attr('data-qualified-sku', selectedIsQualifiedSku);
4173
4174      if (selectedIsQualifiedSku) {
4175        var definedSkuAttributes = Object.keys(filterOptions).map(function getFilters(key) {
4176          return filterOptions[key];
4177        });
4178
4179        var sku = getNested(definedSkuAttributes, definedSkusByCollection[collection]);
4180        skuSelected = sku;
4181        $skuOption = $skuContainer.find('option[value="' + skuSelected + '"]');
4182
4183        publicMembers.handlePartNumberCondition($skuContainer);
4184
4185        messageBus.trigger('productPrice:skuSelected', {
4186          'productId': productId,
4187          'skuId': skuSelected,
4188          'skuContainer': $skuParentContainer,
4189          'productPrices': productPrices,
4190          'productSection': $productSection
4191        });
4192
4193        // for analytics
4194        setTimeout(function analyticsTimeout() {
4195          $(window).trigger('productSize:skuSelected', {
4196            'sku': skuSelected,
4197            'skuContainer': $skuParentContainer,
4198            'productId': productId,
4199            'selectedAttribute': $selectedAttr
4200          });
4201        }, 0);
4202      } else {
4203        var currentKIC = Utils.getProductData(productId).kicId;
4204        $skuOption = $skuContainer.find('option[data-kic="' + currentKIC + '"]').first();
4205
4206        // If we can't find the product via KIC this grabs the first option after the blank option instead.
4207        if (!$skuOption.val()) {
4208          $skuOption = $skuContainer.find('option:eq(2)');
4209        }
4210
4211        messageBus.trigger('productPrice:swatchSelected', {
4212          'productId': productId,
4213          'kic': currentKIC,
4214          'skuContainer': $skuParentContainer,
4215          'productPrices': productPrices,
4216          'productSection': $productSection
4217        });
4218      }
4219      $skuContainer.val(skuSelected);
4220      $productSection.attr('data-inventory', $skuOption.attr('data-inventory'));
4221
4222      var $productQuantityDropdown = $productSection.find('.product-quantity-dropdown select');
4223      var isStickyTileSelection = $selectedAttr.parents(stickySizeTileContainerSelectorClass).length === 1;
4224
4225      messageBus.trigger('productSize:updateUrgencyMessage', {
4226        'sku': skuSelected,
4227        'skuContainer': $skuParentContainer,
4228        'productId': productId,
4229        'selectedAttribute': $selectedAttr,
4230        'isStickyTileSelection': isStickyTileSelection
4231      });
4232
4233      messageBus.trigger('productSize:skuSelected', {
4234        'sku': skuSelected,
4235        'skuContainer': $skuParentContainer,
4236        'productId': productId,
4237        'selectedAttribute': $selectedAttr,
4238        'isStickyTileSelection': isStickyTileSelection,
4239        'quantity': $productQuantityDropdown ? $productQuantityDropdown.val() : 1
4240      });
4241
4242      messageBus.trigger('PDP:skuSelected', {
4243        'sku': skuSelected,
4244        '$parentContainer': $productSection
4245      });
4246
4247      ProductMFEAdapter.attributeUpdate({
4248        sku: skuSelected,
4249        productId: productId,
4250        kic: filterOptions.kic,
4251        seq: productCatalog[productId].swatchSequence
4252      });
4253
4254      ariaLiveSetterService.assertive(ANF.messaging.product.productListUpdated);
4255    },
4256
4257    handlePartNumberCondition: function handlePartNumberCondition($skuContainer) {
4258      var needsPartNumber = ($('body').hasClass('checkout') || $('body').is('#checkout-cart'));
4259
4260      if (needsPartNumber) {
4261        var $addToBagForm = $skuContainer.closest('form');
4262        publicMembers.addPartNumberToForm($addToBagForm);
4263      }
4264    },
4265
4266    addPartNumberToForm: function addPartNumberToForm(form) {
4267      var $sku = form.find('[name="sku"]');
4268      var $partNumber;
4269      var dataSelector = '.product-add-to-bag .data';
4270      var partNumberName = 'partNumber_2';
4271
4272      // if new size tiles are used, the sku is on the form as 'sku' input instead of 'partnumber' as expected.
4273      if ($sku.length) {
4274        $partNumber = form.find('[name="' + partNumberName + '"]');
4275
4276        if ($partNumber.length) {
4277          $partNumber.val($sku.val());
4278        } else {
4279          $('<input>').attr({
4280            type: 'hidden',
4281            id: partNumberName,
4282            name: partNumberName,
4283            value: $sku.val()
4284          }).appendTo(dataSelector);
4285        }
4286      }
4287    }
4288  };
4289
4290  publicMembers.listen = {
4291    'productPageInfo:load': publicMembers.initFilter,
4292    'productMultipleAttributeFilter:attributeUpdate': publicMembers.attributeUpdate,
4293    'productMultipleAttributeFilter:attributeClicked': publicMembers.attributeUpdate
4294  };
4295
4296  return publicMembers;
4297});
4298
4299redesign.define('productModules/product/productSwatches',[
4300  'productModules/helpers/Utils',
4301  'dsPartial/icon-block',
4302  'util/analytics/enum/dataPoint',
4303  'util/analytics/enum/subscriptionName',
4304  'productModules/helpers/ProductMFEAdapter'
4305], function ProductSwatches(
4306  Utils,
4307  dsPartialIconBlock,
4308  analyticsDataPoint,
4309  analyticsSubscriptionName,
4310  ProductMFEAdapter
4311) {
4312  'use strict';
4313
4314  // Constants
4315  var activeProductClass = 'active-product';
4316  var activeProductParentContainerSelectorClass = '.product-page-v2-modules.active-product';
4317  var ajaxErrorClass = 'atb-ajax-error';
4318  var defaultSwatchClass = '.default-swatch';
4319  var errorContainerSelectorClass = '.validator-container';
4320  var fadeEasing = 'linear';
4321  var fadeSpeed = 100;
4322  var messageBus = $(ANF);
4323  var partNumberSelector = 'input[name="partNumber"]';
4324  var productPageATBButtonSelectorClass = '.product-page-add-to-bag__button';
4325  var productSection = '.product-page-v2-modules';
4326  var productSkuSelectorClass = '.product-page__skus';
4327  var productSwatchesSelectorClass = '.product-swatches';
4328  var productWrap = '.product-page__swatches-attributes';
4329  var quickviewModalIsActiveSelectorClass = '.product-quickview__modal[data-open="true"]';
4330  var quickviewModalProductSection = '.product-quickview__modal[data-open="true"] .product-quickview__content .product-page-v2-modules';
4331  var selectedClass = 'selected';
4332  var swatchLabel = '.selected-swatch__label';
4333  var swatchLoadingClass = 'loading';
4334  var swatchTile = '.product-swatch__attr';
4335  var urgencyMessageSelectorClass = '.product-urgency-size-availability';
4336
4337  function handleMfeSwatchChange(event) {
4338    var productDetails = event.detail;
4339    var $productSection = Utils.getProductSection();
4340    messageBus.trigger('mfe:SwatchSelected', [{}, $productSection, productDetails.productId, ANF]);
4341  }
4342
4343  function swatchOnLoad() {
4344    var isQuickview = Utils.isQuickviewOpened;
4345    var $productSection = isQuickview ? $(quickviewModalProductSection) : $(productSection);
4346    var $selectedSwatch = $productSection.find(defaultSwatchClass);
4347    var productId = getProductId($productSection);
4348
4349    if (!isQuickview && Utils.hasProductMFEEnabled()) {
4350      return;
4351    }
4352
4353
4354    if ($selectedSwatch.length > 0) {
4355      $productSection.addClass(activeProductClass); // set active product
4356      swatchSelectedUpdate($selectedSwatch, $productSection, productId);
4357    } else {
4358      updateSwatchUrgencyMessage($productSection, productId);
4359      messageBus.trigger('productMultipleAttributeFilter:attributeUpdate', {$productSection: $productSection});
4360    }
4361    messageBus.trigger('productPageInfo:swatchOnLoad', [$selectedSwatch, $productSection, productId, ANF]);
4362
4363    if (isQuickview) {
4364      setTimeout(function quickviewSwatchLoadedTrigger() {
4365        messageBus.trigger('productQuickview:swatchesLoaded', $productSection);
4366      }, 0);
4367    }
4368  }
4369
4370  function swatchClickEvent(e) {
4371    var $selectedSwatch = $(e.currentTarget);
4372    var $selectedInput = $selectedSwatch.find('input');
4373    var newProductId = $selectedInput.data('productid');
4374    var newKIC = $selectedInput.val();
4375    var $productSection = $selectedSwatch.closest(productSection);
4376    var $addToBagForm = $productSection.find('form');
4377    if (newProductId !== parseInt(getProductId($productSection), 10)) {
4378      $(activeProductParentContainerSelectorClass).removeClass(activeProductClass);
4379      $productSection.addClass(activeProductClass);
4380
4381      $addToBagForm
4382        .find(errorContainerSelectorClass)
4383        .fadeOut(fadeSpeed, fadeEasing)
4384        .removeClass(ajaxErrorClass);
4385
4386      // update product ids across page
4387      $addToBagForm.find('input[name=productId]').val(newProductId);
4388
4389      $productSection
4390        .attr('data-productid', newProductId)
4391        .data('productid', newProductId);
4392
4393      $productSection.find('.details__write-review-modal').attr('data-productid', newProductId);
4394
4395      var $currentProductSkus = $productSection.find(productSkuSelectorClass);
4396      var longSku = $currentProductSkus.find('option[data-kic="' + newKIC + '"]').first().attr('data-long-sku');
4397      $productSection.attr('data-long-sku', $.trim(longSku));
4398
4399      var $fitPredictorContainer = $productSection.find('.fp-root');
4400      if ($fitPredictorContainer.length > 0) {
4401        $fitPredictorContainer.attr('data-product-id', longSku);
4402      }
4403
4404      // trigger image load after all the product data is saved on the <section>
4405      messageBus.trigger('productPageImages:reload', {
4406        $selectedSwatch: $selectedSwatch,
4407        $productSection: $productSection
4408      });
4409
4410      swatchSelectedUpdate($selectedSwatch, $productSection, newProductId);
4411      ProductMFEAdapter.swatchUpdate({
4412        productId: newProductId
4413      });
4414      messageBus.trigger('productPageInfo:swatchSelected', [$selectedSwatch, $productSection, newProductId]);
4415      $addToBagForm.find(productPageATBButtonSelectorClass).removeAttr('disabled');
4416
4417      triggerAnalyticsEvent(newProductId, longSku);
4418    }
4419
4420    // push call to end of stack to avoid race conditions
4421    window.setTimeout(function timeout() {
4422      dataBridgeSwatchSelectHandler($productSection, newProductId);
4423    }, 0);
4424
4425    // This is to prevent the event to alter the pdp when in the quickview of the same product
4426    e.preventDefault();
4427  }
4428
4429  function swatchSelectedUpdate($selectedSwatch, $productSection, productId) {
4430    var $input = $selectedSwatch.find('input');
4431    var $productAttributeWrapper = $input.closest(productWrap);
4432
4433    // handle product urgency message display
4434    updateSwatchUrgencyMessage($productSection, productId);
4435
4436    // EPIC-7708: adding this each back so that both the pdp swatch and tray swatch is updated to have selected class on swatch click
4437    // TODO: remove this when we improve productMultipleAttributeFilter.attributeUpdate's function to use only pdp swatch to filter
4438    var swatchSeq = $input.attr('data-seq');
4439    var swatches = $productSection.find('input[data-seq=' + swatchSeq + ']').closest(swatchTile);
4440
4441    $.each(swatches, function updateSwatches(index, swatch) {
4442      var $swatch = $(swatch);
4443
4444      updateSwatchLabel($input, $productAttributeWrapper);
4445      updateSelectedSeq($input, $productAttributeWrapper);
4446      updateSwatchSelectedProperty($swatch, $input);
4447
4448      if (index === 0) {
4449        setTimeout(function timeout() {
4450          triggerPostSwatchSelectionProcesses($swatch, $productSection);
4451
4452          if ($(quickviewModalIsActiveSelectorClass).length > 0) {
4453            messageBus.trigger('quickview:updateFullProductLink', $swatch.children('input').attr('data-producturl'));
4454          }
4455        }, 0);
4456      }
4457    });
4458  }
4459
4460  function updateSwatchUrgencyMessage($productSection, productId) {
4461    if ($productSection.find('.product-sizes-primary .tiles').first().children().length > 1) {
4462      var $urgencyMsg = $productSection.find(urgencyMessageSelectorClass);
4463      var $urgencyScreenReaderMsg = $urgencyMsg.find('.urgency-message__kic_screen-reader');
4464
4465      var finalThreshold = ANF.params.storeAttributes.catalogV2.lowestInventoryThreshold;
4466      var currentProductInventory = Utils.getProductData(productId).lowestInventoryCount;
4467      var isLowInventory = currentProductInventory > 0 && currentProductInventory < finalThreshold;
4468
4469      if (isLowInventory) {
4470        if (!$urgencyMsg.hasClass('show')) {
4471          $urgencyMsg.addClass('fadein').removeClass('hide default-hidden');
4472          setTimeout(function timeoutBump() {
4473            $urgencyMsg.removeClass('fadein').addClass('bump');
4474
4475            setTimeout(function timeoutShow() {
4476              $urgencyMsg.removeClass('bump').addClass('show');
4477              $urgencyScreenReaderMsg.html(ANF.messaging.catalog.NEW_KIC_URGENCY_MESSAGE);
4478            }, 500);
4479          }, 500);
4480        } else {
4481          $urgencyMsg.removeClass('show hide').addClass('bump');
4482
4483          setTimeout(function timeoutShow() {
4484            $urgencyMsg.removeClass('bump').addClass('show');
4485            $urgencyScreenReaderMsg.html(ANF.messaging.catalog.NEW_KIC_URGENCY_MESSAGE);
4486          }, 500);
4487        }
4488
4489        $(window).trigger('analytics.miscProductFeature', {
4490          'type': 'low inventory message',
4491          'action': 'KIC level'
4492        });
4493      } else if (!$urgencyMsg.hasClass('hide')) {
4494        $urgencyMsg.removeClass('show').addClass('fadeout');
4495        setTimeout(function timeoutHide() {
4496          $urgencyMsg.removeClass('fadeout').addClass('hide');
4497          $urgencyScreenReaderMsg.html('');
4498        }, 450);
4499      }
4500
4501      // unfortunately the best way to gaurantee animation running again is by replacing the content of the urgency message.
4502      var iconBlockSettings = {
4503        'data-icon': 'clock',
4504        'icon-block-optional-content': {
4505          'icon-block-heading': ANF.messaging.catalog.NEW_KIC_URGENCY_MESSAGE
4506        }
4507      };
4508
4509      var template = dsPartialIconBlock.templates['icon-block'](iconBlockSettings);
4510      $urgencyMsg.find('.urgency-message__content').html(template);
4511    }
4512  }
4513
4514  function triggerPostSwatchSelectionProcesses($selectedSwatch, $productSection) {
4515    var $productWrap = $productSection.find(productWrap);
4516
4517    var attributeData = {
4518      selectedAttribute: $selectedSwatch,
4519      $productSection: $productSection
4520    };
4521
4522    messageBus.trigger('productMultipleAttributeFilter:attributeClicked', attributeData);
4523
4524    if ($productWrap.hasClass(swatchLoadingClass)) {
4525      $productWrap.removeClass(swatchLoadingClass);
4526    }
4527  }
4528
4529  function updateSwatchLabel($input, $productAttributeWrapper) {
4530    // multi-pdp pages can have multiple selected swatch tiles, one for each product.
4531    // get the product wrapper for this swatch so we are only setting the label for the correct product.
4532    var $swatchLabel = $productAttributeWrapper.find(swatchLabel);
4533    var swatchData = $input.attr('data-swatch').toLowerCase();
4534
4535    if ($input.length > 0) {
4536      $swatchLabel.html(swatchData);
4537      $input.closest(productSection).attr('data-swatch', $input.attr('data-swatch').toLowerCase());
4538    }
4539  }
4540
4541  function updateSelectedSeq($input, $productAttributeWrapper) {
4542    // multi-pdp pages can have multiple selected swatch tiles, one for each product.
4543    // get the product wrapper for this swatch so we are only setting selected sequence for the correct product.
4544    var $skus = $productAttributeWrapper.find(productSkuSelectorClass);
4545    var newSeq = $input.attr('data-seq');
4546
4547    $skus.attr('data-selected-seq', newSeq);
4548    window.digitalData.set('product.data.sequence', newSeq);
4549  }
4550
4551  function updateSwatchSelectedProperty($selectedSwatch, $input) {
4552    $selectedSwatch
4553      .parents(productSwatchesSelectorClass)
4554      .find(swatchTile)
4555      .removeClass(selectedClass);
4556
4557    $selectedSwatch.addClass(selectedClass);
4558    $input.prop('checked', true);
4559  }
4560
4561  function getProductId($productSection) {
4562    return $productSection.attr('data-productid');
4563  }
4564
4565  function dataBridgeSwatchSelectHandler($productSection, productId) {
4566    var shortSku = $productSection.find(partNumberSelector).val() || null;
4567    var kic = Utils.getProductData(productId).kicId;
4568
4569    try {
4570      var productData = {
4571        kic: kic,
4572        shortSku: shortSku,
4573        productId: productId
4574      };
4575      window.digitalData.trigger('productInfo.swatchSelected', productData);
4576      window.dispatchEvent(new CustomEvent('crs:swatchSelected', { detail: productData }));
4577    } catch (error) {
4578      // do nothing
4579    }
4580  }
4581
4582  function getFromFirstProduct(productId, key) {
4583    var items;
4584    try {
4585      items = productPrices[productId].items;
4586    } catch (error) {
4587      // do nothing
4588    }
4589    var firstItem = items && Object.values(items)[0];
4590    return firstItem ? firstItem[key] : 'null';
4591  }
4592
4593  function getBadgeDataFromProduct(productId, key) {
4594    var productData = Utils.getProductData(productId);
4595    if (!productData) {
4596      return null;
4597    }
4598    var keys = key.split('.');
4599    return keys.reduce(function _reduce(acc, currKey) {
4600      return (acc && acc.hasOwnProperty(currKey)) ? acc[currKey] : null;
4601    }, productData);
4602  }
4603
4604  function getProductBadge(productId) {
4605    var isNewArrival = getBadgeDataFromProduct(productId, 'newArrival');
4606    var earlyAccessFlag = getBadgeDataFromProduct(productId, 'productAttrs.EarlyAccessIndicator');
4607    var isEarlyAccess = earlyAccessFlag ? earlyAccessFlag.toString().toLowerCase() === 'true' : false;
4608    var isTopRated = getBadgeDataFromProduct(productId, 'productAttrs.topRated');
4609    var isBestSeller = getBadgeDataFromProduct(productId, 'productAttrs.bestSeller');
4610    return [isNewArrival ? 'new' : '', isEarlyAccess ? 'early access' : '', isTopRated ? 'top rated' : '', isBestSeller ? 'top seller' : ''].filter(Boolean).join(', ');
4611  }
4612
4613  function triggerAnalyticsEvent(productId, longSku) {
4614    var clickedSwatches = window.digitalData.get('productSwatches.clicked') ? window.digitalData.get('productSwatches.clicked') : [];
4615    var hadBeenClickedCurrentSwatch = clickedSwatches.includes(productId);
4616
4617    if (hadBeenClickedCurrentSwatch) return;
4618
4619    clickedSwatches.push(productId);
4620    window.digitalData.set('productSwatches.clicked', clickedSwatches);
4621
4622    var productInfo = Utils.getProductData(productId);
4623    var dataPointEmptyValue = 'null';
4624
4625    var eventData = {};
4626    eventData[analyticsDataPoint.KEY_ITEM_COLOR] = productInfo.kicId;
4627    eventData[analyticsDataPoint.PRICE_LIST_LOCAL] = getFromFirstProduct(productId, 'listPrice') || dataPointEmptyValue;
4628    eventData[analyticsDataPoint.PRICE_LIST_USD] = getFromFirstProduct(productId, 'listPriceUSD') || dataPointEmptyValue;
4629    eventData[analyticsDataPoint.PRICE_OFFER_LOCAL] = getFromFirstProduct(productId, 'offerPrice') || dataPointEmptyValue;
4630    eventData[analyticsDataPoint.PRICE_OFFER_USD] = getFromFirstProduct(productId, 'offerPriceUSD') || dataPointEmptyValue;
4631    eventData[analyticsDataPoint.PRICE_FLAG] = getFromFirstProduct(productId, 'priceFlag') || dataPointEmptyValue;
4632    eventData[analyticsDataPoint.LONG_SKU] = longSku || dataPointEmptyValue;
4633    eventData[analyticsDataPoint.PRODUCT_ID] = productId || dataPointEmptyValue;
4634    eventData[analyticsDataPoint.PRODUCT_NAME] = productInfo.name || dataPointEmptyValue;
4635    eventData[analyticsDataPoint.COLLECTION_ID] = productInfo.collection || dataPointEmptyValue;
4636    eventData[analyticsDataPoint.BRAND] = productInfo.productAttrs.brand || dataPointEmptyValue;
4637    eventData[analyticsDataPoint.PRODUCT_BADGE] = getProductBadge(productId) || dataPointEmptyValue;
4638    window.digitalData.trigger(analyticsSubscriptionName.ACTION.SWATCH_CLICK, eventData);
4639  }
4640
4641  var publicMembers = {
4642    bindEvents: function bindEvents() {
4643      $(document).on('change', swatchTile, swatchClickEvent);
4644    },
4645    listen: function listen() {
4646      $(ANF).on('productPageInfo:load', swatchOnLoad);
4647      window.addEventListener('mfe:SwatchSelected', handleMfeSwatchChange);
4648    }
4649  };
4650
4651  return publicMembers;
4652});
4653
4654/*!
4655 * currency.js - v1.2.2
4656 * http://scurker.github.io/currency.js
4657 *
4658 * Copyright (c) 2019 Jason Wilson
4659 * Released under MIT license
4660 */
4661
4662(function (global, factory) {
4663  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4664  typeof redesign.define === 'function' && redesign.define.amd ? redesign.define('currency',factory) :
4665  (global = global || self, global.currency = factory());
4666}(this, function () { 'use strict';
4667
4668  var defaults = {
4669    symbol: '$',
4670    separator: ',',
4671    decimal: '.',
4672    formatWithSymbol: false,
4673    errorOnInvalid: false,
4674    precision: 2,
4675    pattern: '!#',
4676    negativePattern: '-!#'
4677  };
4678
4679  var round = function round(v) {
4680    return Math.round(v);
4681  };
4682
4683  var pow = function pow(p) {
4684    return Math.pow(10, p);
4685  };
4686
4687  var rounding = function rounding(value, increment) {
4688    return round(value / increment) * increment;
4689  };
4690
4691  var groupRegex = /(\d)(?=(\d{3})+\b)/g;
4692  var vedicRegex = /(\d)(?=(\d\d)+\d\b)/g;
4693  /**
4694   * Create a new instance of currency.js
4695   * @param {number|string|currency} value
4696   * @param {object} [opts]
4697   */
4698
4699  function currency(value, opts) {
4700    var that = this;
4701
4702    if (!(that instanceof currency)) {
4703      return new currency(value, opts);
4704    }
4705
4706    var settings = Object.assign({}, defaults, opts),
4707        precision = pow(settings.precision),
4708        v = parse(value, settings);
4709    that.intValue = v;
4710    that.value = v / precision; // Set default incremental value
4711
4712    settings.increment = settings.increment || 1 / precision; // Support vedic numbering systems
4713    // see: https://en.wikipedia.org/wiki/Indian_numbering_system
4714
4715    if (settings.useVedic) {
4716      settings.groups = vedicRegex;
4717    } else {
4718      settings.groups = groupRegex;
4719    } // Intended for internal usage only - subject to change
4720
4721
4722    this.s = settings;
4723    this.p = precision;
4724  }
4725
4726  function parse(value, opts) {
4727    var useRounding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
4728    var v = 0,
4729        decimal = opts.decimal,
4730        errorOnInvalid = opts.errorOnInvalid,
4731        decimals = opts.precision,
4732        precision = pow(decimals),
4733        isNumber = typeof value === 'number';
4734
4735    if (isNumber || value instanceof currency) {
4736      v = (isNumber ? value : value.value) * precision;
4737    } else if (typeof value === 'string') {
4738      var regex = new RegExp('[^-\\d' + decimal + ']', 'g'),
4739          decimalString = new RegExp('\\' + decimal, 'g');
4740      v = value.replace(/\((.*)\)/, '-$1') // allow negative e.g. (1.99)
4741      .replace(regex, '') // replace any non numeric values
4742      .replace(decimalString, '.') // convert any decimal values
4743      * precision; // scale number to integer value
4744
4745      v = v || 0;
4746    } else {
4747      if (errorOnInvalid) {
4748        throw Error('Invalid Input');
4749      }
4750
4751      v = 0;
4752    } // Handle additional decimal for proper rounding.
4753
4754
4755    v = v.toFixed(4);
4756    return useRounding ? round(v) : v;
4757  }
4758
4759  currency.prototype = {
4760    /**
4761     * Adds values together.
4762     * @param {number} number
4763     * @returns {currency}
4764     */
4765    add: function add(number) {
4766      var intValue = this.intValue,
4767          _settings = this.s,
4768          _precision = this.p;
4769      return currency((intValue += parse(number, _settings)) / _precision, _settings);
4770    },
4771
4772    /**
4773     * Subtracts value.
4774     * @param {number} number
4775     * @returns {currency}
4776     */
4777    subtract: function subtract(number) {
4778      var intValue = this.intValue,
4779          _settings = this.s,
4780          _precision = this.p;
4781      return currency((intValue -= parse(number, _settings)) / _precision, _settings);
4782    },
4783
4784    /**
4785     * Multiplies values.
4786     * @param {number} number
4787     * @returns {currency}
4788     */
4789    multiply: function multiply(number) {
4790      var intValue = this.intValue,
4791          _settings = this.s;
4792      return currency((intValue *= number) / pow(_settings.precision), _settings);
4793    },
4794
4795    /**
4796     * Divides value.
4797     * @param {number} number
4798     * @returns {currency}
4799     */
4800    divide: function divide(number) {
4801      var intValue = this.intValue,
4802          _settings = this.s;
4803      return currency(intValue /= parse(number, _settings, false), _settings);
4804    },
4805
4806    /**
4807     * Takes the currency amount and distributes the values evenly. Any extra pennies
4808     * left over from the distribution will be stacked onto the first set of entries.
4809     * @param {number} count
4810     * @returns {array}
4811     */
4812    distribute: function distribute(count) {
4813      var intValue = this.intValue,
4814          _precision = this.p,
4815          _settings = this.s,
4816          distribution = [],
4817          split = Math[intValue >= 0 ? 'floor' : 'ceil'](intValue / count),
4818          pennies = Math.abs(intValue - split * count);
4819
4820      for (; count !== 0; count--) {
4821        var item = currency(split / _precision, _settings); // Add any left over pennies
4822
4823        pennies-- > 0 && (item = intValue >= 0 ? item.add(1 / _precision) : item.subtract(1 / _precision));
4824        distribution.push(item);
4825      }
4826
4827      return distribution;
4828    },
4829
4830    /**
4831     * Returns the dollar value.
4832     * @returns {number}
4833     */
4834    dollars: function dollars() {
4835      return ~~this.value;
4836    },
4837
4838    /**
4839     * Returns the cent value.
4840     * @returns {number}
4841     */
4842    cents: function cents() {
4843      var intValue = this.intValue,
4844          _precision = this.p;
4845      return ~~(intValue % _precision);
4846    },
4847
4848    /**
4849     * Formats the value as a string according to the formatting settings.
4850     * @param {boolean} useSymbol - format with currency symbol
4851     * @returns {string}
4852     */
4853    format: function format(useSymbol) {
4854      var _this$_settings = this.s,
4855          pattern = _this$_settings.pattern,
4856          negativePattern = _this$_settings.negativePattern,
4857          formatWithSymbol = _this$_settings.formatWithSymbol,
4858          symbol = _this$_settings.symbol,
4859          separator = _this$_settings.separator,
4860          decimal = _this$_settings.decimal,
4861          groups = _this$_settings.groups,
4862          values = (this + '').replace(/^-/, '').split('.'),
4863          dollars = values[0],
4864          cents = values[1]; // set symbol formatting
4865
4866      typeof useSymbol === 'undefined' && (useSymbol = formatWithSymbol);
4867      return (this.value >= 0 ? pattern : negativePattern).replace('!', useSymbol ? symbol : '').replace('#', "".concat(dollars.replace(groups, '$1' + separator)).concat(ce
4867nts ? decimal + cents : ''));
4868    },
4869
4870    /**
4871     * Formats the value as a string according to the formatting settings.
4872     * @returns {string}
4873     */
4874    toString: function toString() {
4875      var intValue = this.intValue,
4876          _precision = this.p,
4877          _settings = this.s;
4878      return rounding(intValue / _precision, _settings.increment).toFixed(_settings.precision);
4879    },
4880
4881    /**
4882     * Value for JSON serialization.
4883     * @returns {float}
4884     */
4885    toJSON: function toJSON() {
4886      return this.value;
4887    }
4888  };
4889
4890  return currency;
4891
4892}));
4893
4894redesign.define('coreServices/klarna/messagePlacement',[
4895  'anfUtil/testFramework',
4896  'currency'
4897], function klarnaMessagePlacement(test, currency) {
4898  'use strict';
4899
4900  /**
4901   * @desc Reponsible for managing the Klarna Onsite Mesaging Script
4902   * @todo Refactor KlarnaMessaginScript and BaiduScript into a Script class responsible for loading the script
4903   * @private
4904   * @final
4905   */
4906
4907  var KlarnaMessagePlacementScript = {
4908    /**
4909     * @desc the deferred instance that will get resolved when Klarna Onsite Messaging Script is loaded
4910     * @property {Promise} deferred
4911     * @protected
4912     */
4913    deferred: null
4914  };
4915
4916  /**
4917   * @desc load the Klarna Onsite Messaging Script onto the DOM
4918   * @protected
4919   * @static
4920   * @return {Promise} Promise represents when the script has loaded
4921   */
4922
4923  KlarnaMessagePlacementScript.load = function load() {
4924    if (!this.deferred) {
4925      window.$LAB.script(this.getUrl()).wait(function wait() {
4926        this.getDeferred().resolve(this.find().get(0));
4927      }.bind(this));
4928    }
4929    return this.getDeferred().promise();
4930  };
4931
4932  /**
4933   * @desc get the URL to the Baidu Script
4934   * @protected
4935   * @static
4936   * @return {string}
4937   */
4938
4939  KlarnaMessagePlacementScript.getUrl = function getUrl() {
4940    return ANF.params.storeAttributes.klarnaOnsiteMessagingScriptURL;
4941  };
4942
4943  /**
4944   * @desc attempts to find the klarna script tag on the DOM
4945   * @protected
4946   * @static
4947   * @return {HTMLElement} A jQuery wrapped HTMLElement
4948   */
4949
4950  KlarnaMessagePlacementScript.find = function find() {
4951    var url = this.getUrl();
4952    return $('script').filter(function filter() {
4953      return String($(this).attr('src')).indexOf(url) >= 0 ? true : false;
4954    });
4955  };
4956
4957  /**
4958   * @desc get the Deferred() instance used to resolve when Klarna Onsite Messaging Script has been loaded
4959   * @protected
4960   * @static
4961   * @return {$.Deferred}
4962   */
4963
4964  KlarnaMessagePlacementScript.getDeferred = function getDeferred() {
4965    if (!this.deferred) {
4966      this.deferred = new $.Deferred();
4967    }
4968    return this.deferred;
4969  };
4970
4971  /**
4972   * @desc Responsible for controlling Klarna's Onsite Messaging
4973   * @public
4974   * @class
4975   * @final
4976   * @param {HTMLElement} [element] - The HTMLElement that reprsents the <klarna-placement /> tag wrapped in jQuery
4977   * @param {Object} [options] - Contains options for this KlarnaMessagePlacement
4978   * @param {Object} [options.threshold] - The treshold for determining if we can display the Klarna Onsite Messaging
4979   * @param {Number} [options.threshold.min] - The minimum threshold in the smallest unit of account
4980   * @param {Number} [options.threshold.max] - The maximum threshold in the smallest unit of account
4981   * @param {Function} [options.isWithinOtherConstraints] - A function that will return a boolean if conditions match other constraints. This method will replace this instance's isWithinOtherConstraints() function.
4982   * @exports KlarnaMessagePlacement
4983   */
4984
4985  function KlarnaMessagePlacement(options) {
4986    if (test.type.object(options)) {
4987      if (test.type.object(options.element)) {
4988        this.setElement(options.element);
4989      }
4990
4991      if (test.type.object(options.threshold)) {
4992        this.setThreshold(options.threshold);
4993      }
4994
4995      if (test.type.function(options.isWithinOtherConstraints)) {
4996        this.isWithinOtherConstraints = options.isWithinOtherConstraints;
4997      }
4998    }
4999    this.hide();
5000  }
5001
5002  /**
5003   * @desc The HTML element tag name for Klarna Message Placement
5004   * @public
5005   * @property {String}
5006   */
5007
5008  KlarnaMessagePlacement.TagName = 'klarna-placement';
5009
5010  /**
5011   * @desc The HTML element attribute name for setting / geting the purchase amount
5012   * @public
5013   * @property {String}
5014   */
5015
5016  KlarnaMessagePlacement.DataPurchaseAmountAttributeName = 'data-
5016purchase_amount';
5017
5018  /**
5019   * @desc The event name for trigger Klarna Message Placement updates
5020   * @public
5021   * @property {String}
5022   */
5023
5024  KlarnaMessagePlacement.RefreshPlacementsEventName = 'refresh-placements';
5025
5026  /**
5027   * @desc Parse a threshold that comes from a store attribute field 3
5028   * @public
5029   * @static
5030   * @param {String} value - comma separated string e.g. "35,1000"
5031   * @return {Object} containing a min and max field e.g. { min: 3500, max: 100000 }
5032   */
5033
5034  KlarnaMessagePlacement.parseThreshold = function parseThreshold(value) {
5035    var threshold = {};
5036
5037    if (!test.type.string(value)) {
5038      return threshold;
5039    }
5040
5041    var parts = value.split(',');
5042
5043    var min = parseNumber(parts.shift());
5044    if (test.type.number(min)) {
5045      threshold.min = min * 100; // use smallest unit of account
5046    }
5047
5048    var max = parseNumber(parts.shift());
5049    if (test.type.number(max)) {
5050      threshold.max = max * 100; // use smallest unit of account
5051    }
5052
5053    return threshold;
5054  };
5055
5056  /**
5057   * @desc Initializes the Klarna Onsite Messaging Script
5058   * @public
5059   * @instance
5060   * @return {Promise} Promise represents an HTMLElement <script />
5061   */
5062
5063  KlarnaMessagePlacement.prototype.getScriptTag = function getScriptTag() {
5064    var script = KlarnaMessagePlacementScript.find();
5065    if (script && script.length) {
5066      return new $.Deferred().resolve(script.get(0)).promise();
5067    }
5068    return KlarnaMessagePlacementScript.load();
5069  };
5070
5071  /**
5072   * @desc set the element that we are controlling
5073   * @public
5074   * @instance
5075   * @param {jQuery} element - Represents the <klarna-placement /> tag wrapped in jQuery
5076   * @return {KlarnaMessagePlacement} Represents the current instance for chaining
5077   */
5078
5079  KlarnaMessagePlacement.prototype.setElement = function setElement(element) {
5080    if (element) {
5081      this.element = $(element);
5082    }
5083    return this;
5084  };
5085
5086  /**
5087   * @desc get the element that we are controlling
5088   * @public
5089   * @instance
5090   * @return {jQuery} Represents the <klarna-placement /> tag wrapped in jQuery
5091   * @throws {Error} When there are no <klarna-placement /> tags on the DOM
5092   */
5093
5094  KlarnaMessagePlacement.prototype.getElement = function getElement() {
5095    if (!this.element) {
5096      this.setElement($(this.constructor.TagName));
5097    }
5098    return this.element;
5099  };
5100
5101  /**
5102   * @desc reset the message placement
5103   * @public
5104   * @instance
5105   * @return {KlarnaMessagePlacement}
5106   */
5107
5108  KlarnaMessagePlacement.prototype.reset = function reset() {
5109    this.element = null;
5110    return this;
5111  };
5112
5113  /**
5114   * @desc set the threshold for determining if we can display the Klarna Onsite Messaging
5115   * @public
5116   * @instance
5117   * @param {Object} threshold - The treshold for determining if we can display the Klarna Onsite Messaging
5118   * @param {Number} threshold.min - The minimum threshold in the smallest unit of account
5119   * @param {Number} threshold.max - The maximum threshold in the smallest unit of account
5120   * @return {KlarnaMessagePlacement} Represents the current instance for chaining
5121   */
5122
5123  KlarnaMessagePlacement.prototype.setThreshold = function setThreshold(threshold) {
5124    this.threshold = threshold;
5125    return this;
5126  };
5127
5128  /**
5129   * @desc get the threshold for determing if we can display the Klarna Onsite Messaging
5130   * @public
5131   * @instance
5132   * @return {Object} Represents the min and max threshold
5133   */
5134
5135  KlarnaMessagePlacement.prototype.getThreshold = function getThreshold() {
5136    if (!this.threshold) {
5137      this.setThreshold({});
5138    }
5139    return this.threshold;
5140  };
5141
5142  /**
5143   * @desc determine if the value is within the threshold
5144   * @public
5145   * @instance
5146   * @param {Number} value - Represents the value we are checking
5147   * @return {Boolean}
5148   */
5149
5150  KlarnaMessagePlacement.prototype.isWithinThreshold = function isWithinThreshold(value) {
5151    var threshold = this.getThreshold();
5152
5153    if (test.type.number(threshold.min)) {
5154      if (value < threshold.min) {
5155        return false;
5156      }
5157    }
5158
5159    if (test.type.number(threshold.max)) {
5160      if (value > threshold.max) {
5161        return false;
5162      }
5163    }
5164
5165    return true;
5166  };
5167
5168  /**
5169   * @desc Allows for an instance to supply additional constraints by overriding this method
5170   * @public
5171   * @instance
5172   * @override
5173   * @return {Boolean}
5174   */
5175
5176  KlarnaMessagePlacement.prototype.isWithinOtherConstraints = function isWithinOtherConstraints() {
5177    return true;
5178  };
5179
5180  /**
5181   * @desc Determine if the Klarna Onsite Messaging should be visible to the user based on the Klarna Card Brands
5182   * @public
5183   * @instance
5184   * @param {Number} value - The value used to determine if we can display or not
5185   * @return {Boolean}
5186   */
5187
5188  KlarnaMessagePlacement.prototype.canDisplay = function canDisplay(value) {
5189    return this.isWithinThreshold(value) && this.isWithinOtherConstraints();
5190  };
5191
5192  /**
5193   * @desc Updates the Klarna Onsite Messaging by setting the value on the element and pushing an event to Klarna
5194   * @public
5195   * @instance
5196   * @param {number} value - The value used to determine if we can display or not
5197   * @return {KlarnaMessagePlacement} Represents the current instance for chaining
5198   */
5199
5200  KlarnaMessagePlacement.prototype.update = function update(value) {
5201    try {
5202      var purchaseAmount = currency(value).intValue;
5203      this.getElement().attr(this.constructor.DataPurchaseAmountAttributeName, purchaseAmount);
5204      if (this.canDisplay(purchaseAmount)) {
5205        this.show();
5206      } else {
5207        this.hide();
5208      }
5209      window.KlarnaOnsiteService = window.KlarnaOnsiteService || [];
5210      window.KlarnaOnsiteService.push({
5211        eventName: this.constructor.RefreshPlacementsEventName
5212      });
5213    } finally {
5214      return this;
5215    }
5216  };
5217
5218  /**
5219   * @desc hide the placement
5220   * @public
5221   * @instance
5222   * @return {KlarnaMessagePlacement}
5223   */
5224
5225  KlarnaMessagePlacement.prototype.hide = function hide() {
5226    this.getElement().parent().hide();
5227    return this;
5228  };
5229
5230  /**
5231   * @desc show the placement
5232   * @public
5233   * @instance
5234   * @return {KlarnaMessagePlacement}
5235   */
5236
5237  KlarnaMessagePlacement.prototype.show = function show() {
5238    this.getElement().parent().show();
5239    return this;
5240  };
5241
5242  return KlarnaMessagePlacement;
5243
5244  /**
5245   * @desc parse a number
5246   * @private
5247   * @param {Number} value
5248   * @return {Number|undefined}
5249   */
5250
5251  function parseNumber(value) {
5252    var num = parseInt(value, 10);
5253    if (isNaN(num)) {
5254      return void 0;
5255    }
5256    return num;
5257  }
5258});
5259
5260redesign.define('productPartial/pdp_productPrice',['handlebars','dsPartial/product-price','dsPartial/product-price-text','wcsHelper/i18n'], function(Handlebars) {
5261
5262this["ANF"] = this["ANF"] || {};
5263this["ANF"]["templates"] = this["ANF"]["templates"] || {};
5264
5265Handlebars.registerPartial("pdp_productPrice", this["ANF"]["templates"]["pdp_productPrice"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
5266    var stack1;
5267
5268  return ((stack1 = container.invokePartial(partials["product-price"],depth0,{"name":"product-price","hash":{"brand":(depth0 != null ? depth0.productBrand : depth0),"clearance-text":(depth0 != null ? depth0.clearanceText : depth0),"description":(depth0 != null ? depth0.description : depth0),"type":"clearance","class-list":"js-main-price"},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
5269},"2":function(container,depth0,helpers,partials,data) {
5270    var stack1;
5271
5272  return ((stack1 = container.invokePartial(partials["product-price-text"],depth0,{"name":"product-price-text","hash":{"formatted-price":(depth0 != null ? depth0.price : depth0),"type":"original","size":"large"},"data":data,"indent":"\t\t","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
5273    + ((stack1 = container.invokePartial(partials["product-price-text"],depth0,{"name":"product-price-text","hash":{"formatted-price":(depth0 != null ? depth0.discountPrice : depth0),"type":"discount","size":"large"},"data":data,"indent":"\t\t","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
5274},"4":function(container,depth0,helpers,partials,data) {
5275    var stack1;
5276
5277  return ((stack1 = container.invokePartial(partials["product-price"],depth0,{"name":"product-price","hash":{"brand":(depth0 != null ? depth0.productBrand : depth0),"description":(depth0 != null ? depth0.description : depth0),"class-list":"js-main-price"},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
5278},"5":function(container,depth0,helpers,partials,data) {
5279    var stack1;
5280
5281  return ((stack1 = container.invokePartial(partials["product-price-text"],depth0,{"name":"product-price-text","hash":{"formatted-price":(depth0 != null ? depth0.price : depth0),"size":"large"},"data":data,"indent":"\t\t","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
5282},"7":function(container,depth0,helpers,partials,data) {
5283    var stack1;
5284
5285  return ((stack1 = container.invokePartial(partials["product-price"],depth0,{"name":"product-price","hash":{"brand":(depth0 != null ? depth0.productBrand : depth0),"clearance-text":helpers.i18n.call(depth0 != null ? depth0 : (container.nullContext || {}),"loyalty.MEMBER_CLEARANCE",{"name":"i18n","hash":{},"data":data}),"description":(depth0 != null ? depth0.memberPriceDescription : depth0),"type":"member","class-list":"js-member-price"},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
5286},"8":function(container,depth0,helpers,partials,data) {
5287    var stack1;
5288
5289  return ((stack1 = container.invokePartial(partials["product-price-text"],depth0,{"name":"product-price-text","hash":{"formatted-price":(depth0 != null ? depth0.memberPrice : depth0),"type":"member","size":"large"},"data":data,"indent":"\t\t","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
5290},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
5291    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
5292
5293  return "\n"
5294    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isClearance : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.program(4, data, 0),"data":data})) != null ? stack1 : "")
5295    + "\n"
5296    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasMemberPrice : depth0),{"name":"if","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
5297},"usePartial":true,"useData":true}));
5298
5299return this["ANF"];
5300
5301});
5302redesign.define('productModules/product/productPrice',[
5303  'anfUtil/testFramework',
5304  'coreServices/klarna/messagePlacement',
5305  'anfUtil/constants',
5306  'productPartial/pdp_productPrice',
5307  'productModules/helpers/Utils'
5308], function productPrice(
5309  test,
5310  KlarnaMessagePlacement,
5311  coreConstants,
5312  productPartialPdpProductPrice,
5313  Utils
5314) {
5315  'use strict';
5316
5317  // Aliasing this as variable since we can't use const yet
5318
5319  // Constants
5320  var priceContainerSelector = '.js-product-price';
5321  var priceTextSelector = '.product-price-text';
5322  var skuSelect = '.product-page__skus';
5323
5324  var memberPricing = {
5325    contractPrice: 0,
5326    contractPriceFmt: ''
5327  };
5328
5329  var klarna = {
5330    messagePlacement: null,
5331    threshold: KlarnaMessagePlacement.parseThreshold(ANF.params.storeAttributes.klarnaOnsiteMessagingProductThreshold),
5332    hasKlarnaOnsiteMessaging: function hasKlarnaOnsiteMessaging() {
5333      return ANF.params.storeAttributes.hasKlarnaOnsiteMessagingProduct;
5334    },
5335    isWithinOtherConstraints: function isWithinOtherConstraints() {
5336      return this.hasKlarnaOnsiteMessaging();
5337    },
5338    getMessagePlacement: function getMessagePlacement() {
5339      var deferred = new $.Deferred();
5340
5341      if (!this.messagePlacement) {
5342        this.messagePlacement = new KlarnaMessagePlacement({
5343          threshold: this.threshold,
5344          isWithinOtherConstraints: this.isWithinOtherConstraints.bind(this)
5345        });
5346      }
5347
5348      if (!this.hasKlarnaOnsiteMessaging()) {
5349        return deferred.resolve(this.messagePlacement).promise();
5350      }
5351
5352      this.messagePlacement.getScriptTag().done(function done() {
5353        deferred.resolve(this.messagePlacement);
5354      }.bind(this));
5355
5356      return deferred.promise();
5357    }
5358  };
5359
5360  function updatePricetag(sku, productContainer) {
5361    var priceModel = {
5362      isClearance: false,
5363      price: '',
5364      hasMemberPrice: false,
5365      productBrand: Utils.getProductData(productContainer.data('productid')).productAttrs.brand
5366    };
5367    var $priceContainer = productContainer.find(priceContainerSelector);
5368    var contractPrice = memberPricing.contractPrice;
5369    var contractPriceFmt = memberPricing.contractPriceFmt;
5370
5371    /* Handle main price */
5372    priceModel.price = sku.listPriceFmt;
5373    priceModel.description = sku.listPriceFmt;
5374    if (sku.listPrice !== sku.offerPrice) { // Discount price
5375      priceModel.discountPrice = sku.offerPriceFmt;
5376      priceModel.isClearance = true;
5377      if (sku.priceFlag === '2' || sku.priceFlag === '7') {
5378        priceModel.clearanceText = ANF.messaging.catalogV2.TMNT.cardClearance.value;
5379      }
5380      priceModel.description = ANF.messaging.product.GLB_PRICE_DESC_IND_IND.replace('{0}', sku.listPriceFmt)
5381        .replace('{1}', sku.offerPriceFmt);
5382    }
5383
5384    var klarnaPrice = priceModel.discountPrice || priceModel.price;
5385
5386    if (hasMemberPrice(contractPrice, sku)) {
5387      klarnaPrice = contractPrice;
5388      priceModel.hasMemberPrice = true;
5389      priceModel.memberPriceDescription = contractPriceFmt;
5390      priceModel.memberPrice = contractPriceFmt;
5391    }
5392
5393    $priceContainer.empty().html(productPartialPdpProductPrice.templates.pdp_productPrice(priceModel));
5394    $priceContainer.find(priceTextSelector).addClass('ds-override');
5395    if (klarna.hasKlarnaOnsiteMessaging()) {
5396      klarna.getMessagePlacement().done(function done(messagePlacement) {
5397        messagePlacement.reset().update(klarnaPrice);
5398      });
5399    }
5400
5401    if (ANF.params.storeAttributes.checkout.hasPayOverTimeMessagingProduct) {
5402      window.dispatchEvent(new CustomEvent('payOverTime:refresh', {
5403        detail: {
5404          purchaseAmount: parseFloat(String(klarnaPrice).replace(/[^0-9\.]/, '')),
5405          page: 'product'
5406        }
5407      }));
5408    }
5409  }
5410
5411  function hasMemberPrice(contractPrice, sku) {
5412    return coreConstants.anf('params.storeAttributes.loyalty.memberPricingEnabled') &&
5413    (contractPrice && contractPrice > 0) &&
5414    (contractPrice < sku.listPrice && contractPrice < sku.offerPrice);
5415  }
5416
5417  function updateSwatchPrice(e, data) {
5418    if (typeof data === 'object' && typeof data.productId !== 'undefined') {
5419      var kicSkus = $(data.skuContainer).find(skuSelect).find('option[data-kic=' + data.kic + ']');
5420
5421      if (kicSkus.length > 0) {
5422        var sku = data.productPrices[data.productId].items[kicSkus[0].value];
5423
5424        setContractPricing(data.productPrices[data.productId]);
5425
5426        if (sku) {
5427          updatePricetag(sku, $(data.productSection));
5428          reRenderGermanVAT(sku);
5429        }
5430      }
5431    }
5432  }
5433
5434  function updateSkuPrice(e, data) {
5435    if ( typeof data === 'object' && typeof data.productId !== 'undefined' && typeof data.skuId !== 'undefined' ) {
5436      var sku = data.productPrices[data.productId].items[data.skuId];
5437
5438      setContractPricing(data.productPrices[data.productId]);
5439      updatePricetag(sku, $(data.productSection));
5440      reRenderGermanVAT(sku);
5441    }
5442  }
5443
5444  function setContractPricing(product) {
5445    if (product !== null && test.type.object(product)) {
5446      memberPricing.contractPrice = product.lowContractPrice ? product.lowContractPrice : 0;
5447      memberPricing.contractPriceFmt = product.lowContractPriceFmt ? product.lowContractPriceFmt : '';
5448    }
5449  }
5450
5451  function isPromotionalPricing(sku) {
5452    if (!sku) {
5453      return false;
5454    }
5455    var contractPrice = memberPricing.contractPrice || 0;
5456    var priceFlag = sku.priceFlag;
5457    var hasDiscountPricing = (sku.listPrice !== sku.offerPrice);
5458    var hasMemberPricing = (contractPrice > 0 && contractPrice < sku.listPrice && contractPrice < sku.offerPrice);
5459    var hasPriceFlag = (priceFlag === '2' || priceFlag === '7');
5460    var hasPromoMessage = (sku.merchPromoMsgType && sku.merchPromoMsg);
5461    var result = (hasMemberPricing || hasDiscountPricing || hasPriceFlag || hasPromoMessage);
5462    return result;
5463  }
5464
5465  function reRenderGermanVAT(sku) {
5466    var $vatContainer = $('.js-german-vat-container');
5467    if (!$vatContainer.length) return;
5468
5469    var germanVatText = $vatContainer.data('vat-text') || '';
5470    $vatContainer.empty();
5471
5472    var className = isPromotionalPricing(sku)
5473      ? 'product-price-german-tax-discounted'
5474      : 'product-price-german-tax';
5475
5476    $vatContainer.html(
5477      '<div class="' + className + '" data-property="GERMAN_INCLUDE_TAX">' +
5478        germanVatText +
5479      '</div>'
5480    );
5481  }
5482
5483  var publicMembers = {
5484    listen: function listen() {
5485      $(ANF).on('productPrice:swatchSelected', updateSwatchPrice);
5486      $(ANF).on('productPrice:skuSelected', updateSkuPrice);
5487    }
5488  };
5489
5490  return publicMembers;
5491}
5492);
5493
5494!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():'function' === typeof redesign.define && redesign.define.amd?redesign.define('anfDataBridge',[],e):"object"==typeof exports?exports.DataBridge=e():t.DataBridge=e()}(self,()=>(()=>{"use strict";var t={d:(e,r)=>{for(var n in r)t.o(r,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:r[n]})}};t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),t.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var e={};function r(t){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r(t)}t.d(e,{default:()=>St});var n=function(){return"undefined"!=typeof window?window:void 0!==t.g?t.g:Object.create(null)};function o(t){var e,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:new WeakMap;if(null===t||"object"!==r(t))return t;if(i.has(t))return i.get(t);if(t instanceof Date)return e=new Date(t.getTime()),i.set(t,e),e;if(t instanceof RegExp)return e=new RegExp(t.source,t.flags),i.set(t,e),e;if(t instanceof Error)return e=new t.constructor(t.message),i.set(t,e),t.stack&&Object.defineProperty(e,"stack",{value:t.stack,writable:!0,configurable:!0}),void 0!==t.cause&&(e.cause=o(t.cause,i)),Object.getOwnPropertyNames(t).forEach(function(r){if("stack"!==r&&"message"!==r&&"cause"!==r)try{e[r]=o(t[r],i)}catch(t){}}),e;if(Array.isArray(t)){e=new Array(t.length),i.set(t,e);for(var u=0;u<t.length;u++)e[u]=o(t[u],i);return e}if(t instanceof Map)return e=new Map,i.set(t,e),t.forEach(function(t,r){e.set(o(r,i),o(t,i))}),e;if(t instanceof Set)return e=new Set,i.set(t,e),t.forEach(function(t){e.add(o(t,i))}),e;if("undefined"!=typeof ArrayBuffer&&t instanceof ArrayBuffer)return e=t.slice(0),i.set(t,e),e;if("undefined"!=typeof ArrayBuffer&&t&&t.buffer instanceof ArrayBuffer){var a=t.constructor.name,s=n();if(/^(Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array|BigInt64Array|BigUint64Array)$/.test(a)){var c=o(t.buffer,i);return"function"==typeof s[a]?(e=new s[a](c,t.byteOffset,t.length),i.set(t,e),e):(e=new Uint8Array(c,t.byteOffset,t.byteLength),i.set(t,e),e)}}if("undefined"!=typeof DataView&&t instanceof DataView){var f=o(t.buffer,i);return e=new DataView(f,t.byteOffset,t.byteLength),i.set(t,e),e}if("undefined"!=typeof CustomEvent&&t instanceof CustomEvent){var l=t.type,p=t.detail,y=t.bubbles,b=void 0!==y&&y,v=t.cancelable,h=void 0!==v&&v,d=t.composed,m={bubbles:b,cancelable:h,composed:void 0!==d&&d,detail:void 0!==p?o(p,i):void 0};try{return e=new CustomEvent(l,m),i.set(t,e),e}catch(e){var g=document.createEvent("CustomEvent");return g.initCustomEvent(l,b,h,m.detail),i.set(t,g),g}}if("undefined"!=typeof Event&&t instanceof Event&&!(t instanceof CustomEvent)){var w=t.type,S=t.bubbles,O=void 0!==S&&S,_=t.cancelable,A=void 0!==_&&_,j=t.composed,E=void 0!==j&&j;try{return e=new Event(w,{bubbles:O,cancelable:A,composed:E}),i.set(t,e),e}catch(e){var x=document.createEvent("Event");return x.initEvent(w,O,A),i.set(t,x),x}}if("undefined"!=typeof Blob&&t instanceof Blob)return e=t.slice(0,t.size,t.type),i.set(t,e),e;if("undefined"!=typeof File&&t instanceof File)try{return e=new File([t],t.name,{type:t.type,lastModified:t.lastModified}),i.set(t,e),e}catch(r){return(e=t.slice(0,t.size,t.type)).name=t.name,e.lastModified=t.lastModified,i.set(t,e),e}if("undefined"!=typeof URL&&t instanceof URL)return e=new URL(t.href),i.set(t,e),e;if("undefined"!=typeof URLSearchParams&&t instanceof URLSearchParams)return e=new URLSearchParams(t.toString()),i.set(t,e),e;if("undefined"!=typeof FormData&&t instanceof FormData)return e=new FormData,i.set(t,e),t.forEach(function(t,r){e.append(r,t)}),e;e=Object.create(Object.getPrototypeOf(t)),i.set(t,e);for(var P=Object.getOwnPropertyDescriptors(t),T=Object.keys(P),k={},C=0;C<T.length;C++){var I=T[C],M=P[I];void 0!==M.value&&(M.value=o(M.value,i)),k[I]=M}if(Object.defineProperties(e,k),"undefined"!=typeof Symbol)for(var U=Object.getOwnPropertySymbols(t),z=0;z<U.length;z++){var F=U[z],D=Object.getOwnPropertyDescriptor(t,F);void 0!==D.value&&(D.value=o(D.value,i)),Object.defineProperty(e,F,D)}return e}var i=n();function u(t){var e=new WeakMap,n=function t(n){if(null===n||"object"!==r(n))return n;if(e.has(n))return e.get(n);if("undefined"!=typeof CustomEvent&&n instanceof CustomEvent){var o={__isCustomEvent:!0,type:n.type,detail:n.detail?t(n.detail):void 0,bubbles:n.bubbles,cancelable:n.cancelable,composed:n.composed};return e.set(n,o),o}if(Array.isArray(n)){var i=[];e.set(n,i);for(var u=0;u<n.length;u++)i[u]=t(n[u]);return i}if(n instanceof Map){var a=new Map;
5494return e.set(n,a),n.forEach(function(e,r){a.set(t(r),t(e))}),a}if(n instanceof Set){var s=new Set;return e.set(n,s),n.forEach(function(e){s.add(t(e))}),s}var c=Array.isArray(n)?[]:Object.create(Object.getPrototypeOf(n));return e.set(n,c),Object.getOwnPropertyNames(n).forEach(function(e){Object.prototype.hasOwnProperty.call(n,e)&&(c[e]=t(n[e]))}),c}(t);return structuredClone(n)}"function"!=typeof i.structuredClone&&(i.structuredClone=o);var a=function(t,e){return a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},a(t,e)};function s(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}a(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}function c(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function f(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),u=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)u.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return u}function l(t,e,r){if(r||2===arguments.length)for(var n,o=0,i=e.length;o<i;o++)!n&&o in e||(n||(n=Array.prototype.slice.call(e,0,o)),n[o]=e[o]);return t.concat(n||Array.prototype.slice.call(e))}function p(t){return"function"==typeof t}function y(t){var e=t(function(t){Error.call(t),t.stack=(new Error).stack});return e.prototype=Object.create(Error.prototype),e.prototype.constructor=e,e}Object.create,Object.create,"function"==typeof SuppressedError&&SuppressedError;var b=y(function(t){return function(e){t(this),this.message=e?e.length+" errors occurred during unsubscription:\n"+e.map(function(t,e){return e+1+") "+t.toString()}).join("\n  "):"",this.name="UnsubscriptionError",this.errors=e}});function v(t,e){if(t){var r=t.indexOf(e);0<=r&&t.splice(r,1)}}var h=function(){function t(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}var e;return t.prototype.unsubscribe=function(){var t,e,r,n,o;if(!this.closed){this.closed=!0;var i=this._parentage;if(i)if(this._parentage=null,Array.isArray(i))try{for(var u=c(i),a=u.next();!a.done;a=u.next())a.value.remove(this)}catch(e){t={error:e}}finally{try{a&&!a.done&&(e=u.return)&&e.call(u)}finally{if(t)throw t.error}}else i.remove(this);var s=this.initialTeardown;if(p(s))try{s()}catch(t){o=t instanceof b?t.errors:[t]}var y=this._finalizers;if(y){this._finalizers=null;try{for(var v=c(y),h=v.next();!h.done;h=v.next()){var d=h.value;try{g(d)}catch(t){o=null!=o?o:[],t instanceof b?o=l(l([],f(o)),f(t.errors)):o.push(t)}}}catch(t){r={error:t}}finally{try{h&&!h.done&&(n=v.return)&&n.call(v)}finally{if(r)throw r.error}}}if(o)throw new b(o)}},t.prototype.add=function(e){var r;if(e&&e!==this)if(this.closed)g(e);else{if(e instanceof t){if(e.closed||e._hasParent(this))return;e._addParent(this)}(this._finalizers=null!==(r=this._finalizers)&&void 0!==r?r:[]).push(e)}},t.prototype._hasParent=function(t){var e=this._parentage;return e===t||Array.isArray(e)&&e.includes(t)},t.prototype._addParent=function(t){var e=this._parentage;this._parentage=Array.isArray(e)?(e.push(t),e):e?[e,t]:t},t.prototype._removeParent=function(t){var e=this._parentage;e===t?this._parentage=null:Array.isArray(e)&&v(e,t)},t.prototype.remove=function(e){var r=this._finalizers;r&&v(r,e),e instanceof t&&e._removeParent(this)},t.EMPTY=((e=new t).closed=!0,e),t}(),d=h.EMPTY;function m(t){return t instanceof h||t&&"closed"in t&&p(t.remove)&&p(t.add)&&p(t.unsubscribe)}function g(t){p(t)?t():t.unsubscribe()}var w=null,S=null,O=void 0,_=!1,A=!1,j={setTimeout:function(t,e){for(var r=[],n=2;n<arguments.length;n++)r[n-2]=arguments[n];var o=j.delegate;return(null==o?void 0:o.setTimeout)?o.setTimeout.apply(o,l([t,e],f(r))):setTimeout.apply(void 0,l([t,e],f(r)))},clearTimeout:function(t){var e=j.delegate;return((null==e?void 0:e.clearTimeout)||clearTimeout)(t)},delegate:void 0};function E(){}var x=P("C",void 0,void 0);function P(t,e,r){return{kind:t,value:e,error:r}}var T=null;function k(t){if(_){var e=!T;if(e&&(T={errorThrown:!1,error:null}),t(),e){var r=T,n=r.errorThrown,o=r.error;if(T=null,n)throw o}}else t()}var C=function(t){function e(e){var r=t.call(this)||this;return r.isStopped=!1,e?(r.destination=e,m(e)&&e.add(r)):r.destination=N,r}return s(e,t),e.create=function(t,e,r){return new z(t,e,r)},e.prototype.next=function(t){this.isStopped?D(function(t){return P("N",t,void 0)}(t),this):this._next(t)},e.prototype.error=function(t){this.isStopped?D(P("E",void 0,t),this):(this.isStopped=!0,this._error(t))},e.prototype.complete=function(){this.isStopped?D(x,this):(this.isStopped=!0,this._complete())},e.prototype.unsubscribe=function(){this.closed||(this.isStopped=!0,t.prototype.unsubscribe.call(this),this.destination=null)},e.prototype._next=function(t){this.destination.next(t)},e.prototype._error=function(t){try{this.destination.error(t)}finally{this.unsubscribe()}},e.prototype._complete=function(){try{this.destination.complete()}finally{this.unsubscribe()}},e}(h),I=Function.prototype.bind;function M(t,e){return I.call(t,e)}var U=function(){function t(t){this.partialObserver=t}return t.prototype.next=function(t){var e=this.partialObserver;if(e.next)try{e.next(t)}catch(t){F(t)}},t.prototype.error=function(t){var e=this.partialObserver;if(e.error)try{e.error(t)}catch(t){F(t)}else F(t)},t.prototype.complete=function(){var t=this.partialObserver;if(t.complete)try{t.complete()}catch(t){F(t)}},t}(),z=function(t){function e(e,r,n){var o,i,u=t.call(this)||this;return p(e)||!e?o={next:null!=e?e:void 0,error:null!=r?r:void 0,complete:null!=n?n:void 0}:u&&A?((i=Object.create(e)).unsubscribe=function(){return u.unsubscribe()},o={next:e.next&&M(e.next,i),error:e.error&&M(e.error,i),complete:e.complete&&M(e.complete,i)}):o=e,u.destination=new U(o),u}return s(e,t),e}(C);function F(t){var e;_?(e=t,_&&T&&(T.errorThrown=!0,T.error=e)):function(t){j.setTimeout(function(){if(!w)throw t;w(t)})}(t)}function D(t,e){var r=S;r&&j.setTimeout(function(){return r(t,e)})}var N={closed:!0,next:E,error:function(t){throw t},complete:E},B="function"==typeof Symbol&&Symbol.observable||"@@observable";function R(t){return t}var W=function(){function t(t){t&&(this._subscribe=t)}return t.prototype.lift=function(e){var r=new t;return r.source=this,r.operator=e,r},t.prototype.subscribe=function(t,e,r){var n,o=this,i=(n=t)&&n instanceof C||function(t){return t&&p(t.next)&&p(t.error)&&p(t.complete)}(n)&&m(n)?t:new z(t,e,r);return k(function(){var t=o,e=t.operator,r=t.source;i.add(e?e.call(i,r):r?o._subscribe(i):o._trySubscribe(i))}),i},t.prototype._trySubscribe=function(t){try{return this._subscribe(t)}catch(e){t.error(e)}},t.prototype.forEach=function(t,e){var r=this;return new(e=L(e))(function(e,n){var o=new z({next:function(e){try{t(e)}catch(t){n(t),o.unsubscribe()}},error:n,complete:e});r.subscribe(o)})},t.prototype._subscribe=function(t){var e;return null===(e=this.source)||void 0===e?void 0:e.subscribe(t)},t.prototype[B]=function(){return this},t.prototype.pipe=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];return(0===(r=t).length?R:1===r.length?r[0]:function(t){return r.reduce(function(t,e){return e(t)},t)})(this);var r},t.prototype.toPromise=function(t){var e=this;return new(t=L(t))(function(t,r){var n;e.subscribe(function(t){return n=t},function(t){return r(t)},function(){return t(n)})})},t.create=function(e){return new t(e)},t}();function L(t){var e;return null!==(e=null!=t?t:O)&&void 0!==e?e:Promise}var V=y(function(t){return function(){t(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"}}),$=function(t){function e(){var e=t.call(this)||this;return e.closed=!1,e.currentObservers=null,e.observers=[],e.isStopped=!1,e.hasError=!1,e.thrownError=null,e}return s(e,t),e.prototype.lift=function(t){var e=new Y(this,this);return e.operator=t,e},e.prototype._throwIfClosed=function(){if(this.closed)throw new V},e.prototype.next=function(t){var e=this;k(function(){var r,n;if(e._throwIfClosed(),!e.isStopped){e.currentObservers||(e.currentObservers=Array.from(e.observers));try{for(var o=c(e.currentObservers),i=o.next();!i.done;i=o.next())i.value.next(t)}catch(t){r={error:t}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}}})},e.prototype.error=function(t){var e=this;k(function(){if(e._throwIfClosed(),!e.isStopped){e.hasError=e.isStopped=!0,e.thrownError=t;for(var r=e.observers;r.length;)r.shift().error(t)}})},e.prototype.complete=function(){var t=this;k(function(){if(t._throwIfClosed(),!t.isStopped){t.isStopped=!0;for(var e=t.observers;e.length;)e.shift().complete()}})},e.prototype.unsubscribe=function(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null},Object.defineProperty(e.prototype,"observed",{get:function(){var t;return(null===(t=this.observers)||void 0===t?void 0:t.length)>0}
5494,enumerable:!1,configurable:!0}),e.prototype._trySubscribe=function(e){return this._throwIfClosed(),t.prototype._trySubscribe.call(this,e)},e.prototype._subscribe=function(t){return this._throwIfClosed(),this._checkFinalizedStatuses(t),this._innerSubscribe(t)},e.prototype._innerSubscribe=function(t){var e=this,r=this,n=r.hasError,o=r.isStopped,i=r.observers;return n||o?d:(this.currentObservers=null,i.push(t),new h(function(){e.currentObservers=null,v(i,t)}))},e.prototype._checkFinalizedStatuses=function(t){var e=this,r=e.hasError,n=e.thrownError,o=e.isStopped;r?t.error(n):o&&t.complete()},e.prototype.asObservable=function(){var t=new W;return t.source=this,t},e.create=function(t,e){return new Y(t,e)},e}(W),Y=function(t){function e(e,r){var n=t.call(this)||this;return n.destination=e,n.source=r,n}return s(e,t),e.prototype.next=function(t){var e,r;null===(r=null===(e=this.destination)||void 0===e?void 0:e.next)||void 0===r||r.call(e,t)},e.prototype.error=function(t){var e,r;null===(r=null===(e=this.destination)||void 0===e?void 0:e.error)||void 0===r||r.call(e,t)},e.prototype.complete=function(){var t,e;null===(e=null===(t=this.destination)||void 0===t?void 0:t.complete)||void 0===e||e.call(t)},e.prototype._subscribe=function(t){var e,r;return null!==(r=null===(e=this.source)||void 0===e?void 0:e.subscribe(t))&&void 0!==r?r:d},e}($),G=function(t){function e(e){var r=t.call(this)||this;return r._value=e,r}return s(e,t),Object.defineProperty(e.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),e.prototype._subscribe=function(e){var r=t.prototype._subscribe.call(this,e);return!r.closed&&e.next(this._value),r},e.prototype.getValue=function(){var t=this,e=t.hasError,r=t.thrownError,n=t._value;if(e)throw r;return this._throwIfClosed(),n},e.prototype.next=function(e){t.prototype.next.call(this,this._value=e)},e}($),K={now:function(){return(K.delegate||Date).now()},delegate:void 0},X=function(t){function e(e,r,n){void 0===e&&(e=1/0),void 0===r&&(r=1/0),void 0===n&&(n=K);var o=t.call(this)||this;return o._bufferSize=e,o._windowTime=r,o._timestampProvider=n,o._buffer=[],o._infiniteTimeWindow=!0,o._infiniteTimeWindow=r===1/0,o._bufferSize=Math.max(1,e),o._windowTime=Math.max(1,r),o}return s(e,t),e.prototype.next=function(e){var r=this,n=r.isStopped,o=r._buffer,i=r._infiniteTimeWindow,u=r._timestampProvider,a=r._windowTime;n||(o.push(e),!i&&o.push(u.now()+a)),this._trimBuffer(),t.prototype.next.call(this,e)},e.prototype._subscribe=function(t){this._throwIfClosed(),this._trimBuffer();for(var e=this._innerSubscribe(t),r=this._infiniteTimeWindow,n=this._buffer.slice(),o=0;o<n.length&&!t.closed;o+=r?1:2)t.next(n[o]);return this._checkFinalizedStatuses(t),e},e.prototype._trimBuffer=function(){var t=this,e=t._bufferSize,r=t._timestampProvider,n=t._buffer,o=t._infiniteTimeWindow,i=(o?1:2)*e;if(e<1/0&&i<n.length&&n.splice(0,n.length-i),!o){for(var u=r.now(),a=0,s=1;s<n.length&&n[s]<=u;s+=2)a=s;a&&n.splice(0,a+1)}},e}($);function q(t){return function(e){if(function(t){return p(null==t?void 0:t.lift)}(e))return e.lift(function(e){try{return t(e,this)}catch(t){this.error(t)}});throw new TypeError("Unable to lift unknown Observable type")}}function H(t,e,r,n,o){return new J(t,e,r,n,o)}var J=function(t){function e(e,r,n,o,i,u){var a=t.call(this,e)||this;return a.onFinalize=i,a.shouldUnsubscribe=u,a._next=r?function(t){try{r(t)}catch(t){e.error(t)}}:t.prototype._next,a._error=o?function(t){try{o(t)}catch(t){e.error(t)}finally{this.unsubscribe()}}:t.prototype._error,a._complete=n?function(){try{n()}catch(t){e.error(t)}finally{this.unsubscribe()}}:t.prototype._complete,a}return s(e,t),e.prototype.unsubscribe=function(){var e;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){var r=this.closed;t.prototype.unsubscribe.call(this),!r&&(null===(e=this.onFinalize)||void 0===e||e.call(this))}},e}(C);function Q(t,e){return t===e}function Z(t,e,r){if(null==t)return r;if(null==e)return r;if("string"==typeof e&&-1===e.indexOf(".")&&-1===e.indexOf("["))return void 0===t[e]?r:t[e];var n;if(Array.isArray(e))n=e;else try{n=e.toString().replace(/\[(\d+)\]/g,".$1").split(".")}catch(t){return r}for(var o=t,i=0;i<n.length;i++){var u=n[i];if(""!==u){if(null==o)return r;void 0!==(o=o[u])&&""===n[i+1]&&void 0!==o[""]&&(o=o[""],i++)}}return void 0===o?r:o}function tt(t){return tt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},tt(t)}function et(t){if(null===t||"object"!==tt(t))return!1;var e=Object.getPrototypeOf(t);if(null===e)return!0;var r=Object.prototype.hasOwnProperty.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&Function.prototype.toString.call(r)===Function.prototype.toString.call(Object)}function rt(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=Array(e);r<e;r++)n[r]=t[r];return n}function nt(t){return nt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},nt(t)}function ot(t,e){if(t===e)return 0!==t||0!==e||1/t==1/e;if(null==t||null==e)return t===e;var r=nt(t),n=nt(e);if("number"===r&&"number"===n&&Number.isNaN(t)&&Number.isNaN(e))return!0;
5494if("object"===r&&"object"!==n||"object"!==r&&"object"===n)return("string"===r||"number"===r||"boolean"===r)&&t==e||("string"===n||"number"===n||"boolean"===n)&&t==e;if("object"!==r||"object"!==n)return!1;if(Array.isArray(t)&&Array.isArray(e)){if(t.length!==e.length)return!1;for(var o=0;o<t.length;o+=1){var i=o in t;if(i!==o in e)return!1;if(i&&!ot(t[o],e[o]))return!1}return!0}if(Array.isArray(t)||Array.isArray(e))return!1;if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(t instanceof RegExp&&e instanceof RegExp)return t.toString()===e.toString();if(t instanceof Map&&e instanceof Map)return t.size===e.size&&Array.from(t.entries()).every(function(t){var r,n,o=(n=2,function(t){if(Array.isArray(t))return t}(r=t)||function(t,e){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var n,o,i,u,a=[],s=!0,c=!1;try{if(i=(r=r.call(t)).next,0===e){if(Object(r)!==r)return;s=!1}else for(;!(s=(n=i.call(r)).done)&&(a.push(n.value),a.length!==e);s=!0);}catch(t){c=!0,o=t}finally{try{if(!s&&null!=r.return&&(u=r.return(),Object(u)!==u))return}finally{if(c)throw o}}return a}}(r,n)||function(t,e){if(t){if("string"==typeof t)return rt(t,e);var r={}.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?rt(t,e):void 0}}(r,n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),i=o[0],u=o[1];return e.has(i)&&ot(u,e.get(i))});if(t instanceof Set&&e instanceof Set){if(t.size!==e.size)return!1;var u=Array.from(t),a=Array.from(e);return u.every(function(t){return a.some(function(e){return ot(t,e)})})}if(t instanceof Error&&e instanceof Error)return t.name===e.name&&t.message===e.message;if("function"==typeof t.valueOf&&"function"==typeof e.valueOf){var s=t.valueOf(),c=e.valueOf();if(s!==t||c!==e)return ot(s,c)}if(et(t)&&et(e)){var f=Object.keys(t),l=Object.keys(e);return f.length===l.length&&f.every(function(r){return Object.prototype.hasOwnProperty.call(e,r)&&ot(t[r],e[r])})}if(t.constructor!==e.constructor)return!1;var p=Object.keys(t),y=Object.keys(e);return p.length===y.length&&p.every(function(r){return Object.prototype.hasOwnProperty.call(e,r)&&ot(t[r],e[r])})}function it(t){return it="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},it(t)}function ut(t){return function(t){if(Array.isArray(t))return at(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return at(t,e);var r={}.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?at(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function at(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=Array(e);r<e;r++)n[r]=t[r];return n}function st(t){return[].concat(ut(Object.keys(t)),ut(Object.getOwnPropertySymbols(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})))}function ct(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:new WeakMap;if(null==t)return t;if("object"!==it(t))return t;if(r.has(t))return r.get(t);var n=Array.isArray(t)?[]:{};if(r.set(t,n),Array.isArray(t)){for(var o=0;o<t.length;o+=1)n[o]=ct(t[o],e,r);return n}return st(t).forEach(function(o){if(e){var i=e(void 0,t[o],o,n,t);if(void 0!==i)return void(n[o]=i)}n[o]=ct(t[o],e,r)}),n}function ft(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:new WeakMap;return n.has(e)?n.get(e):(n.set(e,t),st(e).forEach(function(o){var i=e[o];if(void 0!==i)if(i!==e){if(r){var u=r(t[o],i,o,t,e);if(void 0!==u)return void(t[o]=u)}Array.isArray(i)?t[o]=ct(i,r,n):et(i)?et(t[o])?ft(t[o],i,r,n):t[o]=ct(i,r,n):t[o]=i}else t[o]=t}),t)}function lt(t){for(var e=arguments.length,r=new Array(e>1?e-1:0),n=1;n<e;n++)r[n-1]=arguments[n];var o="function"==typeof r[r.length-1]?r.pop():void 0;return r.length?null==t?ct(r[0],o):(r.forEach(function(e){null!=e&&ft(t,e,o)}),t):t}function pt(t){return pt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},pt(t)}function yt(t,e){Object.keys(t).forEach(function(r){e[r]=t[r]})}function bt(t,e,r){if(null==t)return t;if(null==e)return t;var n=t,o=Array.isArray(e)?e.slice():String(e);if("string"==typeof o&&(o=(o=o.replace(/\[(\w+)\]/g,".$1")).split(".")),1===o.length&&""===o[0])return n[""]=r,n;if(""===o[0]&&o.shift(),0===o.length)return n;if(1===o.length)return n[o[0]]=r,n;for(var i=n,u=o.length-1,a=0;a<u;a+=1){var s=o[a];if(""!==s){var c=o[a+1],f=!Number.isNaN(parseInt(c,10))&&Number.isFinite(Number(c))&&""!==c;if(void 0===i[s])i[s]=f?[]:{};else if(f&&!Array.isArray(i[s])){var l=i[s];i[s]=[],"object"===pt(l)&&null!==l?yt(l,i[s]):i[s][0]=l}else null!==i[s]&&"object"===pt(i[s])||(i[s]=f?[]:{});i=i[s]}else{if(a<u-1&&""===o[a+1])continue;void 0===i[""]&&(i[""]={}),i=i[""]}}return i[o[u]]=r,n}"function"!=typeof structuredClone&&(window.structuredClone=o);var vt=function(t,e,r){return function(n,o){return"function"==typeof e?e(n,o,r):function(e,r){return-1===t.findIndex(function(t){return!ot(Z(e,t),Z(r,t))})}(n,o)}};const ht=function(t,e,r,n,o){if(!(t instanceof W))throw new TypeError("Argument #1 must be an instance of Observable");var i,u,a,s,c=-1!==e.indexOf(" ")?e.split(" "):e;return Array.isArray(c)||(c=[c]),t.pipe((u=vt(structuredClone(c),null,{count:0}),void 0===a&&(a=R),u=null!=u?u:Q,q(function(t,e){var r,n=!0;t.subscribe(H(e,function(t){var o=a(t);!n&&u(r,o)||(n=!1,r=o,e.next(t))}))})),(s=structuredClone(c),i=function(t){return e=t,r={}
5494,s.forEach(function(t){var n=Z(e,t);bt(r,t,n)}),1===s.length?Z(r,s[0]):r;var e,r},q(function(t,e){var r=0;t.subscribe(H(e,function(t){e.next(i.call(undefined,t,r++))}))}))).subscribe(r,n,o)};function dt(t){return dt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},dt(t)}function mt(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,gt(n.key),n)}}function gt(t){var e=function(t){if("object"!=dt(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var r=e.call(t,"string");if("object"!=dt(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==dt(e)?e:e+""}var wt=new WeakMap;const St=function(){return t=function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Number.MAX_SAFE_INTEGER,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:6e4;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t);var o={};o.data=u(e),o.properties=new G(o.data),o.events=new X(r,n),wt.set(this,o)},e=[{key:"get",value:function(t,e){return Z(wt.get(this).data,t,e)}},{key:"set",value:function(t,e){var r=wt.get(this),n=u(r.data);return bt(n,t,e),r.data=n,r.properties.next(n),this}},{key:"merge",value:function(t,e){if(!et(e))throw new TypeError("Values must be a plain object. Use set or provide the full context for the property.");
5494if("string"!=typeof t)throw new TypeError("Key must be a string.");var r=wt.get(this),n=u(r.data);return bt(n,t,lt({},Z(n,t),e)),r.data=n,r.properties.next(n),wt.set(this,r),this}},{key:"import",value:function(t){var e=wt.get(this),r=lt({},e.data,t);return e.data=r,e.properties.next(r),wt.set(this,e),this}},{key:"export",value:function(){return wt.get(this).data}},{key:"subscribe",value:function(t,e,r,n){var o,i=wt.get(this),u=!1,a=function(){if(!u){this.unsubscribe=function(){u||(u=!0,o&&"function"==typeof o.unsubscribe&&o.unsubscribe())};for(var t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];return e.apply(this,r)}},s=(o=Array.isArray(t)&&-1!==t.findIndex(function(t){return-1!==t.indexOf("event")})||-1!==t.indexOf("event")?function(t,e,r,n,o){if(!(t instanceof W))throw new TypeError("Argument #1 must be an instance of Observable");var i=-1!==e.indexOf(" ")?e.split(" "):e;Array.isArray(i)||(i=[i]);var u,a=i.filter(function(t){return-1!==t.indexOf("event")});if(-1!==a.indexOf("event"))return t.subscribe(r,n,o);if(a.length!==i.length)throw new RangeError("All key must be welformed, one or more malformed keys was provided.");return a=a.map(function(t){return t.split(":").pop()}),t.pipe((u=function(t){return-1!==a.indexOf(t.key)},q(function(t,e){var r=0;t.subscribe(H(e,function(t){return u.call(void 0,t,r++)&&e.next(t)}))}))).subscribe(r,n,o)}(i.events,t,a,r,n):ht(i.properties,t,a,r,n)).unsubscribe;return o.unsubscribe=function(){return u=!0,s.call(this)},o}},{key:"trigger",value:function(t,e,r){var n={key:t,data:e,event:r};return wt.get(this).events.next(n),this}}],e&&mt(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,e}();return e.default})());
5495//# sourceMappingURL=anf-databridge.umd.js.map;
5496redesign.define('coreServices/adapter/bags/items',[
5497  'api/Classes/Adapter',
5498  'api/Classes/AdapterError',
5499  'anfUtil/testFramework',
5500  'anfDataBridge'
5501], function items(APIAdapter, AdapterError, test, DataBridge)  {
5502  'use strict';
5503
5504  var adapter = new APIAdapter();
5505
5506  var errorMessages = {
5507    SHORT_SKU_REQUIRED: 'no shortSku was provided',
5508    ORDER_ITEM_ID_REQUIRED: 'no orderItemId was provided'
5509  };
5510
5511  function pushBingUetqToWindow(aProductItemArr) {
5512    window.digitalData = window.digitalData || new DataBridge();
5513    window.uetq = window.uetq || [];
5514    var pageType = window.digitalData.get('page.pageKind');
5515
5516    // TODO: clean up when tealium is incorporated on Picked For You page
5517    if (pageType === 'pickedForYou') {
5518      pageType = 'other';
5519    }
5520
5521    window.uetq.push({
5522      'prodid': aProductItemArr[aProductItemArr.length - 1].shortSku,
5523      'pagetype': pageType === 'shopping cart' ? 'cart' : pageType
5524    });
5525  }
5526
5527  /**
5528  * @property {object} CONSTANTS
5529  */
5530  adapter.CONSTANTS = {
5531  };
5532
5533  /**
5534   * @name create
5535   * @description Function to sit in front of the api call so we can add some logic if we are going to make the call or not
5536   * @param {object} [settings] - the settings to be supplied to the function
5537   * @param {string} [settings.shortSku] - REQUIRED, the sku of the item to add to bag
5538   * @param {integer} [settings.quantity] - the quantity of provided sku user wants to add to bag, defaults to 1
5539   * @param {boolean} [settings.checkInventory] - should the API check if there is inventory for this sku, defaults to false
5540   * @return {promise} this is a jquery promise that will be resolved/rejected with an object c
5540ontaining reason code and a combination of ajaxData, ajaxJqXHR, ajaxTextStatus, and ajaxErrorThrown depending on the result of the ajax call
5541   */
5542  adapter.configCreate({
5543    endPoint: ANF.params.storeAttributes.apiURLRootBags + '/cart/items',
5544    method: 'POST',
5545    validation: function validation(data, context) {
5546      var hasSku = test.object.containsKey(data, 'shortSku', false);
5547
5548      if (!hasSku || test.string.empty(data.shortSku, true)) {
5549        throw new AdapterError(context.REASON.INVALID_PARAMS, errorMessages.SHORT_SKU_REQUIRED);
5550      }
5551    },
5552    preAjax: function preAjax(data) {
5553      return JSON.stringify(data);
5554    },
5555    done: function done(data, textStatus, jqXHR) {
5556      /**
5557       * @this CRUD
5558       */
5559      var response;
5560      if (data.messages && data.messages.length > 0) {
5561        response = {
5562          data: {
5563            error: [
5564              {
5565                errorMessage: data.messages[0].message
5566              }
5567            ]
5568          }
5569        };
5570
5571        this.deferred.reject(response);
5572      } else {
5573        pushBingUetqToWindow(data.items);
5574        response = this.getAjaxOkResponse(data, textStatus, jqXHR);
5575        this.deferred.resolve(response);
5576      }
5577    }
5578  });
5579
5580  /**
5581   * @name update
5582   * @description Function to sit in front of the api call so we can add some logic if we are going to make the call or not
5583   * @param {object} [settings] - the settings to be supplied to the function
5584   * @param {string} [settings.shortSku] - REQUIRED, the sku of the item to add to bag
5585   * @param {string} [settings.orderItemId] - REQUIRED, the orderItemId that the user wants to update, will be used in the endpoint
5586   * @param {boolean} [settings.checkInventory] - should the API check if there is inventory for this sku
5587   * @return {promise} this is a jquery promise that will be resolved/rejected with an object c
5587ontaining reason code and a combination of ajaxData, ajaxJqXHR, ajaxTextStatus, and ajaxErrorThrown depending on the result of the ajax call
5588   */
5589  adapter.configUpdate({
5590    endPoint: ANF.params.storeAttributes.apiURLRootBags + '/cart/items/<orderItemId>',
5591    method: 'PUT',
5592    validation: function validation(data, context) {
5593      var hasSku = test.object.containsKey(data, 'shortSku', false);
5594      var hasOrderItemId = test.object.containsKey(data, 'orderItemId', false);
5595
5596      if (!hasSku || test.string.empty(data.shortSku, true)) {
5597        throw new AdapterError(context.REASON.INVALID_PARAMS, errorMessages.SHORT_SKU_REQUIRED);
5598      }
5599      if (!hasOrderItemId || test.string.empty(data.orderItemId, true)) {
5600        throw new AdapterError(context.REASON.INVALID_PARAMS, errorMessages.ORDER_ITEM_ID_REQUIRED);
5601      }
5602    },
5603    preAjax: function preAjax(data) {
5604      return JSON.stringify(data);
5605    },
5606    done: function done(data, textStatus, jqXHR) {
5607      /**
5608       * @this CRUD
5609       */
5610      var response;
5611      if (data.messages && data.messages.length > 0) {
5612        response = {
5613          data: {
5614            error: [
5615              {
5616                errorMessage: data.messages[0].message
5617              }
5618            ]
5619          }
5620        };
5621
5622        this.deferred.reject(response);
5623      } else {
5624        pushBingUetqToWindow(data.items);
5625        response = this.getAjaxOkResponse(data, textStatus, jqXHR);
5626        this.deferred.resolve(response);
5627      }
5628    }
5629  });
5630
5631  Object.freeze(adapter.CONSTANTS);
5632
5633  return adapter;
5634});
5635
5636redesign.define('globalModulesHelpers/freeShippingProgress',[], function freeShippingProgress() {
5637  'use strict';
5638
5639  var publicMembers = {
5640    'freeShippingMessageEnabled': ANF.params.storeAttributes.enableFreeShippingMessaging,
5641    'getFreeShippingMessageRange': function getFreeShippingMessageRange() {
5642      return ANF.params.storeAttributes.freeShippingMsgRange;
5643    },
5644    'getFreeShippingPreLabel': function getFreeShippingPreLabel(cartModel) {
5645      return cartModel.amountToFreeShipping > 0 ? this.getShippingThresholdFmtValue(cartModel.freeShippingThreshold.minShippingThresholdFmt) : '';
5646    },
5647    'getFreeShippingPostLabel': function getFreeShippingPostLabel(cartModel) {
5648      return cartModel.amountToFreeShipping > 0 ? this.getShippingThresholdFmtValue(cartModel.freeShippingThreshold.freeShippingThresholdFmt) : '';
5649    },
5650    'getShippingThresholdFmtValue': function getShippingThresholdFmt(value) {
5651      return (value !== null) ? value.slice(0, -3) : value;
5652    },
5653    'getFreeShippingProgressValue': function getFreeShippingProgressValue(amountToFreeShipping, freeShippingProgressMax) {
5654      return freeShippingProgressMax - amountToFreeShipping;
5655    },
5656    'shouldDisplayFreeShippingProgress': function shouldDisplayFreeShippingProgress(testGroup, amountToFreeShipping, freeShippingProgressMax) {
5657      var isValidAmountToFreeShipping = !isNaN(Number(amountToFreeShipping));
5658      if (freeShippingProgressMax !== null) {
5659        return this.freeShippingMessageEnabled && isValidAmountToFreeShipping && ((testGroup === 1 && amountToFreeShipping < publicMembers.getFreeShippingMessageRange()) || testGroup === 2);
5660      }
5661      return false;
5662    },
5663    'getDsModel': function getDsModel(cartModel, testGroup) {
5664      var freeShippingProgressMax = cartModel.freeShippingThreshold && cartModel.freeShippingThreshold.freeShippingThreshold;
5665      return {
5666        'isVisible': this.shouldDisplayFreeShippingProgress(testGroup, cartModel.amountToFreeShipping, freeShippingProgressMax),
5667        'amountToFreeShipping': cartModel.amountToFreeShipping,
5668        'amountToFreeShippingFmt': cartModel.amountToFreeShippingFmt,
5669        'preLabel': this.getFreeShippingPreLabel(cartModel),
5670        'postLabel': this.getFreeShippingPostLabel(cartModel),
5671        'value': this.getFreeShippingProgressValue(cartModel.amountToFreeShipping, freeShippingProgressMax),
5672        'max': freeShippingProgressMax
5673      };
5674    }
5675  };
5676
5677  return publicMembers;
5678});
5679
5680
5681redesign.define('checkoutServices/common/redirect',[
5682  'coreServices/window'
5683], function redirect(windowService) {
5684  'use strict';
5685
5686  var privateMembers = {
5687    'urlParams': {
5688      'storeId': ANF.params.storeAttributes.idList.storeId,
5689      'catalogId': ANF.params.storeAttributes.idList.catalogId,
5690      'langId': ANF.params.storeAttributes.idList.langId
5691    }
5692  };
5693
5694  return {
5695    'buildRedirectURL': function buildRedirectURL(command, additionalParams) {
5696      var parameters = null;
5697      var queryString = null;
5698      var redirectUrl = null;
5699      var baseParameters = privateMembers.urlParams;
5700      var hasCommand = (typeof command === 'string' && command.length > 0) ? true : false;
5701      var hasAdditionalParameters = (typeof additionalParams === 'object' && additionalParams !== null) ? true : false;
5702
5703      if (hasCommand) {
5704        if (hasAdditionalParameters) {
5705          parameters = $.extend({}, baseParameters, additionalParams);
5706        } else {
5707          parameters = baseParameters;
5708        }
5709
5710        queryString = $.param(parameters);
5711        redirectUrl = command + '?' + queryString;
5712      } else {
5713        redirectUrl = '';
5714      }
5715
5716      return redirectUrl;
5717    },
5718    'setRedirectLocation': windowService.location.set
5719  };
5720});
5721
5722redesign.define('coreModules/checkout/utils',['checkoutServices/common/redirect'], function utils(redirectService) {
5723  'use strict';
5724
5725  var publicMembers = {
5726    'getCheckoutURL': function getCheckoutURL() {
5727      var additionalParams = {
5728        'doInventory': 'N',
5729        'InvRepuCheckMode': 'checkout',
5730        'URL': 'OrderCheckoutDisplayView',
5731        'removeSoldOutIems': 'true',
5732        'errpage': 'OrderItemDisplayView',
5733        'checkoutMode': 'webCheckout'
5734      };
5735      return redirectService.buildRedirectURL('Checkout', additionalParams);
5736    },
5737
5738    'buildCheckoutButton': function buildCheckoutButton() {
5739      var hasMiniBagCheckoutButton = ANF.params.storeAttributes.hasMiniBagCheckoutButton;
5740      var hasESWFeatureEnabled = ANF.params.storeAttributes.shoppingBagV2.hasESWFeatureEnabled;
5741      var showCheckoutButton = hasMiniBagCheckoutButton && !hasESWFeatureEnabled;
5742      var showCheckoutButtonClass = (showCheckoutButton) ? 'show' : '';
5743      return {
5744        'props': {
5745          'showCheckoutButton': showCheckoutButton,
5746          'showCheckoutButtonClass': showCheckoutButtonClass,
5747          'href': ANF.params.urls.checkout.checkoutUrl
5748        }
5749      };
5750    }
5751  };
5752
5753  return publicMembers;
5754});
5755
5756redesign.define('anfcore/components/progressBar', ['exports', '../helpers/makeSelector'], function (exports, _makeSelector) {
5757  'use strict';
5758
5759  Object.defineProperty(exports, "__esModule", {
5760    value: true
5761  });
5762
5763  var _makeSelector2 = _interopRequireDefault(_makeSelector);
5764
5765  function _interopRequireDefault(obj) {
5766    return obj && obj.__esModule ? obj : {
5767      default: obj
5768    };
5769  }
5770
5771  function _toConsumableArray(arr) {
5772    if (Array.isArray(arr)) {
5773      for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
5774        arr2[i] = arr[i];
5775      }
5776
5777      return arr2;
5778    } else {
5779      return Array.from(arr);
5780    }
5781  }
5782
5783  // This is a wrapper around querySelectorAll
5784  var components = (0, _makeSelector2['default'])('.js-progress-bar');
5785
5786  exports['default'] = function () {
5787    return {
5788      components: components,
5789      init: function () {
5790        function init() {
5791          [].concat(_toConsumableArray(components())).forEach(function (element) {
5792            var progressElement = element.querySelector('.js-progress-element');
5793
5794            if (!progressElement) return;
5795
5796            var value = progressElement.dataset.value;
5797            var max = progressElement.max;
5798
5799            var animationInterval = setInterval(function () {
5800              if (progressElement.value < value) {
5801                progressElement.setAttribute('value', Math.ceil(progressElement.value + max / 100));
5802              } else {
5803                clearInterval(animationInterval);
5804              }
5805            }, 1);
5806          });
5807          return this;
5808        }
5809
5810        return init;
5811      }()
5812    };
5813  };
5814});
5815redesign.define('productModules/helpers/productAddToBagHelper',[
5816  'coreServices/adapter/bags/items',
5817  'globalServices/startGuestSession',
5818  'anfcore/components/statefulButton',
5819  'coreServices/dataBridge/cart',
5820  'productServices/product/template',
5821  'productModules/helpers/Utils',
5822  'productServices/product/headerHeightCalculator',
5823  'globalModulesHelpers/freeShippingProgress',
5824  'coreModules/checkout/utils',
5825  'util/analytics/enum/dataPoint',
5826  'util/analytics/enum/subscriptionName',
5827  'anfcore/components/progressBar'
5828], function productAddToBagHelper(
5829  bagsItemsApi,
5830  guestSession,
5831  statefulButtonComponent,
5832  cartDataBridgeService,
5833  templateService,
5834  Utils,
5835  headerHeightCalculator,
5836  freeShippingProgressHelper,
5837  checkoutUtils,
5838  analyticsDataPoints,
5839  analyticsSubscriptionNames,
5840  dsProgressBar
5841) {
5842  'use strict';
5843  var minATBProcessingTime = 1500;
5844  var atbButtonSelector = '.pdp-atb-button';
5845  var errorContainerSelector = '.validator-container';
5846  var sizePrimaryNameSelector = '.product-sizes__name__label_primary';
5847  var sizeSecondaryNameSelector = '.product-sizes__name__label_secondary';
5848  var messageBus = $(ANF);
5849  var hideMiniBagTimeout = ANF.params.storeAttributes.hideMiniBagTimeoutCounter;
5850  var testGroup = ANF.params.storeAttributes.checkout.freeShippingProgress;
5851  var sizePrimaryQv = 'size-primary_qv';
5852  var sizeSecondaryQv = 'size-secondary_qv';
5853  var sizePrimary = 'size-primary';
5854  var sizeSecondary = 'size-secondary';
5855
5856  // have to bind utils here bc utils.getvalue uses 'this'
5857  var getInANF = Utils.getValueFromObject.bind(Utils, ANF);
5858
5859
5860  function addToBagTimeout() {
5861    var minProcessTimePromise = new $.Deferred();
5862    setTimeout(function waitMinProcessingTime() {
5863      minProcessTimePromise.resolve();
5864    }, minATBProcessingTime);
5865    return minProcessTimePromise;
5866  }
5867
5868  function triggerAddToBagSuccessEvents(data) {
5869    var formData = data.formData;
5870    var cart = data.cart;
5871    var isEdit = data.isEdit;
5872
5873    // mySaves needs this trigger to update icons on items that may have been saved that were added
5874    messageBus.trigger('productAddToBag:productAddedToBag', formData.productId);
5875
5876    if (!isEdit) {
5877      var orEmptyObject = function orEmptyObjectFn(value) {
5878        return value || {};
5879      };
5880
5881      var orEmptyArray = function orEmptyArrayFn(value) {
5882        return value || [];
5883      };
5884
5885      var productDetail = orEmptyObject(
5886        orEmptyObject(
5887          productCatalog
5888        )[formData.productId]
5889      );
5890
5891      var kicAdded = formData.kic_qv || formData.kic_tray || formData.kic;
5892
5893      var matchedItem = orEmptyObject(
5894        orEmptyArray(orEmptyObject(cart).items)
5895          .filter(function filterNonMatching(item) {
5896            return (
5897              item.item
5898              && item.item.shortSku === formData.sku
5899            );
5900          }).pop()
5901      );
5902
5903      var eventData = {};
5904      eventData[analyticsDataPoints.PRODUCT_COLLECTION] = formData.collection;
5905      eventData[analyticsDataPoints.QUANTITY] = formData.quantity;
5906      eventData[analyticsDataPoints.KEY_ITEM_COLOR] = kicAdded;
5907      eventData[analyticsDataPoints.PRICE_LIST_LOCAL] = matchedItem.item.listPrice;
5908      eventData[analyticsDataPoints.PRICE_LIST_USD] = matchedItem.item.listPriceUSD;
5909      eventData[analyticsDataPoints.PRICE_OFFER_LOCAL] = matchedItem.item.offerPrice;
5910      eventData[analyticsDataPoints.PRICE_OFFER_USD] = matchedItem.item.offerPriceUSD;
5911      eventData[analyticsDataPoints.PRODUCT_ID] = matchedItem.productId;
5912      eventData[analyticsDataPoints.SHORT_SKU] = matchedItem.item.shortSku;
5913      eventData[analyticsDataPoints.PRICE_FLAG] = productDetail.priceFlag;
5914      eventData[analyticsDataPoints.LONG_SKU] = matchedItem.item.longSku;
5915      eventData[analyticsDataPoints.PRODUCT_NAME] = matchedItem.productName;
5916
5917      window.digitalData.trigger(analyticsSubscriptionNames.ACTION.ADD_TO_BAG, eventData);
5918    }
5919
5920    try {
5921      cartDataBridgeService.add({
5922        kic: Utils.getProductData(formData.productId).kicId,
5923        shortSku: formData.sku,
5924        quantity: formData.quantity
5925      });
5926    } catch (err) {
5927      // EPIC-8729: looking at old ATB code, we apparently dont need to handle anything here on error
5928      // err.message
5929    }
5930  }
5931
5932  function hideError($form) {
5933    $form.find(errorContainerSelector).fadeOut(100, 'linear');
5934  }
5935
5936  function centerError($errorContainer) {
5937    var viewPortMiddle = $(window).height() / 2;
5938    var errorContainerTop = $errorContainer.offset().top;
5939
5940    $('html,body').animate({
5941      scrollTop: errorContainerTop - viewPortMiddle
5942    });
5943  }
5944
5945  function unselectedSizeErrorMsg(formData, $form) {
5946    var message = publicMembers.constants.selectSizeError;
5947
5948    var primarySizeUnselected = !formData[sizePrimary] && !formData[sizePrimaryQv];
5949    var secondarySizeUnselected = !formData[sizeSecondary] && !formData[sizeSecondaryQv];
5950
5951    var replaceParamWithText = function replaceParamWithText(text) {
5952      return publicMembers.constants.selectError.replace('{0}', text);
5953    };
5954    if (primarySizeUnselected && !secondarySizeUnselected) {
5955      message = replaceParamWithText($form.find(sizePrimaryNameSelector).text().split(':')[0]);
5956    } else if (!primarySizeUnselected && secondarySizeUnselected) {
5957      message = replaceParamWithText($form.find(sizeSecondaryNameSelector).text().split(':')[0]);
5958    }
5959    return message;
5960  }
5961
5962  var publicMembers = {
5963    constants: {
5964      atbError: getInANF('messaging.catalogV2.PDP_ATB_ERROR', ''),
5965      guestSessionError: getInANF('messaging.catalogV2.GLB_GUEST_SESSION_ERROR', ''),
5966      selectSizeError: getInANF('messaging.catalogV2.selectSizeError', ''),
5967      selectError: getInANF('messaging.catalogV2.SELECT_KEY_SIZE', '')
5968    },
5969
5970    handleMFEAddToBagSuccess: function handleMFEAddToBagSuccess(event) {
5971      var data = event.detail;
5972      var eventData = {};
5973      eventData[analyticsDataPoints.BRAND_VIEWING] = data.brandViewing;
5974      eventData[analyticsDataPoints.CART_UNITS_ADDED] = data.cartUnitsAdded;
5975      eventData[analyticsDataPoints.ORDER_SUBTOTAL] = data.orderSubtotal;
5976      eventData[analyticsDataPoints.ORDER_SUBTOTAL_USD] = data.orderSubtotal;
5977      eventData[analyticsDataPoints.COLLECTION_ID] = data.orderSubtotal;
5978      eventData[analyticsDataPoints.KEY_ITEM_COLOR] = data.orderSubtotal;
5979      eventData[analyticsDataPoints.LIST_PRICE] = data.orderSubtotal;
5980      eventData[analyticsDataPoints.LIST_PRICE_USD] = data.orderSubtotal;
5981      eventData[analyticsDataPoints.PAGE_TYPE] = data.orderSubtotal;
5982      eventData[analyticsDataPoints.PRICE_FLAG] = data.orderSubtotal;
5983      eventData[analyticsDataPoints.PRODUCT_LONG_SKU] = data.orderSubtotal;
5984      eventData[analyticsDataPoints.MERCHANDISING_CATEGORY_ID] = data.orderSubtotal;
5985      window.digitalData.trigger(analyticsSubscriptionNames.ACTION.ADD_TO_BAG, eventData);
5986    },
5987
5988    addProductToBag: function addProductToBag($form, options) {
5989      var myOptions = options || {};
5990
5991      hideError($form);
5992      var response = new $.Deferred();
5993      var formData = publicMembers.getSerializedFormData($form);
5994      var requestData = publicMembers.buildRequestData(formData, myOptions.orderItemId);
5995      var isEdit = !!myOptions.orderItemId;
5996
5997
5998      if (requestData.shortSku) {
5999        var $buttons = $form.find(atbButtonSelector);
6000        publicMembers.setATBButtonState($buttons, 'processing');
6001        guestSession.deferredInit().done(function guestSessionSuccess() {
6002          var minProcessTimePromise = addToBagTimeout();
6003
6004          var cartItemsCall;
6005          if (!myOptions.orderItemId) {
6006            cartItemsCall = bagsItemsApi.create(requestData);
6007          } else {
6008            cartItemsCall = bagsItemsApi.update(requestData);
6009          }
6010
6011          $.when(cartItemsCall, minProcessTimePromise)
6012            .done(function addToBagSuccess(responseData) {
6013              response.resolve(responseData);
6014              triggerAddToBagSuccessEvents({
6015                $form: $form,
6016                cart: responseData.data,
6017                formData: formData,
6018                isEdit: isEdit,
6019                src: myOptions.src
6020              });
6021            })
6022            .fail(function addToBagFail(error) {
6023              var errorMessage = publicMembers.constants.atbError;
6024              var hasAPIErrorMessage = error && error.data && error.data.error && error.data.error.length;
6025
6026              if (hasAPIErrorMessage) {
6027                errorMessage = error.data.error[0].errorMessage;
6028              }
6029
6030              response.reject(errorMessage);
6031            });
6032        }).fail(function guestSessionFail() {
6033          response.reject(publicMembers.constants.guestSessionError);
6034        });
6035      } else {
6036        response.reject(unselectedSizeErrorMsg(formData, $form));
6037      }
6038
6039      return response.promise();
6040    },
6041
6042    getSerializedFormData: function getSerializedFormData($form) {
6043      var formData = $form.serializeArray();
6044      formData = formData.reduce(function reduceFormDataArray(acc, item) {
6045        acc[item.name] = item.value;
6046        return acc;
6047      }, {});
6048
6049      return formData;
6050    },
6051
6052    buildRequestData: function buildRequestData(formData, orderItemId) {
6053      var data = {
6054        shortSku: formData.sku,
6055        checkInventory: false
6056      };
6057
6058      if (orderItemId) {
6059        data.orderItemId = orderItemId;
6060      } else {
6061        data.quantity = parseInt(formData.quantity, 10);
6062      }
6063
6064      return data;
6065    },
6066
6067    hasQualifiedSku: function hasQualifiedSku($form) {
6068      return publicMembers.getSerializedFormData($form).sku;
6069    },
6070
6071    setATBButtonState: function setATBButtonState($buttons, state) {
6072      $buttons.each(function setEachButtonState(index, button) {
6073        publicMembers.statefulButton.changeState({
6074          button: button,
6075          state: state
6076        });
6077      });
6078    },
6079
6080    addToBagFail: function addToBagFail($form, errorMessage) {
6081      var $buttons = $form.find(atbButtonSelector);
6082      var errorHTML = templateService.renderTemplate('errorMessage', {
6083        'error-message-text': errorMessage
6084      });
6085      var $errorContainer = $form.find(errorContainerSelector);
6086      $errorContainer
6087        .html(errorHTML)
6088        .fadeIn(100, 'linear');
6089
6090      if (ANF.breakpoints.screen === 'small_phone' || ANF.breakpoints.screen === 'phone') {
6091        centerError($errorContainer);
6092      }
6093
6094      publicMembers.setATBButtonState($buttons, 'initial');
6095
6096      $(window).trigger('analytics.errorTracking', {
6097        type: 'add to bag',
6098        message: errorMessage
6099      });
6100    },
6101
6102    displayNotification: function displayNotification(cartModel) {
6103      var pasId = ANF.params.storeAttributes.pasId;
6104      var $atbNotification = $(templateService.renderTemplate('addToBagNotification', {
6105        cartUrl: ANF.params.urls.checkout.cartURL,
6106        freeShippingMessage: freeShippingProgressHelper.getDsModel(cartModel, testGroup),
6107        checkoutButton: checkoutUtils.buildCheckoutButton()
6108      }));
6109      var positionY = headerHeightCalculator.getCurrentHeaderHeight(pasId);
6110
6111      $('body').prepend($atbNotification);
6112      $(window).one('dragup scroll', function hideNotification() {
6113        $atbNotification.remove();
6114      });
6115      $atbNotification
6116        .addClass('visible')
6117        .css('transform', 'translateY(' + positionY + 'px)');
6118      dsProgressBar.default().init();
6119      setTimeout(function successTimeout() {
6120        $atbNotification.remove();
6121      }, hideMiniBagTimeout);
6122    },
6123
6124    statefulButton: statefulButtonComponent.default()
6125  };
6126  return publicMembers;
6127});
6128
6129redesign.define('productModules/product/addToBag/pdpAddToBag',[
6130  'productModules/helpers/productAddToBagHelper',
6131  'util/analytics/enum/pageType'
6132], function pdpAddToBag(
6133  addToBagHelper,
6134  analyticsPageType
6135) {
6136  'use strict';
6137
6138  var messageBus = $(ANF);
6139  var successStateTime = 3000;
6140  var pdpAddToBagButtonSelector = '.js-product-page .product-page__atb-saves-wrapper .pdp-atb-button';
6141  var addToBagFormSelector = '.product-page-add-to-bag__container';
6142  var atbButtonSelector = '.pdp-atb-button';
6143  var selectedSwatchSelector = '.product-swatches :checked';
6144
6145  function bindEvents() {
6146    $(document).on('click', pdpAddToBagButtonSelector, addToBagHandler);
6147  }
6148
6149  function listen() {
6150    messageBus.on('initiateAddToBag:sticky', stickyAddToBagHandler);
6151  }
6152
6153  function addToBagHandler(e) {
6154    e.preventDefault();
6155    addToBag($(e.target).closest(addToBagFormSelector), 'analytics.addToBagInline');
6156  }
6157
6158  function stickyAddToBagHandler(e, data) {
6159    addToBag(data.$form, 'analytics.addToBagSticky');
6160  }
6161
6162  function addToBag($form, analyticsATBType) {
6163    addToBagHelper.addProductToBag($form, { src: analyticsPageType.PDP })
6164      .done(function success(data) {
6165        addToBagSuccess(data, $form, analyticsATBType);
6166      })
6167      .fail(function fail(errorMessage) {
6168        addToBagHelper.addToBagFail($form, errorMessage);
6169      });
6170  }
6171
6172  function addToBagSuccess(data, $form, analyticsATBType) {
6173    var kicId = $form.find(selectedSwatchSelector).val();
6174    setButtonSuccess($form);
6175    if (ANF.breakpoints.screen === 'small_phone' ||
6176    ANF.breakpoints.screen === 'phone' ||
6177    ANF.breakpoints.screen === 'tablet' ||
6178    ANF.breakpoints.screen === 'small_desktop' ||
6179    ANF.breakpoints.screen === 'desktop') {
6180      addToBagHelper.displayNotification(data.data);
6181    }
6182    // this shows the minibag with item added
6183    messageBus.trigger('miniBag:productAddedToCart', data);
6184
6185    $(ANF).trigger('styliticsV3Item:addToBag', {kicId: kicId});
6186    $(window).trigger('analytics.addToBagStandard'); // deprecated
6187    $(window).trigger(analyticsATBType);
6188  }
6189
6190  function setButtonSuccess($form) {
6191    var $buttons = $form.find(atbButtonSelector);
6192    addToBagHelper.setATBButtonState($buttons, 'success');
6193    setTimeout(function successTimeout() {
6194      addToBagHelper.setATBButtonState($buttons, 'initial');
6195    }, successStateTime);
6196  }
6197
6198  var publicMembers = {
6199    listen: listen,
6200    bindEvents: bindEvents
6201  };
6202  return publicMembers;
6203});
6204
6205redesign.define('productModules/helpers/curry',[], function Curry() {
6206  'use strict';
6207
6208  return function curry(fn, arity) {
6209    var ar = arity || fn.length;
6210
6211    return (function nextCurried(prevArgs) {
6212      return function curried(nextArg) {
6213        var args = prevArgs.concat(nextArg);
6214
6215        if (args.length >= ar) {
6216          return fn.apply(null, args);
6217        }
6218
6219        return nextCurried(args);
6220      };
6221    })( [] );
6222  };
6223});
6224
6225redesign.define('productModules/product/addToBag/quickviewAddToBag',[
6226  'productModules/helpers/Utils',
6227  'productModules/helpers/productAddToBagHelper',
6228  'productModules/helpers/curry',
6229  'anfcore/components/statefulButton',
6230  'anfcore/components/modal',
6231  'coreServices/window'
6232], function QuickviewAddToBag(
6233  Utils,
6234  addToBagHelper,
6235  curry,
6236  statefulButtonComponent,
6237  modalComponent,
6238  windowService
6239) {
6240  'use strict';
6241
6242  var addToBagButtonSelector = '.pdp-atb-button';
6243  var qvAddToBagButtonSelector = '.js-quickview .pdp-atb-button';
6244  var addToBagFormSelector = '.product-page-add-to-bag__container';
6245  var editModalSelector = '.product-quickview__modal.edit-product';
6246  var checkoutCartSelector = '#checkout-cart';
6247  var quickviewModalId = 'product-quickview__modal';
6248  var quickviewProductInfoContainerSelectorClass = '.product-quickview__modal[data-open="true"] .product-page__info-container';
6249  var quickviewErrorClass = 'qv-error';
6250  var selectedSwatchSelector = '.product-swatches :checked';
6251  var styliticsModalClass = '.stylitics-quickview';
6252
6253  var successStateTime = 1000;
6254
6255  function addToBag(e) {
6256    e.preventDefault();
6257    var $form = $(e.currentTarget).closest(addToBagFormSelector);
6258    var isStylitics = $form.closest(styliticsModalClass).length;
6259    var orderItemId = $form.closest(editModalSelector).attr('data-orderitemid');
6260    var isEditItem = Boolean(orderItemId);
6261    var atbSuccess = curriedSuccess($form)(isEditItem)(isStylitics);
6262    var atbFail = curriedFail($form);
6263    addToBagHelper.addProductToBag($form, {orderItemId: orderItemId})
6264      .done(atbSuccess)
6265      .fail(atbFail);
6266  }
6267
6268  var curriedSuccess = curry(addToBagSuccess);
6269  function addToBagSuccess($form, isEdit, isStylitics, data) {
6270    var button = $form.find(addToBagButtonSelector)[0];
6271    var isShoppingCart = $('body').is(checkoutCartSelector);
6272    var kicId = $form.find(selectedSwatchSelector).val();
6273
6274    publicMembers.statefulButton.changeState({
6275      button: button,
6276      state: isEdit ? 'updateSuccess' : 'success'
6277    });
6278
6279    setTimeout(function successTimeout() {
6280      publicMembers.modal.closeModal(quickviewModalId);
6281      if (isShoppingCart) {
6282        windowService.location.reload();
6283      }
6284      if (!isShoppingCart) {
6285        // this shows the minibag with item added
6286        var customEvent = new Event('miniBag:productAddedToCart');
6287        customEvent.detail = {
6288          data: data
6289        };
6290        window.dispatchEvent(customEvent);
6291
6292        if (ANF.breakpoints.screen === 'small_phone' || ANF.breakpoints.screen === 'phone' || ANF.breakpoints.screen === 'tablet' || ANF.breakpoints.screen === 'small_desktop' || ANF.breakpoints.screen === 'desktop') {
6293          addToBagHelper.displayNotification(data.data);
6294        }
6295      }
6296    }, successStateTime);
6297
6298    window.dispatchEvent(new CustomEvent('addToBag:perso-instrumentation', {
6299      detail: {
6300        kicId: kicId
6301      }
6302    }));
6303
6304    if (isStylitics) {
6305      if (Utils.hasPDPMFEBelowTheFold()) {
6306        var QvFromStyliticsV3ATBEvent = new CustomEvent('styliticsV3Item:addToBagForMFE', {
6307          detail: {
6308            kicId: kicId
6309          }
6310        });
6311        window.dispatchEvent(QvFromStyliticsV3ATBEvent);
6312      } else {
6313        $(ANF).trigger('styliticsV3Item:addToBag', {kicId: kicId});
6314      }
6315    }
6316    $(window).trigger('analytics.addToBagStandard').trigger('analytics.addToBagInline');
6317  }
6318
6319  var curriedFail = curry(addToBagFail);
6320  function addToBagFail($form, errorMessage) {
6321    $(quickviewProductInfoContainerSelectorClass).addClass(quickviewErrorClass);
6322    addToBagHelper.addToBagFail($form, errorMessage);
6323  }
6324
6325  var publicMembers = {
6326    bindEvents: function bindEvents() {
6327      $(document).on('click', qvAddToBagButtonSelector, addToBag);
6328    },
6329    statefulButton: statefulButtonComponent.default(),
6330    modal: modalComponent.default()
6331  };
6332
6333  return publicMembers;
6334});
6335
6336redesign.define('productModules/helpers/hyperlinkShortDescriptorsSplitTest',[],
6337  function hyperlinkShortDescriptorsSplitTest() {
6338    'use strict';
6339
6340    var list1 = {
6341      anf: {
6342        'Men\'s': {
6343          list: {
6344            'best dressed guest collection': '/shop/us/mens-best-dressed-guest-weddings-and-events',
6345            'a&f x trevor project': '/shop/us/pride',
6346            'gender inclusive': '/shop/us/lookbook-a-and-f-lookbook',
6347            'trend edit': '/shop/us/search?filtered=true&rows=90&searchTerm=Trend+Edit&start=0&departmentId=12202-ANF',
6348            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=Online+Exclusive&start=0&departmentId=12202-ANF',
6349            'matching set': '/shop/us/mens-coordinated-sets',
6350            'getaway shop': '#',
6351            'vol. 28': '#',
6352            'golf shop': '#',
6353            'for justice collection': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=For+Justice+Collection'
6354          }
6355        },
6356        'Women\'s': {
6357          list: {
6358            'best dressed guest collection': '/shop/us/womens-best-dressed-guest-weddings-and-events',
6359            'a&f x trevor project': '/shop/us/pride',
6360            'gender inclusive': '/shop/us/lookbook-a-and-f-lookbook',
6361            'trend edit': '/shop/us/search?filtered=true&rows=90&searchTerm=Trend+Edit&start=0&departmentId=12203-ANF',
6362            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=Online+Exclusive&start=0&departmentId=12203-ANF',
6363            'matching set': '/shop/us/womens-matching-sets-dresses-and-rompers',
6364            'getaway shop': '#',
6365            'vol. 28': '#',
6366            'premium footwear collection': '/shop/us/search?departmentCategoryId=12203-ANF&searchTerm=premium+footwear+collection',
6367            'abercrombie x tia booth': '#',
6368            'for justice collection': '/shop/us/search?filtered=true&rows=90&searchTerm=For+Justice+Collection&start=0&departmentId=12203-ANF'
6369          }
6370        }
6371      },
6372      kids: {
6373        boys: {
6374          list: {
6375            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=179205-KIDS',
6376            'matching set': '/shop/us/kids/boys-matching-sets',
6377            'the cool stuff': '/shop/us/search?filtered=true&rows=90&searchTerm=THE+COOL+STUFF&start=0&departmentId=179205-KIDS',
6378            'vol. 28': '#',
6379            'everybody collection': '/shop/us/kids/kids-everybody-collection'
6380          }
6381        },
6382        girls: {
6383          list: {
6384            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=179206-KIDS',
6385            'matching set': '/shop/us/kids/girls-matching-sets',
6386            'the cool stuff': '/shop/us/search?filtered=true&rows=90&searchTerm=THE+COOL+STUFF&start=0&departmentId=179206-KIDS',
6387            'vol. 28': '#',
6388            'everybody collection': '/shop/us/kids/kids-everybody-collection'
6389          }
6390        }
6391      },
6392      hol: {
6393        'Men\'s': {
6394          list: {
6395            'pride collection': '/shop/us/pride-collection',
6396            'gender inclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=gender+inclusive&start=0&departmentId=12551-HOL',
6397            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=12551-HOL',
6398            'must-have collection': '/shop/us/mens-must-have-collection',
6399            'all day gameplay': '/shop/us/mens-all-day-gameplay',
6400            'part of a matching set': '/shop/us/search?departmentCategoryId=12551-HOL&searchTerm=part+of+a+matching+set'
6401          }
6402        },
6403        'Women\'s': {
6404          list: {
6405            'pride collection': '/shop/us/pride-collection',
6406            'gender inclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=gender+inclusive&start=0&departmentId=12552-HOL',
6407            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=12552-HOL',
6408            'all day gameplay': '/shop/us/mens-all-day-gameplay',
6409            'part of a matching set': '/shop/us/womens-matching-sets'
6410          }
6411        }
6412      },
6413      gh: {
6414        'Men\'s': {
6415          list: {
6416            'pride collection': '/shop/us/gilly-hicks/pride-collection',
6417            'gender inclusive': '/shop/us/gilly-hicks/unisex',
6418            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=65014360-GH',
6419            'part of a matching set': '/shop/us/search?filtered=true&rows=90&searchTerm=part+of+a+matching+set&start=0&departmentId=65014360-GH'
6420          }
6421        },
6422        'Women\'s': {
6423          list: {
6424            'pride collection': '/shop/us/gilly-hicks/pride-collection',
6425            'gender inclusive': '/shop/us/gilly-hicks/unisex',
6426            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=65014366-GH',
6427            'part of a matching set': '/shop/us/search?filtered=true&rows=90&searchTerm=part+of+a+matching+set&start=0&departmentId=65014366-GH'
6428          }
6429        }
6430      },
6431      st: {
6432        'men\'s': {
6433          list: {
6434            'gender inclusive': '/shop/us/social-tourist/shop-all-unisex',
6435            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=65014738-ST'
6436          }
6437        },
6438        'women\'s': {
6439          list: {
6440            'gender inclusive': '/shop/us/social-tourist/shop-all-unisex',
6441            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=65014738-ST'
6442          }
6443        }
6444      }
6445    };
6446
6447    var list2 = {
6448      anf: {
6449        'Men\'s': {
6450          list: {
6451            'best dressed guest collection': '/shop/us/mens-best-dressed-guest-weddings-and-events',
6452            'a&f x trevor project': '/shop/us/pride',
6453            'gender inclusive': '/shop/us/lookbook-a-and-f-lookbook',
6454            'trend edit': '/shop/us/search?filtered=true&rows=90&searchTerm=Trend+Edit&start=0&departmentId=12202-ANF',
6455            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=Online+Exclusive&start=0&departmentId=12202-ANF',
6456            'matching set': '/shop/us/mens-coordinated-sets',
6457            'getaway shop': '#',
6458            'vol. 28': '#',
6459            'golf shop': '#',
6460            'for justice collection': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=For+Justice+Collection',
6461            '6 inch | 15 cm': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=6+inch',
6462            'a&f vintage stretch denim': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=A%26F+Vintage+Stretch+Denim',
6463            'a&f signature stretch denim': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=A%26F+Signature+Stretch+Denim',
6464            'a&f authentic rigid denim': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=Authentic+Rigid+Denim',
6465            'a&f basic stretch denim': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=basic+stretch+Denim',
6466            'a&f signature stretch twill': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=Signature+Stretch+Twill',
6467            '7 inch | 18 cm': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=7+inch',
6468            '9 inch | 23 cm': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=9+inch',
6469            '3 inch | 7 cm': '/shop/us/search?departmentCategoryId=12202-ANF&searchTerm=3+inch'
6470          }
6471        },
6472        'Women\'s': {
6473          list: {
6474            'best dressed guest collection': '/shop/us/womens-best-dressed-guest-weddings-and-events',
6475            'a&f x trevor project': '/shop/us/pride',
6476            'gender inclusive': '/shop/us/lookbook-a-and-f-lookbook',
6477            'trend edit': '/shop/us/search?filtered=true&rows=90&searchTerm=Trend+Edit&start=0&departmentId=12203-ANF',
6478            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=Online+Exclusive&start=0&departmentId=12203-ANF',
6479            'matching set': '/shop/us/womens-matching-sets-dresses-and-rompers',
6480            'getaway shop': '#',
6481            'vol. 28': '#',
6482            'premium footwear collection': '/shop/us/search?departmentCategoryId=12203-ANF&searchTerm=premium+footwear+collection',
6483            'abercrombie x tia booth': '#',
6484            'for justice collection': '/shop/us/search?filtered=true&rows=90&searchTerm=For+Justice+Collection&start=0&departmentId=12203-ANF',
6485            'a&f all day comfort stretch denim': '/shop/us/search?departmentCategoryId=12203-ANF&searchTerm=A%26F+All+Day+Comfort+Stretch+Denim',
6486            'a&f signature stretch denim': '/shop/us/search?departmentCategoryId=12203-ANF&searchTerm=A%26F+Signature+Stretch+Denim',
6487            'a&f vintage stretch denim': '/shop/us/search?departmentCategoryId=12203-ANF&searchTerm=A%26F+Vintage+Stretch+Denim',
6488            'authentic rigid denim': '/shop/us/search?departmentCategoryId=12203-ANF&searchTerm=Authentic+Rigid+Denim',
6489            'hold-you-in stretch denim': '/shop/us/search?departmentCategoryId=12203-ANF&searchTerm=Hold-You-In+Stretch+Denim'
6490          }
6491        }
6492      },
6493      kids: {
6494        boys: {
6495          list: {
6496            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=179205-KIDS',
6497            'matching set': '/shop/us/kids/boys-matching-sets',
6498            'the cool stuff': '/shop/us/search?filtered=true&rows=90&searchTerm=THE+COOL+STUFF&start=0&departmentId=179205-KIDS',
6499            'vol. 28': '#',
6500            'everybody collection': '/shop/us/kids/kids-everybody-collection'
6501          }
6502        },
6503        girls: {
6504          list: {
6505            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=179206-KIDS',
6506            'matching set': '/shop/us/kids/girls-matching-sets',
6507            'the cool stuff': '/shop/us/search?filtered=true&rows=90&searchTerm=THE+COOL+STUFF&start=0&departmentId=179206-KIDS',
6508            'vol. 28': '#',
6509            'everybody collection': '/shop/us/kids/kids-everybody-collection'
6510          }
6511        }
6512      },
6513      hol: {
6514        'Men\'s': {
6515          list: {
6516            'pride collection': '/shop/us/pride-collection',
6517            'gender inclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=gender+inclusive&start=0&departmentId=12551-HOL',
6518            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=12551-HOL',
6519            'must-have collection': '/shop/us/mens-must-have-collection',
6520            'all day gameplay': '/shop/us/mens-all-day-gameplay',
6521            'part of a matching set': '/shop/us/search?departmentCategoryId=12551-HOL&searchTerm=part+of+a+matching+set'
6522          }
6523        },
6524        'Women\'s': {
6525          list: {
6526            'pride collection': '/shop/us/pride-collection',
6527            'gender inclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=gender+inclusive&start=0&departmentId=12552-HOL',
6528            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=12552-HOL',
6529            'all day gameplay': '/shop/us/mens-all-day-gameplay',
6530            'part of a matching set': '/shop/us/womens-matching-sets',
6531            'built in shorts': '#',
6532            'i have pockets': '#',
6533            'classic stretch': '#',
6534            'advanced stretch': '#',
6535            'soft stretch': '#'
6536          }
6537        }
6538      },
6539      gh: {
6540        'Men\'s': {
6541          list: {
6542            'pride collection': '/shop/us/gilly-hicks/pride-collection',
6543            'gender inclusive': '/shop/us/gilly-hicks/unisex',
6544            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=65014360-GH',
6545            'part of a matching set': '/shop/us/search?filtered=true&rows=90&
6545searchTerm=part+of+a+matching+set&start=0&departmentId=65014360-GH'
6546          }
6547        },
6548        'Women\'s': {
6549          list: {
6550            'pride collection': '/shop/us/gilly-hicks/pride-collection',
6551            'gender inclusive': '/shop/us/gilly-hicks/unisex',
6552            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=65014366-GH',
6553            'part of a matching set': '/shop/us/search?filtered=true&rows=90&searchTerm=part+of+a+matching+set&start=0&departmentId=65014366-GH'
6554          }
6555        }
6556      },
6557      st: {
6558        'men\'s': {
6559          list: {
6560            'gender inclusive': '/shop/us/social-tourist/shop-all-unisex',
6561            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=65014738-ST'
6562          }
6563        },
6564        'women\'s': {
6565          list: {
6566            'gender inclusive': '/shop/us/social-tourist/shop-all-unisex',
6567            'online exclusive': '/shop/us/search?filtered=true&rows=90&searchTerm=online+exclusive&start=0&departmentId=65014738-ST'
6568          }
6569        }
6570      }
6571    };
6572
6573    var publicMembers = {
6574      computeWhiteList: function computeWhiteList(testSegment, brand, deptName) {
6575        var whitelist = null;
6576        switch (testSegment) {
6577          case 'B':
6578            whitelist = list1[brand] && list1[brand][deptName] && list1[brand][deptName].list;
6579            break;
6580          case 'C':
6581            whitelist = list2[brand] && list2[brand][deptName] && list2[brand][deptName].list;
6582            break;
6583          default:
6584            break;
6585        }
6586        return whitelist;
6587      }
6588    };
6589
6590    return publicMembers;
6591  });
6592
6593
6594
6595redesign.define('productModules/product/productNameAndDescription',[
6596  'productModules/helpers/Utils',
6597  'productModules/helpers/hyperlinkShortDescriptorsSplitTest'
6598], function ProductNameAndDescription(Utils, whitelistHelper) {
6599  'use strict';
6600
6601  var productUniqueNameSelector = '.product-page-info__title .product-title-component';
6602  var productPromoSelector = '.product-price-v2__promo-info';
6603  var productShortDescSelector = '.short-description';
6604
6605  var separator = ' | ';
6606  var messageBus = $(ANF);
6607
6608  var publicMembers = {
6609    listen: function listen() {
6610      messageBus.on('productPageInfo:swatchSelected productPageInfo:swatchOnLoad', onSwatchSelected);
6611      messageBus.on('shortDescriptorTest:init', handleShortDescriptorSplitTestInit);
6612    }
6613  };
6614
6615  function onSwatchSelected(e, $selectedSwatch, $productSection, productId) {
6616    var productData = Utils.getProductData(productId);
6617    var isLoyaltyRegion = ANF.params.storeAttributes.loyalty.enabled;
6618    var isProductBadgeEnabled = ANF.params.storeAttributes.catalogV2.hasProductBadgeEnabled;
6619    if (productData) {
6620      updateProductName($productSection, productData);
6621      updateMerchPromoMsg($productSection, productData);
6622
6623      var isEarlyAccessProduct = Utils.productHasEarlyAccessIndicator(productId);
6624      if (isLoyaltyRegion && isEarlyAccessProduct && !isProductBadgeEnabled) {
6625        updateEarlyAccessDescription($productSection);
6626      } else {
6627        updateShortDescription($productSection, productData, window.digitalData.get('test.pdpHyperlinkDescriptor', 'A'));
6628      }
6629    }
6630  }
6631
6632  function updateProductName($productSection, productData) {
6633    var newProductName = Utils.getValueFromObject(productData, 'name', '');
6634    var $productName = $productSection.find(productUniqueNameSelector);
6635    $productName.html(newProductName);
6636  }
6637
6638  function updateMerchPromoMsg($productSection, productData) {
6639    var merchPromoMsg = Utils.getValueFromObject(productData, 'merchPromoMsg', '');
6640    // no need to further manipulate merchPromoMsg if it's blank
6641    var newMerchPromoMsg = merchPromoMsg === '' ? '' : '<span class="promo-badge">' + merchPromoMsg + '</span>';
6642    var $merchPromo = $productSection.find(productPromoSelector);
6643    // edge case: When there's no $merchPromo when load but there is a new merchPromoMsg on swatch click
6644    // we need to create and add $merchPromo on the DOM as last child of .product-price-v2
6645    if (!$merchPromo.length && !!newMerchPromoMsg) {
6646      $merchPromo = $(document.createElement('div'));
6647      $merchPromo.addClass('product-price-v2__promo-info product-price-v2__promo-info--bogo');
6648      $productSection.find('.product-price-v2').append($merchPromo);
6649    }
6650
6651    $merchPromo.html(newMerchPromoMsg);
6652  }
6653
6654  function updateEarlyAccessDescription($productSection) {
6655    var earlyAccessTMNT =  ANF.messaging.product.PDP_EARLY_ACCESS;
6656    var $productShortDesc = $productSection.find(productShortDescSelector);
6657
6658    $productShortDesc.html(earlyAccessTMNT);
6659  }
6660
6661  function handleShortDescriptorSplitTestInit(e, segment) {
6662    var $productSection = Utils.getProductSection();
6663    var productData = Utils.getProductData($productSection.data('productid'));
6664    updateShortDescription($productSection, productData, segment);
6665  }
6666
6667  function updateShortDescription($productSection, productData, segment) {
6668    var shortDesc1 = Utils.getValueFromObject(productData, 'shortDe
6668sc1', '');
6669    var shortDesc2 = Utils.getValueFromObject(productData, 'shortDesc2', '');
6670
6671    if (segment !== 'A') {
6672      var deptName = ANF.catalog.data.categoryHierarchyObj[1].enName;
6673      var productBrand = productData.productAttrs.brand;
6674      var descriptorWhitelist = whitelistHelper.computeWhiteList(segment, productBrand, deptName);
6675      var shortDesc1Link = descriptorWhitelist[shortDesc1.toLowerCase()];
6676      var shortDesc2Link = descriptorWhitelist[shortDesc2.toLowerCase()];
6677      shortDesc1 = shortDesc1Link ? '<a href=' + shortDesc1Link + '>' + shortDesc1 + '</a>' : null;
6678      shortDesc2 = shortDesc2Link ? '<a href=' + shortDesc2Link + '>' + shortDesc2 + '</a>' : null;
6679    }
6680
6681    var shortDesc = $.grep([shortDesc1, shortDesc2], Boolean).join(separator);
6682    var $productShortDesc = $productSection.find(productShortDescSelector);
6683    $productShortDesc.html(shortDesc);
6684  }
6685
6686  return publicMembers;
6687});
6688
6689redesign.define('productModules/product/addToBag/productStickyAddToBag',[
6690  'productModules/helpers/productAddToBagHelper',
6691  'productModules/helpers/Utils',
6692  'globalServices/userState'
6693], function ProductStickyAddToBag(addToBagHelper, Utils, userStateService) {
6694  'use strict';
6695
6696  var fadeSpeed = 100;
6697  var fadeEasing = 'linear';
6698  var addToBagButtonSelectorClass = '.product .product-page-add-to-bag__button';
6699  var addToBagFormContainerSelectorClass = '.product-page-add-to-bag__container';
6700  var stickyAddToBagContainerSelectorClass = '.product-page-sticky-add-to-bag__container';
6701  var quickviewActiveModalSelectorClass = '.product-quickview__modal[data-open="true"]';
6702  var stickySizeTileSelectorClass = '.product-page-sticky-size-tile__container';
6703  var stickySizeTrayOverlaySelectorClass = '.product-page-sticky-size-tile__overlay';
6704  var stickyOverlay = '<div class="product-page-sticky-size-tile__overlay"></div>';
6705  var stickyAddToBagButtonSelectorClass = '.product-page-sticky-add-to-bag__container .product-page-add-to-bag__button';
6706  var stickySizeTileInputsSelector = '.product-page-sticky-size-tile__container  .product-sizes .product-attrs__attr input';
6707  var sizeTileContainerSelectorClass = '.product-page__swatches-attributes';
6708  var attributeTrayWrapperSelectorClass = '.attribute-tray-wrapper';
6709  var attributeTrayCollapsedState = 'collapsed-state';
6710  var attributeTraySizeTileState = 'size-tile-state';
6711  var attributeTrayState = 'collapsed-state';
6712  var productSection = '.product-page-v2-modules';
6713  var memberAccessSelector = '.product .member-early-access-logged-out';
6714  var stickyMemberAccessSelectorClass = '.product-page-sticky-add-to-bag__container .member-early-access-logged-out';
6715
6716  var messageBus = $(ANF);
6717
6718  return function StickyAddToBagObserver(productIntersectionObserver) {
6719    function wireIntersectionObserver(productId) {
6720      var $addToBagButton = memberAccessFlagCheck(productId);
6721      var addToBagButtonObserver = new productIntersectionObserver.IntersectionObserver(
6722        function productIntersectionObserverCallback(entries) {
6723          for (var i = 0, len = entries.length; i < len; i++) {
6724            var atbButton = entries[i];
6725            // when boundingClientRect y is less than 0, it means button was scrolled off the top of the page,
6726            // only worry about intersect to hide/show sticky when the button is scrolled into/out of view at the bottom!
6727            if (ANF.breakpoints.screen === 'small_phone' || ANF.breakpoints.screen === 'phone') {
6728              handleIntersection(atbButton.isIntersecting);
6729            }
6730          }
6731        },
6732        {
6733          threshold: 1
6734        }
6735      );
6736      addToBagButtonObserver.observe($addToBagButton[0]);
6737    }
6738
6739    function handleIntersection(isIntersecting) {
6740      var isCollapsedState = attributeTrayState === attributeTrayCollapsedState;
6741      if (isIntersecting) { // scrolling down, disable everything
6742        $(stickyAddToBagContainerSelectorClass).slideUp(200);
6743        publicMembers.toggleStickySizeTiles(false);
6744      } else if (!isIntersecting && !isCollapsedState) { // scrolling up and size tiles were active, show sticky tiles!
6745        publicMembers.toggleStickySizeTiles(true);
6746      } else { // scrolling up and size tiles weren't active, show sticky button
6747        $(stickyAddToBagContainerSelectorClass).slideDown(200);
6748      }
6749    }
6750
6751    function memberAccessFlagCheck(productId) {
6752      var $addToBagButton = $(addToBagButtonSelectorClass);
6753      var earlyAccessFlag = Utils.productHasEarlyAccessIndicator(productId);
6754      if (earlyAccessFlag && !userStateService.isLoggedIn()) {
6755        $addToBagButton = $(memberAccessSelector);
6756      }
6757      return $addToBagButton;
6758    }
6759
6760    var publicMembers = {
6761      'bindEvents': function bindEvents() {
6762        var $document = $(document);
6763        $document.on('click', stickyAddToBagButtonSelectorClass, publicMembers.handleStickyATBClick);
6764        $document.on('click', stickySizeTileInputsSelector, publicMembers.handleStickySizeTileSelection);
6765        $document.on('click', stickySizeTrayOverlaySelectorClass, publicMembers.closeAttributeTray);
6766      },
6767      listen: function listen() {
6768        messageBus.on('productPageInfo:load productPageInfo:swatchSelected', publicMembers.addToBagLoad);
6769      },
6770      'setupStickyAddToBagButton': function setupStickyAddToBagButton(productId) {
6771        var $addToBagButton = memberAccessFlagCheck(productId);
6772        var $stickyAddToBagButton = $addToBagButton.clone(true); // Copy the add to bag button and it's event listeners
6773        var $stickyAddToBagContainer = $(stickyAddToBagContainerSelectorClass); // Container that has padding
6774
6775        if ($(stickyAddToBagButtonSelectorClass).length < 1 && $(stickyMemberAccessSelectorClass).length < 1 ) {
6776          // Inject our copied button into our container that has padding
6777          $stickyAddToBagContainer.append($stickyAddToBagButton);
6778          wireIntersectionObserver(productId);
6779        }
6780      },
6781      'toggleStickySizeTiles': function toggleStickySizeTiles(showStickySizeTiles) {
6782        var $stickySizeTileContainer = $(stickySizeTileSelectorClass);
6783        var $overlay = $(stickySizeTrayOverlaySelectorClass);
6784
6785        if (showStickySizeTiles) {
6786          $stickySizeTileContainer.slideDown(200);
6787          $overlay.fadeIn(fadeSpeed, fadeEasing);
6788          publicMembers.setAttributeTrayState(attributeTrayState);
6789        } else {
6790          $stickySizeTileContainer.slideUp(200);
6791          $overlay.fadeOut(fadeSpeed, fadeEasing);
6792        }
6793      },
6794      'showSizeTileTray': function showSizeTileTray() {
6795        publicMembers.setAttributeTrayState(attributeTraySizeTileState);
6796        publicMembers.toggleStickySizeTiles(true);
6797      },
6798      'closeStickySizeTray': function closeStickySizeTray() {
6799        publicMembers.toggleStickySizeTiles(false);
6800        publicMembers.setAttributeTrayState(attributeTrayCollapsedState);
6801      },
6802      'addToBagLoad': function addToBagLoad() {
6803        // only setup sticky add to bag for new pdp phone view.
6804        if (!$(quickviewActiveModalSelectorClass).length && ANF.breakpoints && (ANF.breakpoints.screen === 'small_phone' || ANF.breakpoints.screen === 'phone') && !Utils.hasProductMFEEnabled()) {
6805          var $productSection = $(productSection);
6806          var productId = $productSection.data('productid');
6807          publicMembers.setupStickyAddToBagButton(productId);
6808          publicMembers.setupStickyAttributeTray();
6809        }
6810      },
6811      'setupStickyAttributeTray': function setupStickyAttributeTray() {
6812        // copy the html from the size group
6813        var $addToBagFormContainer = $(addToBagFormContainerSelectorClass);
6814        var $stickyAttributeTiles = $(sizeTileContainerSelectorClass).clone(true);
6815        var $attributeTrayWrapper = $(stickySizeTileSelectorClass).find(attributeTrayWrapperSelectorClass);
6816
6817        /*
6818          * For a11y, input names & id's need to be completely unique.
6819          * After cloning the size & swatch tiles, we append `_tray` to
6820          * make the cloned inputs unique
6821          */
6822        function identifyTraySizes(_idx, attr) {
6823          return attr + '_tray';
6824        }
6825
6826        $stickyAttributeTiles.find('input')
6827          .attr('id', identifyTraySizes)
6828          .attr('name', identifyTraySizes);
6829
6830        $stickyAttributeTiles.find('label').attr('for', identifyTraySizes);
6831
6832        if ($(stickySizeTileInputsSelector).length < 1) {
6833          $attributeTrayWrapper.append($stickyAttributeTiles);
6834          if (Utils.hasFinalSaleEnabled()) {
6835            var $finalSaleContainer = $('.final-sale-container').clone(true);
6836            $attributeTrayWrapper.find('.product-urgency-size-availability').after($finalSaleContainer);
6837          }
6838        }
6839        $addToBagFormContainer.append($(stickyOverlay));
6840      },
6841      'closeAttributeTray': function closeAttributeTray(e) {
6842        e.preventDefault();
6843
6844        var $attributeTray = $(stickySizeTileSelectorClass);
6845        var $overlay = $(stickySizeTrayOverlaySelectorClass);
6846
6847        $attributeTray.slideUp(200);
6848        publicMembers.setAttributeTrayState(attributeTrayCollapsedState);
6849        $(attributeTrayWrapperSelectorClass).animate({ scrollTop: 0 }, 'slow');
6850
6851        $overlay.fadeOut(fadeSpeed, fadeEasing);
6852      },
6853
6854      'setAttributeTrayState': function setAttributeTrayState(state) {
6855        var $attributeTray = $(stickySizeTileSelectorClass);
6856
6857        $attributeTray
6858          .removeClass(attributeTrayCollapsedState)
6859          .removeClass(attributeTraySizeTileState)
6860          .addClass(state);
6861
6862        attributeTrayState = state;
6863      },
6864
6865      handleStickyATBClick: function handleStickyATBClick(e) {
6866        e.preventDefault();
6867        var $form = $(e.currentTarget).closest(addToBagFormContainerSelectorClass);
6868        if (addToBagHelper.hasQualifiedSku($form)) {
6869          messageBus.trigger('initiateAddToBag:sticky', {$form: $form});
6870        } else {
6871          publicMembers.showSizeTileTray();
6872        }
6873      },
6874
6875      handleStickySizeTileSelection: function handleStickySizeTileSelection(e) {
6876        var $selectedTile = $(e.currentTarget).closest('.product-attrs__attr');
6877        if (!$selectedTile.hasClass('unavailable')) {
6878          var $form = $(e.currentTarget).closest(addToBagFormContainerSelectorClass);
6879
6880          messageBus.trigger('stickySizeTileSelected', {$selectedTile: $selectedTile});
6881
6882          if (addToBagHelper.hasQualifiedSku($form)) {
6883            messageBus.trigger('initiateAddToBag:sticky', {$form: $form});
6884            publicMembers.closeStickySizeTray();
6885          }
6886        }
6887      }
6888    };
6889
6890    return publicMembers;
6891  };
6892});
6893
6894redesign.define('productPartial/pdp_detailBadging',['handlebars','dsPartial/icon-block'], function(Handlebars) {
6895
6896this["ANF"] = this["ANF"] || {};
6897this["ANF"]["templates"] = this["ANF"]["templates"] || {};
6898
6899Handlebars.registerPartial("pdp_detailBadging", this["ANF"]["templates"]["pdp_detailBadging"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
6900    var stack1;
6901
6902  return "    <li>\n"
6903    + ((stack1 = container.invokePartial(partials["icon-block"],depth0,{"name":"icon-block","hash":{"data-center-vertically":true,"data-icon-size":(depth0 != null ? depth0.size : depth0),"data-icon":(depth0 != null ? depth0.filename : depth0)},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
6904    + "    </li>\n";
6905},"2":function(container,depth0,helpers,partials,data) {
6906    return "            <span class=\"h3\">"
6907    + container.escapeExpression(container.lambda((depth0 != null ? depth0.text : depth0), depth0))
6908    + "</span>\n";
6909},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
6910    var stack1;
6911
6912  return "<ul class=\"detail-badging-list split-list\">\n"
6913    + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.badges : depth0),{"name":"each","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
6914    + "</ul>\n";
6915},"usePartial":true,"useData":true}));
6916
6917return this["ANF"];
6918
6919});
6920redesign.define('productModules/product/productDetailBadging',[
6921  'coreClass/ANFImage',
6922  'productModules/helpers/Utils',
6923  'productModules/helpers/imageLoadHelper',
6924  'productPartial/pdp_detailBadging',
6925  'anfUtil/testFramework'
6926], function ProductDetailBadging(
6927  ANFImage,
6928  Utils,
6929  imageLoadHelper,
6930  productPartialPdpDetailBadging,
6931  testFramework
6932) {
6933  'use strict';
6934
6935  var messageBus = $(ANF);
6936  var BRAND = '';
6937  var BADGE_MAP = {};
6938
6939  function addDetailBadgingBackground(productDataObject, $badgingContainer) {
6940    var imageUrl = ANFImage.instance()
6941      .setImageName(imageLoadHelper.getProd1ImageId(productDataObject.imageSets))
6942      .setWidth(800)
6943      .url;
6944
6945    $badgingContainer.css('background-image', 'url(' + imageUrl + ')');
6946  }
6947
6948  // TODO: Clean up paramter list to remove unused variables.EPIC-8683
6949  // using this funciton to condense the paramter list, getting us close to the EPIC-8683 Tech Debt
6950  function detailBadgingLoad(e, $selectedSwatch, $productSection, productId) {
6951    var productData = Utils.getProductData(productId);
6952    if (!Utils.isQuickviewOpened) {
6953      var badgingData = productData.productAttrsComplex.ProductBadgingCode;
6954      var tempDOM = '';
6955      var bigDetailObj = {badges: []};
6956      var $badgingContainer = $('.product-badging__container');
6957
6958      // Current badging data for a single badge items is just a value and name without an identifier, so we must check for the values array first
6959      // This will be addressed in greater detail on the backend in EPIC-8685
6960      if (badgingData && badgingData.values) {
6961        badgingData.values.forEach(function createBadgeTemplateObject(badge) {
6962          var iconFileName = BADGE_MAP[badge.identifier];
6963          bigDetailObj.badges.push({
6964            'filename': iconFileName,
6965            'size': 50,
6966            'text': badge.value
6967          });
6968        });
6969
6970        addDetailBadgingBackground(productData, $badgingContainer);
6971        tempDOM = productPartialPdpDetailBadging.templates.pdp_detailBadging(bigDetailObj);
6972        $productSection.find('.details-badge-list-wrapper').html(tempDOM);
6973        $badgingContainer.show();
6974      } else {
6975        $badgingContainer.hide();
6976        $badgingContainer.css('background-image', '');
6977      }
6978    }
6979  }
6980
6981  var publicMembers = {
6982    listen: function listen() {
6983      messageBus.on('productPageInfo:swatchOnLoad productPageInfo:swatchSelected mfe:SwatchSelected', detailBadgingLoad);
6984    },
6985    init: function init() {
6986      BRAND = testFramework.store.hol() ? 'hco' : 'anf';
6987
6988      if ($('.product-page-v2-modules').hasClass('is-kids-product')) {
6989        BRAND = 'kids';
6990      }
6991
6992      BADGE_MAP = {
6993        '100%RecycledFill': 'recycled-fill-hco',
6994        '2-WayZipper': 'two-way-zipper-anf',
6995        'TwoWayStretch': 'two-way-stretch-anf',
6996        '4-WayStretch': 'four-way-stretch-' + BRAND,
6997        'BuiltforOptimalWarmth': 'warm-hco',
6998        'Breathable': 'breathable-' + BRAND,
6999        'CozyLining': 'cozy-lining-' + BRAND,
7000        'CozyLinedPockets': 'cozy-lined-pockets-kids',
7001        'ConcealedPocket': 'concealed-pocket-anf',
7002        'ConcealedPhonePocket': 'concealed-phone-pocket-anf',
7003        'DownBlend': 'down-blend-hco',
7004        'DownFill': 'down-blend-hco',
7005        'DownInsulated': 'down-insulated-anf',
7006        'FleeceLinedPockets': 'fleece-lined-pockets-hco',
7007        'Insulated': 'insulated-anf',
7008        'InteriorPocket': 'interior-pocket-hco',
7009        'LightweightFabric': 'lightweight-fabric-anf',
7010        'LowImpactSupport': 'low-impact-support-gh',
7011        'MachineWashable': 'machine-washable-' + BRAND,
7012        'MediumImpactSupport': 'medium-impact-support-gh',
7013        'MemoryFoam': 'memory-foam-gh',
7014        'MoistureWicking': 'moisture-wicking-' + BRAND,
7015        'Packable': 'packable-anf',
7016        'PackableHood': 'packable-hood-hco',
7017        'PrimaloftInsulation': 'primaloft-insulation-anf',
7018        'RecycledFill': 'recycled-fill-hco',
7019        'RemovableFaux-FurTrim': 'removable-faux-fur-trim-' + BRAND,
7020        'RemovableHood': 'removable-hood-' + BRAND,
7021        'RemovableLiner': 'removable-liner-anf',
7022        'ResponsibleDownStandardCertified': 'responsible-down-standard-certified-hco',
7023        'Reversible': 'reversible-anf',
7024        'SeamSealed': 'seam-sealed-anf',
7025        'SoftTouchFabric': 'soft-touch-fabric-gh',
7026        'StretchFabric': 'stretch-fabric-' + BRAND,
7027        'SuperSoft': 'super-soft-anf',
7028        'VeganLeather': 'vegan-leather-anf',
7029        'WarmDownFill': 'warm-down-fill-hco',
7030        'WarmLikeDown': 'warm-hco',
7031        'WaterproofFabric': 'waterproof-fabric-anf',
7032        'WaterRepellent': 'water-repellent-anf',
7033        'WaterResistant': 'water-resistance-fabric-' + BRAND,
7034        'WaterResistantFabric': 'water-resistance-fabric-' + BRAND,
7035        'Wicking': 'wicking-anf',
7036        'WindproofFabric': 'windproof-fabric-anf',
7037        'WindResistant': 'wind-resistant-' + BRAND,
7038        'WindResistantFabric': 'wind-resistant-' + BRAND,
7039        'Wireless': 'wireless-gh',
7040        'WrinkleRelease': 'wrinkle-release-anf'
7041      };
7042    }
7043  };
7044
7045  return publicMembers;
7046});
7047
7048redesign.define('productModules/product/buyGridAccordions/productDetailsAccordion',['productModules/helpers/Utils',
7049  'productServices/product/template',
7050  'coreServices/geo/helper'
7051], function ProductDetailsAccordion(Utils, templateService, GeoHelper) {
7052  'use strict';
7053
7054  var messageBus = $(ANF);
7055  var hasNewLongDesc = ANF.params.storeAttributes.catalogV2.hasProductLongDescImportedCleanUP;
7056
7057  function loadDetailsAccordion(e, $selectedSwatch, $productSection) {
7058    var productId = $productSection.data('productid');
7059    var $swatch = $selectedSwatch;
7060    var productData = Utils.getProductData(productId);
7061    var longDescriptionDetails = productData.longDesc.trim();
7062
7063    if ($swatch.length === 0) {
7064      $swatch = $productSection.find('.product-swatches .selected');
7065    }
7066
7067    var kicId = $swatch.find('input').val();
7068    if (/\bimported[.,!?]?$/.test(longDescriptionDetails.toLowerCase())) {
7069      longDescriptionDetails = longDescriptionDetails.substring(0, longDescriptionDetails.lastIndexOf(' ')); // Imported text always last word
7070    }
7071    var detailsData = {
7072      productName: $.parseHTML(productData.name)[0].wholeText,
7073      longDescription: hasNewLongDesc ? productData.longDesc : longDescriptionDetails,
7074      storeItemNumber: getStoreItemNumber($swatch, kicId),
7075      webItemNumber: getWebItemNumber(productData, kicId),
7076      isChinaSite: GeoHelper.isChinaSite(),
7077      imported: productData.imported
7078    };
7079
7080    var accordionPanelContent = templateService.renderTemplate('detailsAccordion', detailsData);
7081    $productSection.find('.product-details__accordion .details-accordion__container').html(accordionPanelContent);
7082  }
7083
7084  function getStoreItemNumber($selectedSwatch, kicId) {
7085    var $buyGrid = $selectedSwatch.parents('.product-page__info');
7086    var $firstMatchingOption = $buyGrid.find('.product-page__skus option[data-kic="' + kicId + '"]').first();
7087    var newLongSku = $firstMatchingOption.attr('data-long-sku');
7088
7089    return newLongSku;
7090  }
7091
7092  function getWebItemNumber(productData, kicId) {
7093    var newWebCollection = productData.collection;
7094    var newWebKIC = kicId;
7095    var newWebItem = newWebCollection;
7096    if (typeof newWebKIC !== 'undefined' && newWebKIC.indexOf('KIC_') >= 0) {
7097      newWebItem += '/' + newWebKIC.split('KIC_')[1];
7098    }
7099
7100    return newWebItem;
7101  }
7102
7103  var publicMembers = {
7104    listen: function listen() {
7105      messageBus.on('productPageInfo:swatchOnLoad productPageInfo:swatchSelected', loadDetailsAccordion);
7106    }
7107  };
7108
7109  return publicMembers;
7110});
7111
7112redesign.define('productServices/product/productReviewService',[
7113], function ProductReviewService() {
7114  'use strict';
7115
7116  var reviewsContent = ANF.messaging.catalogV2.REVIEWS;
7117
7118  var publicMembers = {
7119    buildReviewSummaryModel: function buildReviewSummaryModel(data) {
7120      var bvProductId; // This is the BV product ID which correlates to our sku
7121      var fitPopularRecommendation = null;
7122      var fitTotalCount = 0;
7123
7124      if (typeof data.Includes !== 'undefined' && typeof data.Includes.Products !== 'undefined') {
7125        for (var key in data.Includes.Products) { // Quickest way to identify the first property in the object is to start to traverse them and then jump out
7126          if (data.Includes.Products.hasOwnProperty(key)) {
7127            bvProductId = key; // This is the BV product ID which correlates to our sku
7128            break;
7129          }
7130        }
7131      }
7132
7133      if (data.TotalResults > 0 && typeof data.Includes.Products !== 'undefined' && typeof data.Includes.Products[bvProductId] !== 'undefined' && typeof data.Includes.Products[bvProductId].ReviewStatistics !== 'undefined') {
7134        var secondaryRatingsAverages = data.Includes.Products[bvProductId].ReviewStatistics.SecondaryRatingsAverages;
7135        if (typeof secondaryRatingsAverages !== 'undefined' &&  (secondaryRatingsAverages.Fit_22 && typeof secondaryRatingsAverages.Fit_22.AverageRating !== 'undefined')) {
7136          fitPopularRecommendation = Math.round(secondaryRatingsAverages.Fit_22.AverageRating);
7137          fitTotalCount = data.Includes.Products[bvProductId].ReviewStatistics.TotalReviewCount;
7138          data.showFitRecommendation = true;
7139        }
7140
7141        if (fitTotalCount < 4) {
7142          data.showFitRecommendation = false;
7143        }
7144
7145        switch (fitPopularRecommendation) {
7146          case 1:
7147            data.fitRecommendation = reviewsContent.GLB_FIT_SMALL_TITLE_DESCRIPTION;
7148            break;
7149          case 2:
7150            data.fitRecommendation = reviewsContent.GLB_FIT_SOMEWHAT_SMALL_TITLE_DESCRIPTION;
7151            break;
7152          case 3:
7153            data.fitRecommendation = reviewsContent.GLB_FIT_TRUE_TITLE_DESCRIPTION;
7154            break;
7155          case 4:
7156            data.fitRecommendation = reviewsContent.GLB_FIT_SOMEWHAT_LARGE_TITLE_DESCRIPTION;
7157            break;
7158          case 5:
7159            data.fitRecommendation = reviewsContent.GLB_FIT_LARGE_TIT
7159LE_DESCRIPTION;
7160            break;
7161          default:
7162            break;
7163        }
7164      }
7165
7166      return data;
7167    }
7168  };
7169
7170  return publicMembers;
7171});
7172
7173redesign.define('productModules/helpers/garmentMeasurements',['productModules/helpers/Utils'], function GarmentMeasurements(Utils) {
7174  'use strict';
7175
7176  var savedMeasurementObj = {};
7177
7178  function buildMeasurements(keys, tmnts, isEyeware, attrs, valueKey, labelKey) {
7179    return keys.reduce(function buildMeasurementReducer(arr, key) {
7180      if (attrs.hasOwnProperty(key)) {
7181        var tooltip = isEyeware ? tmnts.MEASUREMENTS_ACCORDION.MEASUREMENTS_TOOLTIPS : tmnts.GARMENT_MEASUREMENT_LABELS.GARMENT_TOOLTIPS;
7182        var label = isEyeware ? tmnts.MEASUREMENTS_ACCORDION.MEASUREMENTS_LABELS : tmnts.GARMENT_MEASUREMENT_LABELS.GARMENT_LABELS;
7183
7184        var obj = {
7185          tooltip: false,
7186          tooltipId: key,
7187          tooltipHeader: tooltip[key].HEADER,
7188          tooltipBody: tooltip[key].BODY
7189        };
7190        obj[labelKey] = label[key];
7191        obj[valueKey] = attrs[key];
7192        arr.push(obj);
7193      }
7194      return arr;
7195    }, []);
7196  }
7197
7198  var publicMembers = {
7199    getGarmentMeasurementData: function getGarmentMeasurementData(productId, anfObject, $productSection) {
7200      var productAttrsData = Utils.getProductData(productId).productAttrs;
7201
7202      if (Utils.isKidsProduct($productSection)) {
7203        return { baseSize: productAttrsData.BaseMeasurementSize, measurements: [] };
7204      }
7205
7206      if (!savedMeasurementObj[productId]) {
7207        var keys = [
7208          'BaseSleeveLengthMeasurement',
7209          'BaseShoulderToHemMeasurement',
7210          'BaseInseamX-ShortMeasurement',
7211          'BaseInseamShortMeasurement',
7212          'BaseInseamRegularMeasurement',
7213          'BaseInseamLongMeasurement',
7214          'BaseFrontRiseMeasurement',
7215          'BaseLegOpeningCircumferenceMeasurement',
7216          'BaseSkirtLengthMeasurement'
7217        ];
7218
7219        savedMeasurementObj[productId] = {
7220          baseSize: productAttrsData.BaseMeasurementSize,
7221          measurements: buildMeasurements(
7222            keys,
7223            anfObject.messaging.product,
7224            false,
7225            productAttrsData,
7226            'garmentValue',
7227            'garmentLabel'
7228          )
7229        };
7230      }
7231      return savedMeasurementObj[productId];
7232    },
7233
7234    getEyewearMeasurementData: function getEyewearMeasurementData(productId, anfObject) {
7235      var productAttrsMeasurementData = Utils.getProductData(productId).productAttrs;
7236
7237      if (!savedMeasurementObj[productId]) {
7238        var keys = [
7239          'EyewearDimensionLensWidth',
7240          'EyewearDimensionBridgeWidth',
7241          'EyewearDimensionArmLength'
7242        ];
7243        savedMeasurementObj[productId] = {
7244          isEyeware: true,
7245          measurements: buildMeasurements(
7246            keys,
7247            anfObject.messaging.product,
7248            true,
7249            productAttrsMeasurementData,
7250            'lensMeasurementsValue',
7251            'lensMeasurementsLabel'
7252          )
7253        };
7254      }
7255      return savedMeasurementObj[productId];
7256    }
7257  };
7258
7259  return publicMembers;
7260});
7261
7262redesign.define('productPartial/pdp_modelSpecs',['handlebars','wcsHelper/i18n'], function(Handlebars) {
7263
7264this["ANF"] = this["ANF"] || {};
7265this["ANF"]["templates"] = this["ANF"]["templates"] || {};
7266
7267Handlebars.registerPartial("pdp_modelSpecs", this["ANF"]["templates"]["pdp_modelSpecs"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
7268    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.escapeExpression, alias3=container.lambda;
7269
7270  return "<p class=\"size-guide-fit-model-specs\">\n    "
7271    + alias2(helpers.i18n.call(alias1,"product.PDP_TEXT_MODEL_SPECS_LABEL",{"name":"i18n","hash":{},"data":data}))
7272    + ": <span class=\"model-specs__height-measurement\">"
7273    + ((stack1 = alias3((depth0 != null ? depth0.modelHeight : depth0), depth0)) != null ? stack1 : "")
7274    + "</span> <span class='lowercase'>"
7275    + alias2(helpers.i18n.call(alias1,"product.GLB_WEARINGSIZE",{"name":"i18n","hash":{},"data":data}))
7276    + "</span> <span class=\"model-specs__size-measurement\">"
7277    + alias2(alias3((depth0 != null ? depth0.modelSize : depth0), depth0))
7278    + "</span>\n</p>\n";
7279},"useData":true}));
7280
7281return this["ANF"];
7282
7283});
7284redesign.define('productPartial/pdp_sizeFitAccordionContent',['handlebars','wcsHelper/i18n','productPartial/pdp_modelSpecs','productPartial/pdp_garmentMeasurements'], function(Handlebars) {
7285
7286this["ANF"] = this["ANF"] || {};
7287this["ANF"]["templates"] = this["ANF"]["templates"] || {};
7288
7289Handlebars.registerPartial("pdp_sizeFitAccordionContent", this["ANF"]["templates"]["pdp_sizeFitAccordionContent"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
7290    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
7291
7292  return "\n  <div class=\"hr above-fit-information\"></div>\n\n  <h4 class=\"h4\">"
7293    + container.escapeExpression(helpers.i18n.call(alias1,"product.FIT_INFORMATION",{"name":"i18n","hash":{},"data":data}))
7294    + "</h4>\n  <div class=\"fit-information\">\n    <ul>\n"
7295    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasFitRecommendation : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7296    + "\n"
7297    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.fitType : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7298    + "\n"
7299    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.style : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7300    + "\n"
7301    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.bottomRiseCode : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7302    + "\n"
7303    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.bottomLengthCode : depth0),{"name":"if","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7304    + "\n"
7305    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasModelSpecs : depth0),{"name":"if","hash":{},"fn":container.program(12, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7306    + "    </ul>\n  </div>\n\n"
7307    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.compareFitLinkEspot : depth0),{"name":"if","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
7308},"2":function(container,depth0,helpers,partials,data) {
7309    var stack1;
7310
7311  return "        <li>\n          <p class=\"size-fit-reviewer-recommendation\">\n            "
7312    + ((stack1 = container.lambda((depth0 != null ? depth0.contextualFitFullTMNT : depth0), depth0)) != null ? stack1 : "")
7313    + "\n          </p>\n        </li>\n";
7314},"4":function(container,depth0,helpers,partials,data) {
7315    var alias1=container.lambda, alias2=container.escapeExpression;
7316
7317  return "        <li>"
7318    + alias2(alias1((depth0 != null ? depth0.fitHeaderTMNT : depth0), depth0))
7319    + ": "
7320    + alias2(alias1((depth0 != null ? depth0.fitDescription : depth0), depth0))
7321    + "</li>\n";
7322},"6":function(container,depth0,helpers,partials,data) {
7323    var alias1=container.lambda, alias2=container.escapeExpression;
7324
7325  return "        <li>"
7326    + alias2(alias1((depth0 != null ? depth0.style : depth0), depth0))
7327    + ": "
7328    + alias2(alias1((depth0 != null ? depth0.styleDescription : depth0), depth0))
7329    + "</li>\n";
7330},"8":function(container,depth0,helpers,partials,data) {
7331    var alias1=container.lambda, alias2=container.escapeExpression;
7332
7333  return "        <li>"
7334    + alias2(alias1((depth0 != null ? depth0.riseTMNT : depth0), depth0))
7335    + ": "
7336    + alias2(alias1((depth0 != null ? depth0.bottomRiseCode : depth0), depth0))
7337    + "</li>\n";
7338},"10":function(container,depth0,helpers,partials,data) {
7339    var alias1=container.lambda, alias2=container.escapeExpression;
7340
7341  return "        <li>"
7342    + alias2(alias1((depth0 != null ? depth0.lengthTMNT : depth0), depth0))
7343    + ": "
7344    + alias2(alias1((depth0 != null ? depth0.bottomLengthCode : depth0), depth0))
7345    + "</li>\n";
7346},"12":function(container,depth0,helpers,partials,data) {
7347    var stack1;
7348
7349  return "        <li>\n"
7350    + ((stack1 = helpers["with"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.modelSpecs : depth0),{"name":"with","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7351    + "        </li>\n";
7352},"13":function(container,depth0,helpers,partials,data) {
7353    var stack1;
7354
7355  return "            <div class=\"model-specs-container\">\n              "
7356    + ((stack1 = container.invokePartial(partials.pdp_modelSpecs,depth0,{"name":"pdp_modelSpecs","fn":container.program(14, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
7357    + "\n            </div>\n";
7358},"14":function(container,depth0,helpers,partials,data) {
7359    return "";
7360},"16":function(container,depth0,helpers,partials,data) {
7361    var stack1;
7362
7363  return "    "
7364    + ((stack1 = container.lambda((depth0 != null ? depth0.compareFitLinkEspot : depth0), depth0)) != null ? stack1 : "")
7365    + "\n";
7366},"18":function(container,depth0,helpers,partials,data) {
7367    return "  <div class=\"hr below-fit-information\"></div>\n";
7368},"20":function(container,depth0,helpers,partials,data) {
7369    var stack1;
7370
7371  return "  <div class=\"garment-measurements\">\n"
7372    + ((stack1 = helpers["with"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.garmentData : depth0),{"name":"with","hash":{},"fn":container.program(21, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7373    + "  </div>\n";
7374},"21":function(container,depth0,helpers,partials,data) {
7375    var stack1;
7376
7377  return "      "
7378    + ((stack1 = container.invokePartial(partials.pdp_garmentMeasurements,depth0,{"name":"pdp_garmentMeasurements","fn":container.program(14, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
7379    + "\n";
7380},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
7381    var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
7382
7383  return ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasFitInfo : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7384    + "\n"
7385    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.displayHR : depth0),{"name":"if","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7386    + "\n"
7387    + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasGarmentMeasurements : depth0),{"name":"if","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
7388},"usePartial":true,"useData":true}));
7389
7390return this["ANF"];
7391
7392});
7393redesign.define('productPartial/pdp_fitRecommendation',['handlebars'], function(Handlebars) {
7394
7395this["ANF"] = this["ANF"] || {};
7396this["ANF"]["templates"] = this["ANF"]["templates"] || {};
7397
7398Handlebars.registerPartial("pdp_fitRecommendation", this["ANF"]["templates"]["pdp_fitRecommendation"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
7399    var stack1;
7400
7401  return "<p class=\"size-fit-reviewer-recommendation\">\n  "
7402    + ((stack1 = container.lambda((depth0 != null ? depth0.contextualFitFullTMNT : depth0), depth0)) != null ? stack1 : "")
7403    + "\n</p>\n";
7404},"useData":true}));
7405
7406return this["ANF"];
7407
7408});
7409redesign.define('globalServices/marketing/eSpotContentProvider',[],function () {
7410  'use strict';
7411
7412  /**
7413	 * @description ESpot content API proxy service.
7414	 * @exports globalServices/marketing/eSpotContentProvider
7415	 * @see {@link https://ecom106.abercrombie.com/apidocs/#!/Marketing/getESpot}
7416	 */
7417  var publicMembers = {
7418    /**
7419		 * @description A name/value object used by jQuery to represent a query string parameter.
7420		 * @typedef {Object} NameValue
7421		 * @property {string} name - The parameter name.
7422		 * @property {*} value - The parameter value.
7423		 */
7424
7425    /**
7426		 * @description The normalized Espot content settings object used throughout this service.
7427		 * @typedef {Object} NormalizedSettings
7428		 * @property {NameValue[]} parameters - An array of name/value objects that will be passed to the API.
7429		 */
7430
7431    /**
7432		 * @description The URL for the `getESpot` API endpoint. Note: The ending forward slash ("/") is required.
7433		 * @type {string}
7434		 */
7435    'apiUrl': ANF.params.storeAttributes.apiURLRoot + '/content/marketing/',
7436
7437    /**
7438		 * @description Get eSpot content.
7439		 * @param {string[]} eSpotNames - An array of eSpot names to retrieve.
7440     * @param {object[]} settings - An array of objects containing additional parameters
7441		 * @throws {Error} If passed an invalid argument.
7442		 * @return {Promise} A jQuery Promise implementation.
7443		 */
7444    'fetch': function (eSpotNames, settings) {
7445      if (Array.isArray(eSpotNames) && eSpotNames.length === 0) {
7446        return this.getEmptyArrayPromise();
7447      }
7448
7449      var normalizedSettings = this.normalizeSettings(eSpotNames, settings);
7450
7451      if (!this.validateSettings(normalizedSettings)) {
7452        throw new Error('An invalid argument was supplied');
7453      }
7454
7455      var queryString = normalizedSettings.parameters.map(function (parameter) {
7456        return parameter.name + '=' + encodeURIComponent(parameter.value);
7457      }).join('&');
7458
7459      // The `name[]` parameter is not being URL decoded by the server so
7460      // we are using a manually generating a query string instead of
7461      // using the built in jQuery functionality.
7462      return $.getJSON(this.apiUrl + '?' + queryString).promise();
7463    },
7464
7465    /**
7466		 * @description Get a Promise which resolves with an empty array for use in implementing the null object pattern.
7467		 * @return {Promise} A jQuery Promise implementation.
7468		 */
7469    'getEmptyArrayPromise': function () {
7470      return $.Deferred().resolve([]).promise();
7471    },
7472
7473    /**
7474		 * @description A callback function to be used with `Array.prototype.reduce` to validate an array of settings parameters.
7475		 * @param {*} previousValue - This argument is currently unused.
7476		 * @param {*} currentValue - The item to be verified as a name/value object.
7477		 * @return {boolean} A Boolean indicating whether the current reduction is valid.
7478		 */
7479    'isValidParametersReduction': function (previousValue, currentValue) {
7480      return $.isPlainObject(currentValue) &&
7481				currentValue.hasOwnProperty('name') &&
7482				typeof currentValue.name === 'string' &&
7483				currentValue.hasOwnProperty('value');
7484    },
7485
7486    /**
7487		 * @description Normalize the settings passed into the service.
7488		 * @param {string[]} eSpotNames - An array of Espot names to normalize.
7489     * @param {object[]} settings - An array of objects containing additional parameters
7490		 * @return {NormalizedSettings} The normalized settings object.
7491		 */
7492    'normalizeSettings': function (eSpotNames, settings) {
7493      var normalizedSettings = {'parameters': []};
7494
7495      if (!Array.isArray(eSpotNames)) {
7496        return normalizedSettings;
7497      }
7498
7499      eSpotNames.forEach(function (name) {
7500        normalizedSettings.parameters.push({
7501          'name': 'name',
7502          'value': name
7503        });
7504      });
7505
7506      if (Array.isArray(settings)) {
7507        settings.forEach(function (addlParam) {
7508          normalizedSettings.parameters.push({
7509            'name': addlParam.key,
7510            'value': addlParam.value
7511          });
7512        });
7513      }
7514
7515      return normalizedSettings;
7516    },
7517
7518    /**
7519		 * @description Validate a normalized settings object.
7520		 * @param {NormalizedSettings} settings - A normalized settings object.
7521		 * @return {boolean} A Boolean indicating whether the provided settings are valid or not.
7522		 */
7523    'validateSettings': function (settings) {
7524      if (!$.isPlainObject(settings)) {
7525        return false;
7526      }
7527
7528      if (!Array.isArray(settings.parameters) || settings.parameters.length === 0) {
7529        return false;
7530      }
7531
7532      if (!settings.parameters.reduce(this.isValidParametersReduction, false)) {
7533        return false;
7534      }
7535
7536      return true;
7537    }
7538  };
7539
7540  return publicMembers;
7541});
7542
7543redesign.define('api/adobeExperienceManager/dataSource',[
7544  'api/Classes/Adapter',
7545  'api/Classes/AdapterError',
7546  'anfUtil/testFramework',
7547  'anfUtil/constants'
7548], function aemContentAPIAdapter(APIAdapter, AdapterError, test, coreConstants)  {
7549  'use strict';
7550
7551  var adapter = new APIAdapter();
7552
7553  /**
7554   * @property {object} CONSTANTS
7555   * @property {object} CONSTANTS.BRAND
7556   * @property {string} CONSTANTS.BRAND.ANF anf
7557   * @property {string} CONSTANTS.BRAND.HOL hol
7558   * @property {string} CONSTANTS.BRAND.KIDS kids
7559   * @property {object} CONSTANTS.MATCH_CRITERIA
7560   * @property {string} CONSTANTS.MATCH_CRITERIA.DEFAULT default_home_page
7561   */
7562  adapter.CONSTANTS = {
7563    SWITCH_MODES: {
7564      OFF: 'OFF',
7565      AEM: 'AEM',
7566      AEM_JSP: 'AEM_JSP'
7567    },
7568    ESPOT_SWITCH: {
7569      OFF: '0',
7570      ON: '1'
7571    },
7572    ESPOT_CONFIG: {
7573      AEM: '2',
7574      AEM_JSP: '3'
7575    }
7576  };
7577
7578  var errorMessages = {
7579    INVALID_TIMEOUT: 'The timeout attribute needs to be a number',
7580    INVALID_URL_ROOT: 'The urlRoot is required',
7581    INVALID_LOCALE: 'The locale is required',
7582    INVALID_ESPOT: 'The espot ID(s) is required',
7583    INVALID_STYLES_IN_RESPONSE: 'The stylesInResponse is required'
7584  };
7585
7586  /**
7587   * @property {object} REASON
7588   */
7589
7590  /**
7591   * @name read
7592   * @description Function to sit in front of the api call so we can add some logic if we are going to make the call or not
7593   * @param {object} [settings] - the settings to be supplied to the function
7594   * @param {Number} [settings.timeout=0] - the max time to wait for the ajax call to come back
7595   * @return {promise} this is a jquery promise that will be resolved/rejected with an object c
7595ontaining reason code and a combination of ajaxData, ajaxJqXHR, ajaxTextStatus, and ajaxErrorThrown depending on the result of the ajax call
7596   */
7597  adapter.configRead({
7598    endPoint: '/' + coreConstants.anf('params.storeAttributes.api.aem.aemApiURLContext') + '/v3',
7599    method: 'GET',
7600    getDataType: function getDataType(data) {
7601      return data.dataType || 'json';
7602    },
7603    getTimeout: function getTimeout(data) {
7604      return data.timeout || 0;
7605    },
7606    validation: function validation(data, context) {
7607      // validate data goes here
7608      if (test.type.defined(data.timeout, false) && test.type.not.number(data.timeout, false)) {
7609        throw new AdapterError(context.REASON.INVALID_PARAMS, errorMessages.INVALID_TIMEOUT);
7610      }
7611
7612      if (test.string.empty(data.locale, true)) {
7613        throw new AdapterError(context.REASON.INVALID_PARAMS, errorMessages.INVALID_LOCALE);
7614      }
7615
7616      if ((!test.object.containsKey(data, 'espotId', false) || test.string.empty(data.espotId, true)) &&
7617        (!test.object.containsKey(data, 'pageId', false) || test.string.empty(data.pageId, true))) {
7618        throw new AdapterError(context.REASON.INVALID_PARAMS, errorMessages.INVALID_ESPOT);
7619      }
7620
7621      if (!test.type.boolean(data.stylesInResponse, false)) {
7622        throw new AdapterError(context.REASON.INVALID_PARAMS, errorMessages.INVALID_STYLES_IN_RESPONSE);
7623      }
7624    },
7625    preAjax: function preAjax(data) {
7626      var myData = $.extend(true, {}, data);
7627      delete myData.timeout;
7628      delete myData.dataType;
7629      delete myData.adapterSettings;
7630      return myData;
7631    },
7632    done: function done(data, textStatus, jqXHR) {
7633      /**
7634       * @this CRUD
7635       */
7636      var response;
7637      var responseData = data;
7638      if (typeof responseData === 'string') {
7639        responseData = JSON.parse(data);
7640      }
7641      if (responseData && test.array.not.empty(responseData.response, false)) {
7642        response = this.getAjaxOkResponse(responseData.response, textStatus, jqXHR);
7643      } else {
7644        response = responseData;
7645      }
7646      this.deferred.resolve(response);
7647    }
7648  });
7649
7650  Object.freeze(adapter.CONSTANTS.SWITCH_MODES);
7651
7652  return adapter;
7653});
7654
7655redesign.define('coreServices/personalizedContent',[
7656  'api/adobeExperienceManager/dataSource',
7657  'anfUtil/testFramework'
7658], function personalizedContentService(
7659  aemContentAPI,
7660  test
7661) {
7662  'use strict';
7663
7664  var CONSTANTS = Object.create(Object.prototype, {
7665    REASONS: {
7666      value: Object.create(Object.prototype, {
7667        AJAX_OK: {
7668          value: 1
7669        },
7670        AJAX_FAIL: {
7671          value: 2
7672        },
7673        INVALID_PARAMS: {
7674          value: 3
7675        },
7676        NO_CONTENT: {
7677          value: 4
7678        }
7679      })
7680    },
7681    SWITCH_MODES: {
7682      value: aemContentAPI.CONSTANTS.SWITCH_MODES
7683    },
7684    ESPOT_SWITCH: {
7685      value: aemContentAPI.CONSTANTS.ESPOT_SWITCH
7686    },
7687    ESPOT_CONFIG: {
7688      value: aemContentAPI.CONSTANTS.ESPOT_CONFIG
7689    }
7690
7691  });
7692
7693  var standardResponseObject = {
7694    node: null,
7695    reason: null
7696  };
7697
7698  var adapterSettings;
7699  var response;
7700
7701  function handleFailedContentCalls(contentUri) {
7702    // Create container for failed content and fill it later
7703    var failedFragmentElement = document.querySelector('div[data-url="' + contentUri + '"]');
7704    if (failedFragmentElement === null) {
7705      failedFragmentElement = document.createElement('div');
7706      failedFragmentElement.classList.add('failed-fragment');
7707      failedFragmentElement.setAttribute('data-url', contentUri);
7708    }
7709    return failedFragmentElement;
7710  }
7711
7712  /**
7713   * @private
7714   * @description function to just make the call to get the aem content promise
7715   * @param {object} settings - the setting object
7716   * @param {string} settings.segment - the url of the content
7717   * @param {number} settings.timeout - the time wait for content to come back
7718   * @return {Deferred.promise} - the promise returned from the aemConentAPI.read call
7719   */
7720  function getAEMContentReadPromise(settings) {
7721    var myDeferred = new $.Deferred();
7722    if (!settings.segment) {
7723      return myDeferred.resolve(handleFailedContentCalls(settings.segment)).promise();
7724    }
7725    $.ajax({
7726      url: settings.segment,
7727      timeout: settings.timeout
7728    })
7729      .done(function contentDoneHandler(data) {
7730        var html = document.createElement('html');
7731        var element = document.createElement('div');
7732        var body;
7733
7734        html.innerHTML = data;
7735        body = html.querySelector('body');
7736        element.innerHTML = body.innerHTML;
7737
7738        myDeferred.resolve(element);
7739      })
7740      .fail(function contentFailHandler() {
7741        var failedFragmentElement = handleFailedContentCalls(settings.segment);
7742        myDeferred.resolve(failedFragmentElement);
7743      });
7744
7745    return myDeferred.promise();
7746  }
7747
7748  /*
7749  * @private
7750  * @description Creates a function to be used to stitch together one or more responses when we fetch the AEM Content
7751  * @param {$.Deferred} myDeferred - the Deferred object to be enacted upon
7752  * @return {function} A function to handle the success of making the request to get the aem content
7753  */
7754  function getAemContentReadSuccessHandler(myDeferred) {
7755    return function aemContentReadSuccessResponseHandler() {
7756      var content = Array.prototype.slice.call(arguments);
7757      var domNode = document.createElement('div');
7758      var responseObj = Object.create(standardResponseObject);
7759
7760      domNode = content.reduce(function contentReductionHandler(node, currentNode) {
7761        node.appendChild(currentNode);
7762        return node;
7763      }, domNode);
7764
7765      if (domNode.childNodes.length > 0) {
7766        responseObj.reason = CONSTANTS.REASONS.AJAX_OK;
7767        responseObj.node = domNode;
7768        myDeferred.resolve(responseObj);
7769      } else {
7770        // Fetch the standard function to fail with no content and execute it right away
7771        getFailWithNoContent(myDeferred)();
7772      }
7773    };
7774  }
7775
7776  /*
7777  * @private
7778  * @description Creates a function to be used to handle the results of the call to get the list of content from AEM
7779  * @param {object} settings - the setting object
7780  * @param {$.Deferred} settings.myDeferred - the Deferred object to be enacted upon
7781  * @param {number} settings.timeout - The time to wait for the HTML content to come back
7782  * @return {function} A function to handle the success of making the request to get the AEM content
7783  */
7784  function getAemSegmentReadSuccessHandler(settings) {
7785    return function aemSegmentReadSuccessHandler(results) {
7786      response = results;
7787      if (
7788        results &&
7789        results.reason === aemContentAPI.REASON.AJAX_OK &&
7790        test.array.not.empty(results.data, false)
7791      ) {
7792        if (adapterSettings.isSingleResponse) {
7793          settings.myDeferred.resolve(results);
7794        }
7795        // Need to use apply so that the map is treated as separate
7796        // arguments instead on one to take advantage of the $.when
7797        // marshaling of promises/Deferreds
7798        var fragments = results.data[0].pages.map(function mapHandler(fragment) {
7799          return fragment.path;
7800        }, this);
7801        $.when.apply($, fragments.map(function getPromiseListItem(segment) {
7802          return getAEMContentReadPromise({
7803            segment: segment,
7804            timeout: settings.timeout
7805          });
7806        }))
7807          .done(getAemContentReadSuccessHandler(settings.myDeferred))
7808          .fail(getFailWithNoContent(settings.myDeferred));
7809      } else {
7810        getFailWithNoContent(settings.myDeferred)();
7811      }
7812    };
7813  }
7814
7815  /*
7816  * @private
7817  * @description Creates a method that will reject the given Deferred with the reason of NO_CONTENT
7818  * @param  {$.Deferred} myDeferred - the Deferred object to be rejected
7819  * @return {function} a method to reject the supplied deferred with the NO_CONTENT reason
7820  */
7821  function getFailWithNoContent(myDeferred) {
7822    return function failWithNoContent() {
7823      var responseObj = Object.create(standardResponseObject);
7824      responseObj.reason = CONSTANTS.REASONS.NO_CONTENT;
7825      responseObj.node = document.createElement('div');
7826      myDeferred.reject(responseObj);
7827    };
7828  }
7829
7830
7831  return {
7832    reasons: CONSTANTS.REASONS,
7833    CONSTANTS: {
7834      SWITCH_MODES: CONSTANTS.SWITCH_MODES,
7835      ESPOT_SWITCH: CONSTANTS.ESPOT_SWITCH,
7836      ESPOT_CONFIG: CONSTANTS.ESPOT_CONFIG
7837    },
7838    /*
7839    * @description This acts a single point of entry to get the products that are currently saved from the server.  It will update local storage on successful call to the mysaves api
7840    * @param {string} brand - The brand that we are fetching content for
7841    * @param {string} locale - The local that should be used
7842    * @param {string} matchCriteria - The matching criteria
7843    * @param {number} aemTimeout - How long we should wait for the api call before timing out
7844    * @return {promise} this is a jQuery promise that will be resolved/rejected with an object containing reason code and a combination of ajaxData, ajaxJqXHR, ajaxTextStatus, and ajaxErrorThrown depending on the result of the ajax call
7845    */
7846    get: function get(data) {
7847      var myDeferred = new $.Deferred();
7848      var options = $.extend(true, {}, data);
7849      adapterSettings = data.adapterSettings;
7850      options.headers = {
7851        'x-source': 'CRS_WEB',
7852        Accept: 'application/json'
7853      };
7854      aemContentAPI.read(options)
7855        .done(getAemSegmentReadSuccessHandler({
7856          myDeferred: myDeferred,
7857          timeout: data.adapterSettings.aemHTMLTimeout
7858        })
7859        ).fail(getFailWithNoContent(myDeferred));
7860
7861      return myDeferred.promise();
7862    },
7863
7864    getFailedContent: function getFailedContent(settings) {
7865      return getAEMContentReadPromise(settings);
7866    },
7867
7868    getAEMResponse: function getAEMResponse() {
7869      return (response && response.data) ? response.data : [];
7870    }
7871  };
7872});
7873
7874redesign.define('globalPartial/productSliderTemplate',['handlebars','dsPartial/faux-button','dsPartial/product-template','dsPartial/product-name','dsPartial/product-price','dsPartial/product-price-text'], function(Handlebars) {
7875
7876this["ANF"] = this["ANF"] || {};
7877this["ANF"]["templates"] = this["ANF"]["templates"] || {};
7878
7879Handlebars.registerPartial("productSliderTemplate", this["ANF"]["templates"]["productSliderTemplate"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data,blockParams,depths) {
7880    var stack1;
7881
7882  return ((stack1 = container.invokePartial(partials["faux-button"],depth0,{"name":"faux-button","hash":{"data-prop":(depth0 != null ? depth0.productTemplateProps : depth0),"class-list":"js-product-card-button product-quickview__button"},"fn":container.program(2, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
7883},"2":function(container,depth0,helpers,partials,data,blockParams,depths) {
7884    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
7885
7886  return "		<div \n			class=\"js-product-card-wrapper product-card-wrapper product-card--"
7887    + alias2(alias1(((stack1 = (depth0 != null ? depth0.productAttrs : depth0)) != null ? stack1.brand : stack1), depth0))
7888    + "\"\n			data-collection=\""
7889    + alias2(alias1((depth0 != null ? depth0.collection : depth0), depth0))
7890    + "\"\n			data-images=\""
7891    + alias2(alias1(((stack1 = (depth0 != null ? depth0.productAttrs : depth0)) != null ? stack1.primaryFaceOutImage : stack1), depth0))
7892    + ","
7893    + alias2(alias1(((stack1 = (depth0 != null ? depth0.productAttrs : depth0)) != null ? stack1.primaryHoverImage : stack1), depth0))
7894    + ","
7895    + alias2(alias1(((stack1 = (depth0 != null ? depth0.productAttrs : depth0)) != null ? stack1.testFaceOutImage : stack1), depth0))
7896    + ","
7897    + alias2(alias1(((stack1 = (depth0 != null ? depth0.productAttrs : depth0)) != null ? stack1.testHoverImage : stack1), depth0))
7898    + "\"\n			data-kic=\""
7899    + alias2(alias1((depth0 != null ? depth0.kicId : depth0), depth0))
7900    + "\"\n			data-productId=\""
7901    + alias2(alias1((depth0 != null ? depth0.productId : depth0), depth0))
7902    + "\"\n			>\n"
7903    + ((stack1 = container.invokePartial(partials["product-template"],depth0,{"name":"product-template","hash":{"class-list":"ds-standard-vertical-example"},"fn":container.program(3, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
7904    + "		</div>\n";
7905},"3":function(container,depth0,helpers,partials,data,blockParams,depths) {
7906    return "			\n";
7907},"4":function(container,depth0,helpers,partials,data) {
7908    var alias1=container.lambda, alias2=container.escapeExpression;
7909
7910  return "					<img\n						class=\"product-card__image\"\n						src=\""
7911    + alias2(alias1((depth0 != null ? depth0.imagePath : depth0), depth0))
7912    + "\"\n						data-fallback=\""
7913    + alias2(alias1((depth0 != null ? depth0.imageFallbackPath : depth0), depth0))
7914    + "\"\n						alt=\""
7915    + alias2(alias1((depth0 != null ? depth0.name : depth0), depth0))
7916    + "\"\n						data-productId=\""
7917    + alias2(alias1((depth0 != null ? depth0.productId : depth0), depth0))
7918    + "\"\n					>\n";
7919},"6":function(container,depth0,helpers,partials,data) {
7920    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
7921
7922  return ((stack1 = container.invokePartial(partials["product-name"],depth0,{"name":"product-name","hash":{"class-list":"product-card__name-wrapper","brand":(depth0 != null ? depth0.brand : depth0)},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
7923    + "\n					<meta itemprop=\"name\" content=\""
7924    + alias2(alias1((depth0 != null ? depth0.name : depth0), depth0))
7925    + "\" />\n					<meta itemprop=\"image\" content=\""
7926    + alias2(alias1((depth0 != null ? depth0.imagePath : depth0), depth0))
7927    + "\" />\n\n					<div class=\"product-card__price\">\n						<div class=\"product-price-v2--inner\" data-priceFlag=\""
7928    + alias2(alias1((depth0 != null ? depth0.priceFlag : depth0), depth0))
7929    + "\">\n"
7930    + ((stack1 = container.invokePartial(partials["product-price"],depth0,{"name":"product-price","hash":{"clearance-text":((stack1 = (depth0 != null ? depth0.priceObj : depth0)) != null ? stack1.clearanceText : stack1),"type":((stack1 = (depth0 != null ? depth0.priceObj : depth0)) != null ? stack1.priceType : stack1),"description":((stack1 = (depth0 != null ? depth0.priceObj : depth0)) != null ? stack1.description : stack1)},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
7931    + "\n"
7932    + ((stack1 = helpers["with"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.memberPriceObj : depth0),{"name":"with","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
7933    + "						</div>\n					</div>\n";
7934},"7":function(container,depth0,helpers,partials,data) {
7935    var stack1;
7936
7937  return "						"
7938    + ((stack1 = container.lambda((depth0 != null ? depth0.name : depth0), depth0)) != null ? stack1 : "")
7939    + "\n";
7940},"9":function(container,depth0,helpers,partials,data) {
7941    var stack1;
7942
7943  return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.priceObj : depth0)) != null ? stack1.priceText : stack1),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
7944},"10":function(container,depth0,helpers,partials,data) {
7945    var stack1;
7946
7947  return ((stack1 = container.invokePartial(partials["product-price-text"],depth0,{"name":"product-price-text","hash":{"formatted-
7947price":(depth0 != null ? depth0.formattedPriceText : depth0),"type":(depth0 != null ? depth0.priceTextType : depth0)},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
7948},"11":function(container,depth0,helpers,partials,data) {
7949    return "";
7950},"13":function(container,depth0,helpers,partials,data) {
7951    var stack1;
7952
7953  return ((stack1 = container.invokePartial(partials["product-price"],depth0,{"name":"product-price","hash":{"clearance-text":(depth0 != null ? depth0.clearanceText : depth0),"type":(depth0 != null ? depth0.priceType : depth0),"description":(depth0 != null ? depth0.description : depth0),"class-list":"member-price"},"fn":container.program(14, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
7954},"14":function(container,depth0,helpers,partials,data) {
7955    var stack1;
7956
7957  return ((stack1 = helpers["with"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.priceText : depth0),{"name":"with","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
7958},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
7959    var stack1;
7960
7961  return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),depth0,{"name":"each","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
7962},"3_d":  function(fn, props, container, depth0, data, blockParams, depths) {
7963
7964  var decorators = container.decorators;
7965
7966  fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(4, data, 0, blockParams, depths),"inverse":container.noop,"args":["product-image-section"],"data":data}) || fn;
7967  fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(6, data, 0, blockParams, depths),"inverse":container.noop,"args":["product-content"],"data":data}) || fn;
7968  return fn;
7969  }
7970
7971,"useDecorators":true,"usePartial":true,"useData":true,"useDepths":true}));
7972
7973return this["ANF"];
7974
7975});
7976redesign.define('globalPartial/productSliderTemplateV3',['handlebars','dsPartial/faux-button','dsPartial/product-template','dsPartial/product-name','dsPartial/product-price','dsPartial/product-price-text'], function(Handlebars) {
7977
7978this["ANF"] = this["ANF"] || {};
7979this["ANF"]["templates"] = this["ANF"]["templates"] || {};
7980
7981Handlebars.registerPartial("productSliderTemplateV3", this["ANF"]["templates"]["productSliderTemplateV3"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data,blockParams,depths) {
7982    var stack1;
7983
7984  return ((stack1 = container.invokePartial(partials["faux-button"],depth0,{"name":"faux-button","hash":{"data-prop":(depth0 != null ? depth0.productTemplateProps : depth0),"class-list":"js-product-card-button product-quickview__button"},"fn":container.program(2, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
7985},"2":function(container,depth0,helpers,partials,data,blockParams,depths) {
7986    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
7987
7988  return "        <div \n            class=\"js-product-card-wrapper product-card-wrapper product-card--"
7989    + alias2(alias1((depth0 != null ? depth0.brand : depth0), depth0))
7990    + "\"\n            data-collection=\""
7991    + alias2(alias1((depth0 != null ? depth0.collectionId : depth0), depth0))
7992    + "\"\n            data-images=\""
7993    + alias2(alias1((depth0 != null ? depth0.primaryFaceOut : depth0), depth0))
7994    + ","
7995    + alias2(alias1(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.attributes : depth0)) != null ? stack1.primaryHoverImage : stack1)) != null ? stack1.value : stack1)) != null ? stack1["0"] : stack1)) != null ? stack1.value : stack1), depth0))
7996    + ","
7997    + alias2(alias1(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.attributes : depth0)) != null ? stack1.testFaceOutImage : stack1)) != null ? stack1.value : stack1)) != null ? stack1["0"] : stack1)) != null ? stack1.value : stack1), depth0))
7998    + ","
7999    + alias2(alias1(((stack1 = ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.attributes : depth0)) != null ? stack1.testHoverImage : stack1)) != null ? stack1.value : stack1)) != null ? stack1["0"] : stack1)) != null ? stack1.value : stack1), depth0))
8000    + "\"\n            data-kic=\""
8001    + alias2(alias1((depth0 != null ? depth0.kicId : depth0), depth0))
8002    + "\"\n            data-productId=\""
8003    + alias2(alias1((depth0 != null ? depth0.productId : depth0), depth0))
8004    + "\"\n            >\n"
8005    + ((stack1 = container.invokePartial(partials["product-template"],depth0,{"name":"product-template","hash":{"class-list":"ds-standard-vertical-example"},"fn":container.program(3, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
8006    + "        </div>\n";
8007},"3":function(container,depth0,helpers,partials,data,blockParams,depths) {
8008    return "            \n";
8009},"4":function(container,depth0,helpers,partials,data) {
8010    var alias1=container.lambda, alias2=container.escapeExpression;
8011
8012  return "                    <img\n                        class=\"product-card__image\"\n                        src=\""
8013    + alias2(alias1((depth0 != null ? depth0.imagePath : depth0), depth0))
8014    + "\"	\n                        data-fallback=\""
8015    + alias2(alias1((depth0 != null ? depth0.imageFallbackPath : depth0), depth0))
8016    + "\"\n                        alt=\""
8017    + alias2(alias1((depth0 != null ? depth0.name : depth0), depth0))
8018    + "\"\n                        data-productId=\""
8019    + alias2(alias1((depth0 != null ? depth0.productId : depth0), depth0))
8020    + "\"\n                    >\n";
8021},"6":function(container,depth0,helpers,partials,data) {
8022    var stack1, alias1=container.lambda, alias2=container.escapeExpression;
8023
8024  return ((stack1 = container.invokePartial(partials["product-name"],depth0,{"name":"product-name","hash":{"class-list":"product-card__name-wrapper","brand":(depth0 != null ? depth0.brand : depth0)},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
8025    + "\n                    <meta itemprop=\"name\" content=\""
8026    + alias2(alias1((depth0 != null ? depth0.name : depth0), depth0))
8027    + "\" />\n                    <meta itemprop=\"image\" content=\""
8028    + alias2(alias1((depth0 != null ? depth0.imagePath : depth0), depth0))
8029    + "\" />\n\n                    <div class=\"product-card__price\">\n                        <div class=\"product-price-v2--inner\" data-priceFlag=\""
8030    + alias2(alias1((depth0 != null ? depth0.priceFlag : depth0), depth0))
8031    + "\">\n"
8032    + ((stack1 = container.invokePartial(partials["product-price"],depth0,{"name":"product-price","hash":{"clearance-text":((stack1 = (depth0 != null ? depth0.priceObj : depth0)) != null ? stack1.clearanceText : stack1),"type":((stack1 = (depth0 != null ? depth0.priceObj : depth0)) != null ? stack1.priceType : stack1),"description":((stack1 = (depth0 != null ? depth0.priceObj : depth0)) != null ? stack1.description : stack1)},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
8033    + "\n"
8034    + ((stack1 = helpers["with"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.memberPriceObj : depth0),{"name":"with","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
8035    + "                        </div>\n                    </div>\n";
8036},"7":function(container,depth0,helpers,partials,data) {
8037    var stack1;
8038
8039  return "                        "
8040    + ((stack1 = container.lambda((depth0 != null ? depth0.name : depth0), depth0)) != null ? stack1 : "")
8041    + "\n";
8042},"9":function(container,depth0,helpers,partials,data) {
8043    var stack1;
8044
8045  return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.priceObj : depth0)) != null ? stack1.priceText : stack1),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
8046},"10":function(container,depth0,helpers,partials,data) {
8047    var stack1;
8048
8049  return ((stack1 = container.invokePartial(partials["product-price-text"],depth0,{"name":"product-price-text","hash":{"formatted-
8049price":(depth0 != null ? depth0.formattedPriceText : depth0),"type":(depth0 != null ? depth0.priceTextType : depth0)},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
8050},"11":function(container,depth0,helpers,partials,data) {
8051    return "";
8052},"13":function(container,depth0,helpers,partials,data) {
8053    var stack1;
8054
8055  return ((stack1 = container.invokePartial(partials["product-price"],depth0,{"name":"product-price","hash":{"clearance-text":(depth0 != null ? depth0.clearanceText : depth0),"type":(depth0 != null ? depth0.priceType : depth0),"description":(depth0 != null ? depth0.description : depth0),"class-list":"member-price"},"fn":container.program(14, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
8056},"14":function(container,depth0,helpers,partials,data) {
8057    var stack1;
8058
8059  return ((stack1 = helpers["with"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.priceText : depth0),{"name":"with","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
8060},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
8061    var stack1;
8062
8063  return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),depth0,{"name":"each","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
8064},"3_d":  function(fn, props, container, depth0, data, blockParams, depths) {
8065
8066  var decorators = container.decorators;
8067
8068  fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(4, data, 0, blockParams, depths),"inverse":container.noop,"args":["product-image-section"],"data":data}) || fn;
8069  fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(6, data, 0, blockParams, depths),"inverse":container.noop,"args":["product-content"],"data":data}) || fn;
8070  return fn;
8071  }
8072
8073,"useDecorators":true,"usePartial":true,"useData":true,"useDepths":true}));
8074
8075return this["ANF"];
8076
8077});
8078redesign.define('globalModulesHelpers/substituteTMNTParams',[], function () {
8079  'use strict';
8080
8081  var publicMembers = {
8082    substitute: function (str, params) {
8083      var pattern = '[{]__INDEX__[}]';
8084      var result = str;
8085      var expr;
8086      for (var i = 0; i < params.length; i++) {
8087        expr = new RegExp(pattern.replace('__INDEX__', i), 'g');
8088        result = result.replace(expr, params[i]);
8089      }
8090
8091      return result;
8092    }
8093  };
8094
8095  return publicMembers;
8096});
8097
8098function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
8099
8100function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
8101
8102function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8103
8104redesign.define('es6CoreServices/recommendationSliderHelpers',['exports', 'anfUtil/constants', 'globalModulesHelpers/substituteTMNTParams'], function (exports, constants, substituteTMNTParams) {
8105  'use strict';
8106  /**
8107   * @name isProductListV3Enabled
8108   * @public
8109   * @description Function that returns whether product list v3 flag is turned on or not
8110   *
8111   * @return {Boolean} - Returns a boolean.
8112   */
8113
8114  var isProductListV3Enabled = function isProductListV3Enabled() {
8115    var _window$digitalData, _window$digitalData$e;
8116
8117    var storeAttributeFlags = (_window$digitalData = window.digitalData) === null || _window$digitalData === void 0 ? void 0 : (_window$digitalData$e = _window$digitalData.export()) === null || _window$digitalData$e === void 0 ? void 0 : _window$digitalData$e.flag;
8118    return storeAttributeFlags ? storeAttributeFlags['has-product-list-v3-enabled'] : false;
8119  };
8120  /**
8121   * @name generateProductPriceObject
8122   * @public
8123   * @description This function will add a 'priceObj' object to the each product object in the product list array
8124   * @param {String} productsList - An array of objects. Each object contains product details
8125   *
8126   * @return {String} - Returns productsList array, with each object containing 'priceObj'
8127   */
8128
8129
8130  var generateProductPriceObject = function generateProductPriceObject(productsList) {
8131    return productsList.map(function (product) {
8132      var clearanceText = product.priceFlag === 'clearance' ? constants.anf('messaging.catalogV2.TMNT.cardClearance.value') : null;
8133      var priceType = product.priceFlag === 'clearance' ? product.priceFlag : '';
8134      var listPrice = product.prices.list.price;
8135      var listPriceFormatted = product.prices.list.formatted;
8136      var offerPrice = product.prices.offer.price;
8137      var offerPriceFormatted = product.prices.offer.formatted;
8138      var hasDiscountPricing = listPrice > offerPrice; // Ignoring range pricing & member pricing
8139
8140      var priceObjConfiguration = hasDiscountPricing ? {
8141        description: substituteTMNTParams.substitute(constants.anf('messaging.product.GLB_PRICE_DESC_IND_IND'), [listPriceFormatted, offerPriceFormatted]),
8142        priceText: [{
8143          formattedPriceText: listPriceFormatted,
8144          priceTextType: 'original'
8145        }, {
8146          formattedPriceText: offerPriceFormatted,
8147          priceTextType: 'discount'
8148        }]
8149      } : {
8150        description: listPriceFormatted,
8151        priceText: [{
8152          priceTextType: '',
8153          formattedPriceText: listPriceFormatted
8154        }]
8155      };
8156      return _objectSpread(_objectSpread({}, product), {}, {
8157        priceObj: _objectSpread({
8158          priceType: priceType,
8159          clearanceText: clearanceText
8160        }, priceObjConfiguration)
8161      });
8162    });
8163  };
8164
8165  exports.isProductListV3Enabled = isProductListV3Enabled;
8166  exports.generateProductPriceObject = generateProductPriceObject;
8167  return exports;
8168});
8169
8170redesign.define('globalModules/productSlider',[
8171  'anfUtil/testFramework',
8172  'anfcore/components/slider',
8173  'coreClass/ANFImage',
8174  'globalPartial/productSliderTemplate',
8175  'globalPartial/productSliderTemplateV3',
8176  'es6CoreServices/recommendationSliderHelpers'
8177],
8178function productSlider(
8179  test,
8180  dsSlider,
8181  ANFImage,
8182  globalPartialProductSliderTemplate,
8183  globalPartialProductSliderTemplateV3,
8184  recommendationSliderHelpers
8185) {
8186  'use strict';
8187
8188  var NO_TARGET = 'No target node provided.';
8189  var INVALID_ARRAY = 'No array of products provided.';
8190  var sliderDefaults = {
8191    clickable: true,
8192    infinite: true,
8193    slidesToShow: 2,
8194    slidesToScroll: 2,
8195    dots: false,
8196    arrows: true,
8197    centerMode: true,
8198    mobileFirst: true,
8199    respondTo: 'window',
8200    responsive: [
8201      {
8202        breakpoint: 0,
8203        settings: {
8204          arrows: true,
8205          centerMode: false,
8206          slidesToShow: 2,
8207          slidesToScroll: 2
8208        }
8209      },
8210      {
8211        breakpoint: 540,
8212        settings: {
8213          arrows: true,
8214          centerMode: false,
8215          slidesToShow: 3,
8216          slidesToScroll: 3
8217        }
8218      },
8219      {
8220        breakpoint: 825,
8221        settings: {
8222          arrows: true,
8223          centerMode: false,
8224          slidesToShow: 4,
8225          slidesToScroll: 4
8226        }
8227      },
8228      {
8229        breakpoint: 1200,
8230        settings: {
8231          arrows: true,
8232          centerMode: false,
8233          slidesToShow: 5,
8234          slidesToScroll: 5
8235        }
8236      }
8237    ]
8238  };
8239
8240  /**
8241   * @description Function to build the slider html and instantiate slick slider
8242   * @param  {array} productArray - an array of product objects
8243	 * @param  {object} targetNode - an object the slider will be injected in to
8244    * @param  {object} settings - an object used to override the default slider settings
8245    * @param  {function} customDataProperties - function that accepts a product and returns an array of key/value pairs to construct custom data properties
8246    * @return {undefined}
8247    */
8248  function buildProductSlidesHtml(productArray, targetNode, settings, customDataProperties) {
8249    var dsSliderSettings = $.extend({}, sliderDefaults, settings);
8250    var productHtml;
8251    var localProductArray;
8252
8253    var isProductListV3Enabled = recommendationSliderHelpers.isProductListV3Enabled();
8254    var normalizeFunction = isProductListV3Enabled ? normalizeProductDataV3 : normalizeProductData;
8255    var templateFunction = isProductListV3Enabled ? globalPartialProductSliderTemplateV3.templates.productSliderTemplateV3 : globalPartialProductSliderTemplate.templates.productSliderTemplate;
8256
8257    localProductArray = normalizeFunction(productArray, customDataProperties);
8258    productHtml = templateFunction(localProductArray);
8259
8260    // Disabling for this line that needs to manipulate the DOM
8261    // eslint-disable-next-line no-param-reassign
8262    targetNode.innerHTML = productHtml;
8263
8264    dsSlider.default().initializeSlider(targetNode, dsSliderSettings);
8265
8266    bindEvents(targetNode);
8267
8268    // add the automation testing attribute to the slick slider wrapper
8269    targetNode.setAttribute('data-aui', 'product-slider');
8270  }
8271
8272  /**
8273   * @description Function that binds a custom function to the error trigger
8274   * @param  {object} targetNode - an object the slider will be injected in to
8275   * @return {undefined}
8276   */
8277  function bindEvents(targetNode) {
8278    var sliderImages = targetNode.querySelectorAll('.product-card__image');
8279    for (var i = 0, len = sliderImages.length; i < len; i++) {
8280      setImageErrorHandler(sliderImages[i]);
8281    }
8282  }
8283
8284  function setImageErrorHandler(imgNode) {
8285    $(imgNode).one('error', function imgError() {
8286      imageErrorHandler(this);
8287    });
8288  }
8289
8290  /**
8291   * @description Function to replace all slider images src with data src
8292   * @param  {object} imgNode - node of the image that failed to load
8293   * @return {undefined}
8294   */
8295  function imageErrorHandler(imgNode) {
8296    var failedProducts = $(imgNode).parents('.js-product-slider').find('.product-card__image[data-productId="' + imgNode.dataset.productid + '"]');
8297
8298    for (var i = 0, len = failedProducts.length; i < len; i++) {
8299      failedProducts[i].src = failedProducts[i].dataset.fallback;
8300    }
8301  }
8302
8303  /**
8304   * @description Function to generate a string of custom data properties
8305   * @param  {array} properties - Array of key/value pairs for custom properties
8306   * @return {string} - Empty string or a string of concatenated data properties
8307   */
8308  function generateCustomDataProperties(properties) {
8309    var result = [];
8310
8311    if (test.type.array(properties) && !test.array.empty(properties)) {
8312      result = properties.map(function propertiesMap(prop) {
8313        if (prop.key) {
8314          return 'data-' +
8315            prop.key +
8316            (typeof prop.value !== 'undefined' && prop.value !== '' ? "='" + prop.value + "'" : '');
8317        }
8318
8319        return '';
8320      });
8321
8322      return result.join(' ');
8323    }
8324
8325    return '';
8326  }
8327
8328  function capitalizeFirstLetter(word) {
8329    if (typeof word === 'string' ||  word instanceof String) {
8330      return word.charAt(0).toUpperCase() + word.slice(1);
8331    }
8332    return '';
8333  }
8334
8335  /**
8336   * @description Function that performs required string concatenation to properly build a slider
8337   * Same as normalizeProductData, adpated for product list v3 response
8338   * @param  {array} productArray - array of product objects
8339   * @param  {function} customProperties - sets custom properties on individual products
8340   * @return {array} - array of modified product objects
8341   */
8342  function normalizeProductDataV3(productArray, customProperties) {
8343    var normalizedDataArray = productArray;
8344    var imageWidth = 347;
8345    var imageName;
8346
8347    for (var i = 0, len = normalizedDataArray.length; i < len; i++) {
8348      var product = normalizedDataArray[i];
8349      var propsArray = test.type.function(customProperties) ? customProperties(product) : [];
8350      var faceout = product.primaryFaceOut || 'prod';
8351      var faceoutType = capitalizeFirstLetter(faceout.slice(0, faceout.search(/\d/)));
8352      var customDataProperties = generateCustomDataProperties(propsArray);
8353      var imageSet = 'imageSet' + faceoutType;
8354
8355      product.productTemplateProps = "data-collectionid='" + product.collectionId +
8356          "' data-productid='" + product.productId +
8357          "' data-imageid='" + product.kicId + // image id is just kicId
8358          "' data-faceout='" + faceout + "' " +
8359          "' data-product-brand='" + product.brand + "' " +
8360          customDataProperties;
8361
8362      imageName = product[imageSet] ? product[imageSet][0] : product.imageSetProd[0];
8363
8364      product.imagePath = ANFImage.instance()
8365        .setImageName(imageName)
8366        .setWidth(imageWidth)
8367        .url;
8368
8369      product.imageFallbackPath = ANFImage.instance()
8370        .setImageName(product.kicId + '_prod1')
8371        .setWidth(imageWidth)
8372        .url;
8373    }
8374    return normalizedDataArray;
8375  }
8376
8377  /**
8378   * @description Function that performs required string concatenation to properly build a slider
8379   * @param  {array} productArray - array of product objects
8380   * @param  {function} customProperties - sets custom properties on individual products
8381   * @return {array} - array of modified product objects
8382   */
8383  function normalizeProductData(productArray, customProperties) {
8384    var normalizedDataArray = productArray.filter(function removeEmptyImageSet(product) {
8385      return !test.object.empty(product.imageSet);
8386    });
8387    var imageWidth = 347;
8388    var imageName;
8389
8390    for (var i = 0, len = normalizedDataArray.length; i < len; i++) {
8391      var product = normalizedDataArray[i];
8392      var faceout = extractFaceout(product.productAttrs.PrimaryFaceOutImage);
8393      var propsArray = test.type.function(customProperties) ? customProperties(product) : [];
8394      var faceoutType = faceout.slice(0, faceout.search(/\d/));
8395      var customDataProperties = generateCustomDataProperties(propsArray);
8396
8397      product.productTemplateProps = "data-collectionid='" + product.collection +
8398        "' data-productid='" + product.productId +
8399        "' data-imageid='" + product.imageId +
8400        "' data-faceout='" + faceout + "' " +
8401        "' data-product-brand='" + product.productAttrs.brand + "' " +
8402        customDataProperties;
8403
8404      imageName = product.imageSet[faceoutType] ? product.imageSet[faceoutType][0].id : product.imageSet.prod[0].id;
8405
8406      product.imagePath = ANFImage.instance()
8407        .setImageName(imageName)
8408        .setWidth(imageWidth)
8409        .url;
8410
8411      product.imageFallbackPath = ANFImage.instance()
8412        .setImageName(product.imageId + '_prod1')
8413        .setWidth(imageWidth)
8414        .url;
8415    }
8416    return normalizedDataArray;
8417  }
8418
8419  /**
8420   * @description Function that extracts the faceout value from the image ID
8421   * @param  {string} PrimaryFaceOutImage - image ID
8422   * @return {string} - image faceout value
8423   */
8424  function extractFaceout(PrimaryFaceOutImage) {
8425    if (test.type.string(PrimaryFaceOutImage)) {
8426      var faceout = PrimaryFaceOutImage.split('_');
8427      return faceout[faceout.length - 1];
8428    }
8429
8430    return 'prod1';
8431  }
8432
8433  /**
8434   * @description Function that checks if the parameter is an Array
8435   * @param  {array} productArray - an array of product objects
8436   * @return {undefined}
8437   */
8438  function validateProductArray(productArray) {
8439    if (
8440      test.type.not.array(productArray, false) ||
8441      (!productArray.length)
8442    ) {
8443      throw new Error(INVALID_ARRAY);
8444    }
8445  }
8446
8447  /**
8448   * @description Function that checks id the parameter is an Object
8449   * @param  {object} targetNode - an object the slider will be injected in to
8450   * @return {undefined}
8451   */
8452  function validateTargetNode(targetNode) {
8453    if (test.object.null(targetNode, false)) {
8454      throw new Error(NO_TARGET);
8455    }
8456  }
8457
8458  function resolveSliderOpts(overrides) {
8459    return $.extend({}, sliderDefaults, overrides);
8460  }
8461
8462  var publicMembers = {
8463    /**
8464     * @description Function that instantiates the product slider
8465     * @param  {array} productArray - an array of product objects
8466     * @param  {object} targetNode - an object the slider will be injected in to
8467     * @param  {object} settings - an object used to override the default slider settings
8468     * @return {undefined}
8469     */
8470    'init': function init(productArray, targetNode, settings) {
8471      var localSettings = $.extend(true, {}, settings);
8472      var sliderSettings = resolveSliderOpts(localSettings.slider);
8473
8474      validateTargetNode(targetNode);
8475
8476      validateProductArray(productArray);
8477
8478      buildProductSlidesHtml(productArray, targetNode, sliderSettings, localSettings.dataProps);
8479    }
8480  };
8481
8482  return publicMembers;
8483});
8484
8485redesign.define('coreServices/generateProductPriceObject',['globalModulesHelpers/substituteTMNTParams'], function generateProductPriceObject(substituteTMNTParams) {
8486  'use strict';
8487
8488  var showDiscount = function showDiscountPercentage(product) {
8489    return product.discountPercentage && parseInt(product.discountPercentage, 10) > 0 && ANF.catalog.data.selectedSort.sortOption === 'discount';
8490  };
8491
8492  var getMemberPriceConfig = function getMemberPriceConfig(product) {
8493    var hasRangeMemberPricing = product.highContractPrice > product.lowContractPrice;
8494    var formattedLowMemberPrice = product.lowContractPriceFmt;
8495    var formattedHighMemberPrice = product.highContractPriceFmt;
8496    var memberPriceObj = {
8497      clearanceText: ANF.messaging.loyalty.MEMBER_CLEARANCE,
8498      priceType: 'member',
8499      priceText: {
8500        priceTextType: 'member'
8501      },
8502      'data-prop': {
8503        aui: 'member-price'
8504      }
8505    };
8506
8507    if (hasRangeMemberPricing) {
8508      memberPriceObj.description = substituteTMNTParams.substitute(ANF.messaging.loyalty.MEMBER_PRICE_DESC_RANGE, [
8509        formattedLowMemberPrice,
8510        formattedHighMemberPrice
8511      ]);
8512      memberPriceObj.priceText.formattedPriceText = formattedLowMemberPrice + ' - ' + formattedHighMemberPrice;
8513    } else {
8514      memberPriceObj.description = substituteTMNTParams.substitute(ANF.messaging.loyalty.MEMBER_PRICE_DESC_REG, [formattedLowMemberPrice]);
8515      memberPriceObj.priceText.formattedPriceText = formattedLowMemberPrice;
8516    }
8517
8518    return memberPriceObj;
8519  };
8520
8521  return function getProductArray(products) {
8522    var productArray = products;
8523
8524    for (var i = 0, len = productArray.length; i < len; i++) {
8525      var product = products[i];
8526
8527      var clearanceText = product.showClearanceBadge ? ANF.messaging.catalogV2.TMNT.cardClearance.value : null;
8528
8529      var formattedLowListPrice = product.lowListPriceFmt;
8530      var formattedHighListPrice = product.highListPriceFmt;
8531      var formattedLowPrice = product.lowPriceFmt;
8532      var formattedHighPrice = product.highPriceFmt;
8533
8534      var hasRangeListPricing = product.highListPrice > product.lowListPrice;
8535      var hasRangeOfferPricing = product.highPrice > product.lowPrice;
8536      var hasRangePricing = hasRangeListPricing || hasRangeOfferPricing;
8537      var hasDiscountHighPricing = product.highListPrice > product.highPrice;
8538      var hasDiscountLowPricing = product.lowListPrice > product.lowPrice;
8539      var hasDiscountPricing = hasDiscountHighPricing || hasDiscountLowPricing;
8540
8541      var priceType = product.showClearanceBadge ? 'clearance' : '';
8542      var priceObj = {
8543        priceType: priceType,
8544        clearanceText: clearanceText
8545      };
8546
8547      var priceObjConfiguration = {};
8548
8549      if (product.discountPercentage) {
8550        priceObj.discountPercentage = product.discountPercentage.toString();
8551      }
8552
8553      priceObj.showDiscountPercentage = showDiscount(product);
8554
8555      // Wonky logic to specifically deal with the outlet-pricing case where the product OFFER (low) price can
8556      // actually be higher than the product list (HIGH) price. TODO: Remove this once the underlying issue is resolved.
8557      if (product.lowPrice > product.lowListPrice) {
8558        priceObjConfiguration = {
8559          description: formattedLowPrice,
8560          priceText: [
8561            {
8562              priceTextType: '',
8563              formattedPriceText: formattedLowPrice
8564            }
8565          ]
8566        };
8567      } else if (hasRangePricing && !hasDiscountPricing) {
8568        // Range list price
8569        priceObjConfiguration = {
8570          description: 'Between ' + formattedLowListPrice + ' and ' + formattedHighListPrice,
8571          priceText: [
8572            {
8573              priceTextType: '',
8574              formattedPriceText: formattedLowListPrice + ' - ' + formattedHighListPrice
8575            }
8576          ]
8577        };
8578      } else if (hasRangePricing && hasDiscountPricing) {
8579        if (!hasRangeListPricing && hasRangeOfferPricing) {
8580          priceObjConfiguration = {
8581            description: 'Was ' + formattedLowListPrice + ', now between ' + formattedLowPrice + ' and ' + formattedHighPrice,
8582            priceText: [
8583              {
8584                formattedPriceText: formattedLowListPrice,
8585                priceTextType: 'original'
8586              },
8587              {
8588                formattedPriceText: formattedLowPrice + ' - ' + formattedHighPrice,
8589                priceTextType: 'discount'
8590              }
8591            ]
8592          };
8593        } else if (hasRangeListPricing && !hasRangeOfferPricing) {
8594          priceObjConfiguration = {
8595            description: 'Was between ' + formattedLowListPrice + ' and ' + formattedHighListPrice + ', now ' + formattedLowPrice,
8596            priceText: [
8597              {
8598                formattedPriceText: formattedLowListPrice + ' - ' + formattedHighListPrice,
8599                priceTextType: 'original'
8600              },
8601              {
8602                formattedPriceText: formattedLowPrice,
8603                priceTextType: 'discount'
8604              }
8605            ]
8606          };
8607        } else {
8608          priceObjConfiguration = {
8609            description:
8610							'Was between ' +
8611							formattedLowListPrice +
8612							' and ' +
8613							formattedHighListPrice +
8614							', now between ' +
8615							formattedLowPrice +
8616							' and ' +
8617							formattedHighPrice,
8618            priceText: [
8619              {
8620                formattedPriceText: formattedLowListPrice + ' - ' + formattedHighListPrice,
8621                priceTextType: 'original'
8622              },
8623              {
8624                formattedPriceText: formattedLowPrice + ' - ' + formattedHighPrice,
8625                priceTextType: 'discount'
8626              }
8627            ]
8628          };
8629        }
8630      } else if (!hasRangePricing && hasDiscountPricing) {
8631        priceObjConfiguration = {
8632          description: 'Was ' + formattedLowListPrice + ', now ' + formattedLowPrice,
8633          priceText: [
8634            {
8635              formattedPriceText: formattedLowListPrice,
8636              priceTextType: 'original'
8637            },
8638            {
8639              formattedPriceText: formattedLowPrice,
8640              priceTextType: 'discount'
8641            }
8642          ]
8643        };
8644      } else {
8645        priceObjConfiguration = {
8646          description: formattedLowListPrice, // this should be lowListPrice !!!!!
8647          priceText: [
8648            {
8649              formattedPriceText: formattedLowListPrice,
8650              priceTextType: ''
8651            }
8652          ]
8653        };
8654      }
8655
8656      product.priceObj = $.extend(priceObj, priceObjConfiguration);
8657
8658      /*
8659			display member price only if
8660		  	1. its gt 0
8661				2. lowContractPrice < lowPrice
8662        3. lowContractPrice < lowListPrice
8663      */
8664      if (
8665        ANF.params.storeAttributes.loyalty.memberPricingEnabled &&
8666				product.lowContractPrice > 0 &&
8667				product.lowContractPrice < product.lowPrice &&
8668				product.lowContractPrice < product.lowListPrice
8669      ) {
8670        product.memberPriceObj = $.extend(true, {}, getMemberPriceConfig(product));
8671      }
8672
8673      if (product && product.productAttrs && product.productAttrs.imageAutoFlip === 'true') {
8674        product.dataImageAutoFlip = 'data-image-auto-flip';
8675      }
8676    }
8677
8678    return productArray;
8679  };
8680});
8681
8682redesign.define('es6Adapter/categoryView',['exports', 'anfUtil/constants'], function categoryViewAdapter(exports, coreConstants) {
8683  'use strict';
8684
8685  var CONSTANTS = Object.create(Object.prototype, {
8686    REASONS: {
8687      value: Object.create(Object.prototype, {
8688        AJAX_OK: {
8689          value: 1,
8690          message: 'ok'
8691        },
8692        AJAX_FAIL: {
8693          value: 2,
8694          message: 'fail'
8695        },
8696        INVALID_PARAMS: {
8697          value: 3,
8698          message: 'invalid params'
8699        }
8700      })
8701    }
8702  });
8703
8704  var getApiUrl = function getApiUrl(settings) {
8705    var categoryViewApiUrl = coreConstants.anf('params.storeAttributes.categoryViewApiUrl');
8706    var catalogId = coreConstants.anf('params.storeAttributes.idList.catalogId');
8707    var catIdentifierPrefix = coreConstants.anf('params.storeAttributes.catIdentifierPrefix');
8708    return "".concat(categoryViewApiUrl + (catIdentifierPrefix + settings.commonCatId).trim(), "?catalogId=").concat(catalogId, "&responseFormat=json");
8709  };
8710
8711  var performApiRequest = function performApiRequest(settings) {
8712    var deferredObject = new $.Deferred();
8713    var ajaxSettings;
8714
8715    try {
8716      ajaxSettings = {
8717        contentType: 'application/json',
8718        dataType: 'json',
8719        type: 'GET',
8720        url: getApiUrl(settings)
8721      };
8722      $.ajax(ajaxSettings).done(function (ajaxData, ajaxTextStatus, ajaxJqXHR) {
8723        deferredObject.resolve({
8724          ajaxData: ajaxData,
8725          ajaxJqXHR: ajaxJqXHR,
8726          ajaxTextStatus: ajaxTextStatus,
8727          reason: CONSTANTS.REASONS.AJAX_OK,
8728          message: CONSTANTS.REASONS.AJAX_OK.message
8729        });
8730      }).fail(function (ajaxJqXHR, ajaxTextStatus, ajaxErrorThrown) {
8731        deferredObject.reject({
8732          ajaxErrorThrown: ajaxErrorThrown,
8733          ajaxJqXHR: ajaxJqXHR,
8734          ajaxTextStatus: ajaxTextStatus,
8735          reason: CONSTANTS.REASONS.AJAX_FAIL,
8736          message: CONSTANTS.REASONS.AJAX_FAIL.message
8737        });
8738      });
8739    } catch (_ref) {
8740      var _eMsg = _ref.message;
8741      deferredObject.reject({
8742        _eMsg: _eMsg,
8743        reason: CONSTANTS.REASONS.INVALID_PARAMS
8744      });
8745    }
8746
8747    return deferredObject.promise();
8748  };
8749
8750  exports.get = function (settings) {
8751    return performApiRequest(settings);
8752  };
8753
8754  return exports;
8755});
8756
8757function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
8758
8759function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
8760
8761function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8762
8763function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
8764
8765function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
8766
8767function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
8768
8769redesign.define('es6HomeModules/marketingProductSlider',['exports', 'globalModules/productSlider', 'coreServices/generateProductPriceObject', 'coreServices/adapter/category', 'es6Adapter/categoryView'], function marketingProductSlider(exports, productSlider, generateProductPriceObject, categoryAPIAdapter, categoryViewAPIAdapter) {
8770  'use strict';
8771
8772  var NO_CAT_ID = 'No category id found on the target node.';
8773  var CATEGORY_API_CALL_FAIL = 'Category API call failed.';
8774  var CATEGORY_VIEW_CALL_FAIL = 'Category View API call failed.';
8775  var NO_PRODUCTS = 'No product data returned from API.';
8776
8777  function getProductSliders(parent) {
8778    var allCatDrivenProductSliders = [].concat(_toConsumableArray(parent.querySelectorAll('.js-product-slider[data-categoryid]:not(.slick-initialized)')), _toConsumableArray(parent.querySelectorAll('.js-product-slider[data-cat-identifier]:not(.slick-initialized)'))).reduce(function (acum, element) {
8779      if (element.dataset.categoryid !== '' || element.dataset.catIdentifier !== '') acum.valid.add(element);
8780      if (element.dataset.categoryid === '' && element.dataset.catIdentifier === '') acum.invali
8780d.add(element);
8781      return acum;
8782    }, {
8783      valid: new Set(),
8784      invalid: new Set()
8785    });
8786
8787    if (allCatDrivenProductSliders.invalid.length) {
8788      // eslint-disable-next-line no-console
8789      allCatDrivenProductSliders.invalid.forEach(function (element) {
8790        return console.error(NO_CAT_ID, element);
8791      });
8792    }
8793
8794    return _toConsumableArray(allCatDrivenProductSliders.valid);
8795  }
8796
8797  function setSliderWaypoints(sliderTarget) {
8798    return new Waypoint({
8799      element: sliderTarget,
8800      handler: function handler() {
8801        if (typeof this.destroy === 'function') this.destroy();
8802        productSliderHandler(this.element).fail(function failure(e) {
8803          // eslint-disable-next-line no-console
8804          console.error(e, sliderTarget);
8805        });
8806      },
8807      offset: '180%'
8808    });
8809  }
8810
8811  function getCategoryId(targetNode) {
8812    var deferredObject = new $.Deferred();
8813    var commonCatId = targetNode.getAttribute('data-cat-identifier');
8814    var categoryId = '';
8815
8816    if (commonCatId) {
8817      categoryViewAPIAdapter.get({
8818        commonCatId: commonCatId
8819      }).done(function success(data) {
8820        var _data$ajaxData$Catalo, _data$ajaxData, _data$ajaxData$Catalo2, _data$ajaxData$Catalo3, _data$ajaxData$Catalo4, _categoryId;
8821
8822        categoryId = (_data$ajaxData$Catalo = data === null || data === void 0 ? void 0 : (_data$ajaxData = data.ajaxData) === null || _data$ajaxData === void 0 ? void 0 : (_data$ajaxData$Catalo2 = _data$ajaxData.CatalogGroupView) === null || _data$ajaxData$Catalo2 === void 0 ? void 0 : (_data$ajaxData$Catalo3 = _data$ajaxData$Catalo2[0]) === null || _data$ajaxData$Catalo3 === void 0 ? void 0 : (_data$ajaxData$Catalo4 = _data$ajaxData$Catalo3.uniqueID) === null || _data$ajaxData$Catalo4 === void 0 ? void 0 : _data$ajaxData$Catalo4.trim()) !== null && _data$ajaxData$Catalo !== void 0 ? _data$ajaxData$Catalo : '';
8823
8824        if ((_categoryId = categoryId) !== null && _categoryId !== void 0 && _categoryId.length) {
8825          deferredObject.resolve(categoryId);
8826        } else {
8827          deferredObject.reject(new Error(NO_CAT_ID));
8828        }
8829      }).fail(function failure() {
8830        deferredObject.reject(new Error(CATEGORY_VIEW_CALL_FAIL));
8831      });
8832    } else {
8833      var _categoryId2;
8834
8835      categoryId = targetNode.getAttribute('data-categoryId');
8836
8837      if ((_categoryId2 = categoryId) !== null && _categoryId2 !== void 0 && _categoryId2.length) {
8838        deferredObject.resolve(categoryId);
8839      } else {
8840        deferredObject.reject(new Error(NO_CAT_ID));
8841      }
8842    }
8843
8844    return deferredObject.promise();
8845  }
8846
8847  function productSliderHandler(targetNode) {
8848    var deferredObject = new $.Deferred();
8849    getCategoryId(targetNode).done(function successCatId(catId) {
8850      categoryAPIAdapter.get({
8851        categoryId: catId.trim(),
8852        rows: 50
8853      }).done(function success(data) {
8854        if (!(targetNode.classList.contains('.slick-initialized') && !targetNode.querySelector('.slick-initialized'))) {
8855          var _data$ajaxData$produc, _data$ajaxData2;
8856
8857          var productArray = (_data$ajaxData$produc = data === null || data === void 0 ? void 0 : (_data$ajaxData2 = data.ajaxData) === null || _data$ajaxData2 === void 0 ? void 0 : _data$ajaxData2.products) !== null && _data$ajaxData$produc !== void 0 ? _data$ajaxData$produc : [];
8858
8859          if (productArray.length === 0) {
8860            deferredObject.reject(new Error(NO_PRODUCTS));
8861            return;
8862          }
8863
8864          productArray = generateProductPriceObject(productArray);
8865
8866          try {
8867            productSlider.init(productArray, targetNode, {
8868              image: 'model1'
8869            });
8870          } catch (ignore) {// do nothing, the throws will handle any errors
8871          } finally {
8872            deferredObject.resolve();
8873          }
8874        }
8875      }).fail(function fail() {
8876        deferredObject.reject(new Error(CATEGORY_API_CALL_FAIL));
8877      });
8878    }).fail(function fail(e) {
8879      deferredObject.reject(e);
8880    });
8881    return deferredObject.promise();
8882  }
8883
8884  exports.init = function () {
8885    var parent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;
8886    getProductSliders(parent).forEach(setSliderWaypoints);
8887  };
8888
8889  return exports;
8890});
8891
8892redesign.define('productPartial/pdp_fitTypeAndDescription',['handlebars'], function(Handlebars) {
8893
8894this["ANF"] = this["ANF"] || {};
8895this["ANF"]["templates"] = this["ANF"]["templates"] || {};
8896
8897Handlebars.registerPartial("pdp_fitTypeAndDescription", this["ANF"]["templates"]["pdp_fitTypeAndDescription"] = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
8898    var alias1=container.lambda, alias2=container.escapeExpression;
8899
8900  return "<div>\n    <h3 class=\"product-attrs__shown-in\">\n        <strong>\n            "
8901    + alias2(alias1((depth0 != null ? depth0.fitTMNT : depth0), depth0))
8902    + ":\n        </strong>
8902\n        <span class=\"selected-swatch__label\">\n            "
8903    + alias2(alias1((depth0 != null ? depth0.fitType : depth0), depth0))
8904    + "\n        </span>\n    </h3>\n    <p> "
8905    + alias2(alias1((depth0 != null ? depth0.fitDescription : depth0), depth0))
8906    + " </p>\n</div>\n";
8907},"useData":true}));
8908
8909return this["ANF"];
8910
8911});
8912redesign.define('productModules/product/buyGridAccordions/productSizeFitAccordion',[
8913  'productModules/helpers/Utils',
8914  'productServices/product/productReviewService',
8915  'anfcore/components/tooltip',
8916  'productModules/helpers/garmentMeasurements',
8917  'productPartial/pdp_sizeFitAccordionContent',
8918  'productPartial/pdp_fitRecommendation',
8919  'productPartial/pdp_modelSpecs',
8920  'globalServices/marketing/eSpotContentProvider',
8921  'anfcore/components/modal',
8922  'coreServices/personalizedContent',
8923  'anfUtil/constants',
8924  'anfUtil/testFramework',
8925  'coreServices/userPreference',
8926  'es6HomeModules/marketingProductSlider',
8927  'productPartial/pdp_fitTypeAndDescription',
8928  'globalModulesHelpers/debounce',
8929  'productPartial/pdp_measurements'
8930],
8931function ProductSizeFitAccordion(
8932  Utils,
8933  reviewService,
8934  dsTooltip,
8935  garmentMeasurements,
8936  productPartialPdpSizeFitAccordionContent,
8937  productPartialPdpFitRecommendation,
8938  productPartialPdpModelSpecs,
8939  eSpotContentProvider,
8940  modal,
8941  personalizedContentAPI,
8942  coreConstants,
8943  test,
8944  userPreferenceHelper,
8945  marketingProductSlider,
8946  productPartialPdpFitTypeAndDescription,
8947  debounceService,
8948  productPartialLensMeasurementsAccordionContent
8949) {
8950  'use strict';
8951
8952  var messageBus = $(ANF);
8953
8954  function reformSizeFitAccordion($productSection) {
8955    var anfObject = Utils.getANFObject();
8956    var productId = $productSection.data('productid');
8957    var productData = Utils.getProductData(productId);
8958    var collection = productData.collection;
8959    var sizeFitInformation = $productSection.find('.size-fit-information');
8960
8961    var accordionData = {};
8962    var measurementData = Utils.isEyewearProduct(productData.productAttrs) ?
8963      garmentMeasurements.getEyewearMeasurementData(productId, anfObject) :
8964      garmentMeasurements.getGarmentMeasurementData(productId, anfObject, $productSection);
8965
8966    if (measurementData && measurementData.isEyeware) {
8967      renderMeasurementsAccordion(measurementData, $productSection);
8968    } else {
8969      accordionData.garmentData = measurementData;
8970      accordionData.hasGarmentMeasurements = accordionData.garmentData.measurements.length > 0 && !Utils.isJeansProduct(productId);
8971
8972      accordionData.isQuickviewOpened = Utils.isQuickviewOpened;
8973      accordionData.fitRecommendation = getFitRecommendation(anfObject, collection);
8974      accordionData.hasFitRecommendation = !!accordionData.fitRecommendation;
8975      accordionData.hasModelSpecs =  hasModelSpecs(productData);
8976      if (hasModelSpecs(productData)) {
8977        accordionData.modelSpecs = Utils.getModelSpecs(productId);
8978      }
8979
8980      if ($productSection.hasClass('size-fit-desc-enabled')) {
8981        var fitTypes = productData.productAttrsComplex['Details-6233'];
8982        if (fitTypes && fitTypes.values) {
8983          var fitDetails = fitTypes.values.reduce(function getFitDetails(previous, current) {
8984            if (current.value === 'Curvy' || current.value === 'Classic' || current.value === 'Curvy Love') {
8985              return current.value;
8986            }
8987            return previous;
8988          }, '');
8989          var fitTypeTmntMapping = {
8990            'Curvy': 'PDP_CURVE_FIT',
8991            'Curvy Love': 'PDP_CURVE_FIT',
8992            'Classic': 'PDP_CLASSIC_FIT'
8993          };
8994          if (fitDetails) {
8995            accordionData.fitType = fitDetails;
8996            accordionData.fitHeaderTMNT = ANF.messaging.product[fitTypeTmntMapping[fitDetails]];
8997            accordionData.fitDescription = productData.productAttrs.FitDescription;
8998            accordionData.fitTMNT = ANF.messaging.product.PDP_FIT;
8999            sizeFitInformation.html(productPartialPdpFitTypeAndDescription.templates.pdp_fitTypeAndDescription(accordionData));
9000          }
9001        }
9002        accordionData.riseTMNT = ANF.messaging.product.PDP_RISE_FIT;
9003        accordionData.lengthTMNT = ANF.messaging.product.PDP_LENGTH_FIT;
9004        accordionData.bottomRiseCode = productData.productAttrs.BottomsRiseCode;
9005        accordionData.bottomLengthCode = productData.productAttrs.BottomsLengthCode;
9006        accordionData.style = productData.productAttrs.Style;
9007        accordionData.styleDescription = productData.productAttrs.StyleDescription;
9008        accordionData.hasCurvyOrClassicFit = accordionData.fitType || accordionData.fitDescription || accordionData.bottoms
9008RiseCode || accordionData.bottomsLengthCode || accordionData.style;
9009        if (accordionData.hasCurvyOrClassicFit) {
9010          var sizeFitAccordion = $productSection.find('.size-fit__accordion');
9011          sizeFitAccordion.find('button').attr('aria-expanded', 'true');
9012          sizeFitAccordion.find('.js-accordion-panel').attr('aria-hidden', false).css('max-height', 'max-content');
9013        }
9014      }
9015      var debounceInstance = debounceService.debounce(makeCompareFitLink, 500);
9016      debounceInstance(collection, productId);
9017    }
9018
9019    function makeCompareFitLink(collectionDetails, productIdDetails) {
9020      getCompareFitTemplate(collectionDetails, productIdDetails, accordionData, $productSection).done(function _updateSizeFitAccordion() {
9021        accordionData.hasFitInfo = accordionData.hasFitRecommendation || accordionData.hasModelSpecs || accordionData.compareFitLinkEspot || accordionData.hasCurvyOrClassicFit;
9022        var linkText = '<a href="#rating-and-reviews"> ' + accordionData.fitRecommendation + '</a>';
9023
9024        if (accordionData.isQuickviewOpened) {
9025          accordionData.contextualFitFullTMNT = ANF.messaging.product.PDP_NEW_MOST_RECOMMEND.replace('{0}', accordionData.fitRecommendation);
9026        } else {
9027          accordionData.contextualFitFullTMNT = ANF.messaging.product.PDP_NEW_MOST_RECOMMEND.replace('{0}', linkText);
9028        }
9029
9030        accordionData.displayHR = accordionData.hasFitInfo && accordionData.hasGarmentMeasurements;
9031        updateSizeFitAccordionDisplay(accordionData, $productSection);
9032        modal.default().init();
9033        $productSection
9034          .has('.size-fit__accordion .js-product-slider')
9035          .each(function applyMarketingProductSlider(index, element) {
9036            marketingProductSlider.init(element);
9037          });
9038      });
9039    }
9040  }
9041
9042  function updateSizeFitAccordion(e, $selectedSwatch, $productSection) {
9043    reformSizeFitAccordion($productSection);
9044  }
9045
9046  function getContentAPISettings() {
9047    return {
9048      stylesInResponse: false,
9049      locale: coreConstants.anf('params.storeAttributes.api.aem').locale,
9050      singleResponse: true,
9051      dataType: 'json',
9052      adapterSettings: {
9053        aemTimeout: coreConstants.anf('params.storeAttributes.api.aem').timeout.apiBin,
9054        aemHTMLTimeout: coreConstants.anf('params.storeAttributes.api.aem').timeout.content,
9055        isSingleResponse: true
9056      }
9057    };
9058  }
9059
9060  function getISODate(value) {
9061    try {
9062      return new Date(value).toISOString();
9063    } catch (e) {
9064      return null;
9065    }
9066  }
9067
9068  function getRequestParams() {
9069    var isStorePreview = coreConstants.anf('params.storeAttributes.api.aem.isStorePreview');
9070    var espotContentSettings = getContentAPISettings();
9071    var hasSiteExperienceByShipToCountry = coreConstants.anf('params.storeAttributes.userPreference.siteExperience');
9072    var uPrefCookieValue = userPreferenceHelper.read({cookieName: 'uPref'});
9073    var countryParams;
9074
9075    if (isStorePreview) {
9076      $.extend(true, espotContentSettings, getStorePreviewParams());
9077    }
9078
9079    if (hasSiteExperienceByShipToCountry) {
9080      if (test.string.not.empty(coreConstants.anf('params.storeAttributes.countryFromIP'))) {
9081        countryParams = {
9082          countryCode: coreConstants.anf('params.storeAttributes.countryFromIP')
9083        };
9084      } else if (test.object.containsKey(uPrefCookieValue, 'shipTo', false)) {
9085        countryParams = {
9086          countryCode: uPrefCookieValue.shipTo
9087        };
9088      } else {
9089        countryParams = {
9090          countryCode: 'US'
9091        };
9092      }
9093      espotContentSettings.countryCode = countryParams.countryCode;
9094    }
9095
9096    return espotContentSettings;
9097  }
9098
9099  function getStorePreviewParams() {
9100    var storePreviewParams = null;
9101    var previewFrameWrapper = parent.document.getElementById('previewFrameWrapper');
9102
9103    if (previewFrameWrapper && previewFrameWrapper.dataset) {
9104      storePreviewParams = {
9105        previewStart: getISODate(previewFrameWrapper.dataset.start),
9106        previewMode: true
9107      };
9108    }
9109    return storePreviewParams;
9110  }
9111
9112  function getCompareFitAEMContent(collection, settings, accordionData, $productSection) {
9113    var response = new $.Deferred();
9114    var compareFitLinkEspotName = 'pdp_sizefitaccordion';
9115    var compareFitLinkEspot = '';
9116
9117    personalizedContentAPI.get(settings)
9118      .done(function _successFunction(results) {
9119        if (results.reason === personalizedContentAPI.reasons.AJAX_OK) {
9120          results.data.forEach(function getCompareFitsAccordion(espotContent) {
9121            if (test.object.containsKey(espotContent, 'espotId', false) && espotContent.espotId === compareFitLinkEspotName) {
9122              espotContent.pages.forEach(function concatContent(page) {
9123                compareFitLinkEspot += page.htmlContent;
9124              });
9125            }
9126          });
9127        }
9128        ANF.product.data[collection].compareOurFitContent += compareFitLinkEspot;
9129        ANF.product.data[collection].hasFetchedCompareOurFitContent = true;
9130
9131        response.resolve(compareFitLinkEspot);
9132        Object.assign(accordionData, {compareFitLinkEspot: compareFitLinkEspot});
9133        updateSizeFitAccordionDisplay(accordionData, $productSection);
9134      })
9135      .fail(function _failFunction() {
9136        response.reject();
9137      });
9138
9139    return response.promise();
9140  }
9141
9142  function getCompareFitCMCContent(collection, productId) {
9143    var response = new $.Deferred();
9144    var compareFitLinkEspot = '';
9145    var espotSettings = [{
9146      key: 'productId',
9147      value: productId
9148    }, {
9149      key: 'page',
9150      value: 'ProductDisplay'
9151    }];
9152    eSpotContentProvider.fetch(['Product_CompareFitLink'], espotSettings).done(function _successFunction(content) {
9153      if (content[0]) {
9154        for (var i = 0; i < content[0].content.length; i++) {
9155          compareFitLinkEspot += content[0].content[i].text;
9156        }
9157      }
9158      ANF.product.data[collection].compareOurFitContent = compareFitLinkEspot;
9159      ANF.product.data[collection].hasFetchedCompareOurFitContent = true;
9160      response.resolve(compareFitLinkEspot);
9161    }).fail(function _failFunction() {
9162      response.resolve('');
9163    });
9164
9165    return response.promise();
9166  }
9167
9168  function getEspotIds(productId) {
9169    return [productCatalog[productId].productPartNum, 'ALL_KIC_ALL_CTGY', coreConstants.anf('catalog.data.espotIdentifier')];
9170  }
9171
9172  function getCompareFitTemplate(collection, productId, accordionData, $productSection) {
9173    var response = new $.Deferred();
9174    var compareFitLinkEspot = '';
9175    var settings;
9176    var espots;
9177    if (ANF.product.data[collection].hasFetchedCompareOurFitContent) {
9178      compareFitLinkEspot = ANF.product.data[collection].compareOurFitContent;
9179      response.resolve(compareFitLinkEspot);
9180    } else if (window.digitalData.get('flag.aemCompareFits', false)) {
9181      espots = getEspotIds(productId);
9182      settings = getRequestParams();
9183      ANF.product.data[collection].compareOurFitContent = '';
9184      $.when.apply($, espots.map(function fetchESpotContent(espotId) {
9185        settings.pageId = espotId;
9186        return getCompareFitAEMContent(collection, settings, accordionData, $productSection);
9187      })).always(function getAllEspotContent() {
9188        response.resolve(ANF.product.data[collection].compareOurFitContent);
9189      });
9190    } else {
9191      return getCompareFitCMCContent(collection, productId);
9192    }
9193
9194    return response.promise();
9195  }
9196
9197  function getFitRecommendation(anfObject, collection) {
9198    var reviewData = {};
9199    var review = anfObject.product.data[collection] && anfObject.product.data[collection].reviews;
9200    var fitRecommendation;
9201
9202    if (review) {
9203      reviewData = reviewService.buildReviewSummaryModel(review);
9204    }
9205
9206    if (reviewData && reviewData.showFitRecommendation && reviewData.fitRecommendation) {
9207      fitRecommendation = reviewData.fitRecommendation;
9208    }
9209
9210    return fitRecommendation;
9211  }
9212
9213  function hasModelSpecs(productData) {
9214    var productAttrs = productData.productAttrs;
9215    return (productAttrs.OFPModelHeight && productAttrs.OFPModelSize);
9216  }
9217
9218  function updateSizeFitAccordionDisplay(accordionData, $productSection) {
9219    var $sizeFitAccordion = $productSection.find('.size-fit__accordion');
9220    var $accordionContainer = $sizeFitAccordion.find('.size-fit-accordion__container');
9221
9222    if (accordionData.fitRecommendation) {
9223      var $productSizeSectionContainer = $productSection.find('.product-size-section__container');
9224      $productSizeSectionContainer.html(productPartialPdpFitRecommendation.templates.pdp_fitRecommendation(accordionData));
9225    }
9226
9227    // hide and exit if shouldShowSizeFitAccordion == false
9228    if (!shouldShowSizeFitAccordion(accordionData)) {
9229      $sizeFitAccordion.hide();
9230      return;
9231    }
9232    $accordionContainer.html(productPartialPdpSizeFitAccordionContent.templates.pdp_sizeFitAccordionContent(accordionData));
9233    $sizeFitAccordion.show();
9234
9235    // Accordion calcs a height on open, this fixes the height issue of updating content within that already open accordion
9236    $productSection.find('.size-fit__accordion .js-accordion-panel').css('max-height', '');
9237
9238    if (accordionData.hasGarmentMeasurements) {
9239      // re-init the tooltips since they are injected post load
9240      dsTooltip.default().init();
9241    }
9242  }
9243
9244  function shouldShowSizeFitAccordion(accordionData) {
9245    return accordionData.hasGarmentMeasurements ||
9246      accordionData.hasFitInfo;
9247  }
9248
9249  function onModelChanged(e, eventData) {
9250    var modelSpecs = Utils.getModelSpecs(eventData.productId);
9251    var $container = eventData.$productSection.find('.model-specs-container');
9252    $container.html(productPartialPdpModelSpecs.templates.pdp_modelSpecs(modelSpecs));
9253  }
9254
9255  function triggerBTest() {
9256    var $productSection = $('.product-page-v2-modules').not('.quickview-preload');
9257    $productSection.addClass('size-fit-desc-enabled');
9258    var productSection = $productSection;
9259    if ($productSection.length > 1) {
9260      productSection = $productSection.not('.js-product-page');
9261    }
9262    reformSizeFitAccordion(productSection);
9263  }
9264
9265  function renderMeasurementsAccordion(measurementData, $productSection) {
9266    var $measurementsAccordion = $productSection.find('.measurements__accordion');
9267    var $measurementsAccordionContainer = $measurementsAccordion.find('.measurements-accordion__container');
9268
9269    if (!measurementData && !measurementData.isEyeware) {
9270      $measurementsAccordion.hide();
9271      return;
9272    }
9273    $measurementsAccordion.show();
9274    $measurementsAccordionContainer.html(productPartialLensMeasurementsAccordionContent.templates.pdp_measurements(measurementData));
9275
9276    dsTooltip.default().init();
9277  }
9278
9279  var publicMembers = {
9280    listen: function listen() {
9281      messageBus.on('productPageInfo:swatchOnLoad productPageInfo:swatchSelected', updateSizeFitAccordion);
9282      messageBus.on('productPageMainImages:modelSelected', onModelChanged);
9283      messageBus.on('styleFitDesc:init', triggerBTest);
9284    }
9285  };
9286
9287  return publicMembers;
9288});
9289
9290redesign.define('productModules/product/sizeGuide/sizeGuideCharts',[
9291  'globalModulesHelpers/debounce',
9292  'productModules/helpers/curry',
9293  'productServices/product/template'
9294], function SizeGuideCharts(debounce, curry, template) {
9295  'use strict';
9296
9297  var sizeGuideTableScrollSelector = '.size-guide__table-scroll';
9298  var sizeGuideTableSelector = '.size-guide__guide';
9299  var hideShadowClass = 'size-guide__table-shadow--hide';
9300  var dropShadowLeftSelector = '.size-guide__table-shadow-left';
9301  var dropShadowRightSelector = '.size-guide__table-shadow-right';
9302  var sizeGuidePrimarySelector = '.size-guide__primary-column';
9303  var sizeGuideTableRegionSelector = '.size-guide__country-column';
9304  var sizeGuideShowInchesClass = 'size-guide__show-inches';
9305  var sizeGuideShowCentimeterClass = 'size-guide__show-cm';
9306  var selectedClass = 'selected';
9307
9308  function renderSizeCharts($container, constants, sizeChartData, defaultRegion) {
9309    var defaultUnitClass = defaultRegion === 'usa' ? sizeGuideShowInchesClass : sizeGuideShowCentimeterClass;
9310
9311    var tables = template.renderTemplate('sizeGuideCharts', {
9312      sizeCharts: sizeChartData,
9313      defaultUnitClass: defaultUnitClass,
9314      defaultRegion: defaultRegion,
9315      sizeChartHeader: constants.sizeChartHeader
9316    });
9317
9318    $container.html(tables);
9319
9320    // curry this with an extra argument so debounce calls it with zero args and the container as context
9321    var curriedRenderShadows = curry(renderTableScrollShadows, 2)($container);
9322    var debounced = debounce.debounce(curriedRenderShadows, 250);
9323    $container.find(sizeGuideTableScrollSelector).on('scroll', debounced);
9324  }
9325
9326  function renderTableScrollShadows($container) {
9327    $container.find(sizeGuideTableScrollSelector).each(function setScrollShadows(_idx, tableScroll) {
9328      var maxScrollLeft = tableScroll.scrollWidth - tableScroll.clientWidth;
9329
9330      // only when has scrolling
9331      if (tableScroll.scrollWidth > 375 && maxScrollLeft !== 0) {
9332        var $currentTableScroll = $(tableScroll);
9333        var $dropShadowLeft = $currentTableScroll.find(dropShadowLeftSelector);
9334        var $dropShadowRight = $currentTableScroll.find(dropShadowRightSelector);
9335
9336        var hideLeftShadow = tableScroll.scrollLeft === 0;
9337        var hideRightShadow = tableScroll.scrollLeft === maxScrollLeft;
9338
9339        // account for width of first column
9340        var $leftHeaders = $currentTableScroll.find(sizeGuidePrimarySelector);
9341        $dropShadowLeft.css('left', $leftHeaders[0].clientWidth);
9342
9343        $dropShadowLeft.toggleClass(hideShadowClass, hideLeftShadow);
9344        $dropShadowRight.toggleClass(hideShadowClass, hideRightShadow);
9345      }
9346    });
9347  }
9348
9349  function toggleTableUnit($container, unit) {
9350    var $table = $container.find(sizeGuideTableSelector);
9351
9352    switch (unit) {
9353      case 'inches':
9354        $table
9355          .removeClass(sizeGuideShowCentimeterClass)
9356          .addClass(sizeGuideShowInchesClass);
9357        break;
9358      case 'centimeters':
9359        $table
9360          .removeClass(sizeGuideShowInchesClass)
9361          .addClass(sizeGuideShowCentimeterClass);
9362        break;
9363      default:
9364        $table
9365          .removeClass(sizeGuideShowCentimeterClass)
9366          .addClass(sizeGuideShowInchesClass);
9367    }
9368
9369    renderTableScrollShadows($container);
9370  }
9371
9372  function changeTableRegion($container, region, unit) {
9373    var $regionColumns = $container.find(sizeGuideTableRegionSelector);
9374    var regionSelectedClass = '.size-guide__country-' + region;
9375
9376    $regionColumns
9377      .removeClass(selectedClass)
9378      .filter(regionSelectedClass)
9379      .addClass(selectedClass);
9380
9381    toggleTableUnit($container, unit);
9382  }
9383
9384  function addAltBackgroundFlag(sizeChartData) {
9385    var enrichedSizeChartData = $.extend({}, sizeChartData);
9386
9387    $.each(sizeChartData, function sizeChartLoop(e, chart) {
9388      $.each(chart.sizes, function altColoringCalculation(i) {
9389        if (i % 2) {
9390          enrichedSizeChartData[e].sizes[i].hasAltBackground = true;
9391        }
9392      });
9393    });
9394
9395    return enrichedSizeChartData;
9396  }
9397
9398  function init($container, constants, sizeChartData) {
9399    var region = constants.sizeGuideDefaultRegion.toLowerCase();
9400
9401    var enrichedSizeChartData = addAltBackgroundFlag(sizeChartData);
9402    renderSizeCharts($container, constants, enrichedSizeChartData, region);
9403  }
9404
9405  var publicMembers = {
9406    init: init,
9407    changeTableRegion: changeTableRegion,
9408    toggleTableUnit: toggleTableUnit
9409  };
9410
9411  return publicMembers;
9412});
9413
9414redesign.define('productModules/product/sizeGuide/sizeGuideChartControls',[
9415  'productServices/product/template',
9416  'productModules/helpers/Utils',
9417  'productModules/product/sizeGuide/sizeGuideCharts'
9418], function SizeGuideChartControls(template, Utils, SizeGuideCharts) {
9419  'use strict';
9420
9421  var sizeGuideParentSelector = '.size-guide';
9422  var sizeGuideRegionSelector = '.size-guide-region-selector select';
9423  var sizeGuideRegionDropDownSelector = '.size-guide__region-selector';
9424  var unitTabContainerSelector = '.size-guide__unit-toggle-wrapper .toggle-radio';
9425  var sizeGuideUnitToggleWrapperSelector = '.size-guide__unit-toggle-wrapper';
9426
9427  // Treat this as immutable -- once data for a productId is set on init, it should not be modified
9428  var regionsByProductId = {};
9429
9430  function bindEvents() {
9431    $(document).on('change', unitTabContainerSelector, handleUnitToggleChange);
9432    $(document).on('change', sizeGuideRegionSelector, handleRegionChange);
9433  }
9434
9435  function qvModifier() {
9436    return Utils.isQuickviewOpened ? '_qv' : '';
9437  }
9438
9439  function handleUnitToggleChange(event) {
9440    var $target = $(event.currentTarget);
9441    var unitClicked = $target.val();
9442    var $sizeGuideWrapper = $target.closest(sizeGuideParentSelector);
9443
9444    SizeGuideCharts.toggleTableUnit($sizeGuideWrapper, unitClicked);
9445  }
9446
9447  function handleRegionChange(event) {
9448    var $selectedRegion = $(event.target);
9449
9450    var region = $selectedRegion.val();
9451    var unit = region.toLowerCase() === 'usa' ? 'inches' : 'centimeters';
9452
9453    var $regionSelectorDropDown = $selectedRegion.closest(sizeGuideRegionDropDownSelector);
9454    var $unitToggle = $regionSelectorDropDown.siblings(sizeGuideUnitToggleWrapperSelector);
9455    var $sizeGuideWrapper = $regionSelectorDropDown.closest(sizeGuideParentSelector);
9456
9457    $unitToggle.find('input[value="' + unit + '"]').prop('checked', true);
9458
9459    SizeGuideCharts.changeTableRegion($sizeGuideWrapper, region, unit);
9460  }
9461
9462  // This is mostly a single use func, parses a messy size guide json response and gets the available regions
9463  function findAvailableRegions(data, constants) {
9464    // Gotta flatten out all these nested arrays so we can reduce them
9465    var types = data.reduce(function getSizes(acc, table) {
9466      return table.sizes.reduce(function getTypes(_callback, size) {
9467        return acc.concat(size.types);
9468      }, []);
9469    }, []);
9470
9471    // Reduce down using an object to merge duplicates
9472    var regions = types.reduce(function mergeCountryProps(acc, type) {
9473      if (type.country !== '') {
9474        acc[type.country] = true;
9475      }
9476
9477      return acc;
9478    }, {});
9479
9480    // add default region
9481    regions[constants.sizeGuideDefaultRegion] = true;
9482
9483    return Object.keys(regions);
9484  }
9485
9486  function buildRegionSelectorTemplateModel(productId, regions, constants) {
9487    var options = regions.map(function formatRegionForTemplate(region) {
9488      return {
9489        title: region,
9490        value: region
9491      };
9492    });
9493
9494    return {
9495      id: 'size-guide-region-selector-' + productId + qvModifier(),
9496      productId: productId,
9497      productBrand: Utils.getProductData(productId).productAttrs.brand,
9498      classList: 'size-guide-region-selector',
9499      label: constants.sizeGuideRegionSelectorAriaLabel,
9500      value: constants.sizeGuideDefaultRegion,
9501      dataProperty: 'SIZE_GUIDE_REGION_LIST_ARIA_LABEL',
9502      options: options
9503    };
9504  }
9505
9506  function buildUnitToggleTemplateModel(productId, constants) {
9507    var defaultInches = constants.sizeGuideDefaultRegion.toLowerCase() === 'usa';
9508
9509    return {
9510      productId: productId,
9511      productBrand: Utils.getProductData(productId).productAttrs.brand,
9512      classList: 'size-guide__unit-toggle',
9513      name: 'size-guide-toggle-' + productId + qvModifier(),
9514      toggleLabel: constants.tmntSizeGuideUnitToggleLabel,
9515      toggleBlock: [
9516        {
9517          'value': 'inches',
9518          'toggle-text': constants.tmntSizeGuideInch,
9519          'id': 'size-guide__toggle-inch-' + productId + qvModifier(),
9520          'checked': defaultInches
9521        },
9522        {
9523          'value': 'centimeters',
9524          'toggle-text': constants.tmntSizeGuideCm,
9525          'id': 'size-guide__toggle-cm-' + productId + qvModifier(),
9526          'checked': !defaultInches
9527        }
9528      ]
9529    };
9530  }
9531
9532  function renderChartControls($container, constants, productId, regions) {
9533    var unitToggle = template.renderTemplate('sizeGuideUnitToggle', buildUnitToggleTemplateModel(productId, constants));
9534    var regionSelector = template.renderTemplate('sizeGuideRegionSelector', buildRegionSelectorTemplateModel(productId, regions, constants));
9535
9536    $container.html([regionSelector, unitToggle]);
9537  }
9538
9539  function init($container, constants, productId, data) {
9540    if (!!data) {
9541      regionsByProductId[productId] = findAvailableRegions(data[productId], constants);
9542    }
9543
9544    renderChartControls($container, constants, productId, regionsByProductId[productId]);
9545  }
9546
9547
9548  var publicMembers = {
9549    init: init,
9550    bindEvents: bindEvents
9551  };
9552
9553  return publicMembers;
9554});
9555
9556redesign.define('productModules/product/sizeGuide/productSizeGuide',[
9557  'productModules/helpers/Utils',
9558  'productModules/product/sizeGuide/sizeGuideChartControls',
9559  'productModules/product/sizeGuide/sizeGuideCharts',
9560  'anfcore/components/tabs',
9561  'anfcore/components/modal',
9562  'anfcore/helpers/scope'
9563], function ProductSizeGuide(
9564  Utils,
9565  SizeGuideChartControls,
9566  SizeGuideCharts,
9567  tabs,
9568  modal,
9569  scope
9570) {
9571  'use strict';
9572
9573  var sizeGuideLinkSelector = '.details__link-size-chart, .product-page__info-size-chart, .size-fit__accordion .view-size-fit-btn';
9574  var sizeGuideTableContainerSelector = '.size-guide__guide-wrapper';
9575  var sizeGuideControlsContainerSelector = '.size-guide__cta-wrapper';
9576
9577  var sizeChartsData = {};
9578
9579  // have to bind utils here bc utils.getvalue uses 'this'
9580  var getInANF = Utils.getValueFromObject.bind(Utils, ANF);
9581
9582  var constants = {
9583    apiURLRoot: getInANF('params.storeAttributes.apiURLRoot', ''),
9584    sizeGuideDefaultRegion: getInANF('params.storeAttributes.catalogV2.sizeGuideDefaultRegion', ''),
9585    sizeGuideRegionSelectorAriaLabel: getInANF('messaging.product.TMNT.SIZE_GUIDE_REGION_SELECTOR_ARIA_LABEL.value', ''),
9586    tmntSizeChartHeader: getInANF('messaging.product.TMNT.SIZE_CHART_HEADER.value', ''),
9587    tmntSizeGuideUnitToggleLabel: getInANF('messaging.product.TMNT.SIZE_GUIDE_UNIT_TOGGLE_LABEL.value', ''),
9588    tmntSizeGuideInch: getInANF('messaging.product.TMNT.SIZE_GUIDE_INCH.value', ''),
9589    tmntSizeGuideCm: getInANF('messaging.product.TMNT.SIZE_GUIDE_CM.value', '')
9590  };
9591
9592  function sizeGuideClickHandler(event) {
9593    // keep the event executed only on the <button></button>
9594    event.stopPropagation();
9595
9596    var $currentTarget = $(event.currentTarget);
9597    var $productSection = $currentTarget.closest('.product-page-v2-modules');
9598    var productId = $productSection.data('productid');
9599
9600    var sizeChartName = Utils.getProductData(productId).sizeChartName;
9601
9602    var $tableContainer = $productSection.find(sizeGuideTableContainerSelector);
9603    var $controlsContainer = $productSection.find(sizeGuideControlsContainerSelector);
9604
9605    if (!sizeChartsData[productId] || !sizeChartsData[productId].length) {
9606      $.get(ANF.params.storeAttributes.apiURLRoot + '/product/sizeguide/' + sizeChartName)
9607        .done(function handleSizeChartData(data) {
9608          sizeChartsData[productId] = data.sizeguides[0].sizecharts;
9609
9610          SizeGuideCharts.init($tableContainer, constants, sizeChartsData[productId]);
9611          SizeGuideChartControls.init($controlsContainer, constants, productId, sizeChartsData);
9612        });
9613    } else {
9614      SizeGuideCharts.init($tableContainer, constants, sizeChartsData[productId]);
9615      SizeGuideChartControls.init($controlsContainer, constants, productId);
9616    }
9617
9618    // With the size guide now in QV the ds components we init on page load need to be re-inited() so that the beautiful tabbies work
9619    // below I set the scope to '.scope-1892' because the scope is being set too small on other pages on the site
9620    // Since PDP (Qv, Edit) is pretty much on every page we have to make sure the components init properly.
9621    if (Utils.isQuickviewOpened) {
9622      scope.default.setScope('.scope-1892');
9623      tabs.default().init();
9624    }
9625    modal.default().init();
9626  }
9627
9628  var publicMembers = {
9629    bindEvents: function bindEvents() {
9630      $(document).on('click', sizeGuideLinkSelector, sizeGuideClickHandler);
9631    }
9632  };
9633
9634  return publicMembers;
9635});
9636
9637redesign.define('productModules/product/sizeGuide/sizeGuideHeader',[
9638  'productModules/helpers/Utils',
9639  'coreModulesHelpers/StringUtils',
9640  'productServices/product/template',
9641  'coreClass/ANFImage',
9642  'productModules/helpers/garmentMeasurements',
9643  'anfcore/components/tooltip'
9644], function SizeGuideHeader(Utils, StringUtils, template, ANFImage, garmentMeasurements, dsTooltip) {
9645  'use strict';
9646
9647  var productSectionSelector = '.product-page-v2-modules';
9648  var infoPanelSelector = '.size-guide-info-panel';
9649
9650  var sizeGuideRecommendedFitSelector = '.size-guide-info-panel .size-guide-fit-most-reviewers-say';
9651  var reviewRecommendedFitSelector = '.size-fit-accordion__container .size-fit-reviewer-recommendation';
9652  var detailsHeightSelector = '.model-specs__height-measurement';
9653  var detailsSizeSelector = '.model-specs__size-measurement';
9654  var sizeGuideImagesSelector = '.size-guide-info-panel .size-guide-images';
9655  var garmentMeasurementsSelector = '.garment-measurements';
9656
9657  function gatherImagesToDisplay(selectedModel, imageObject) {
9658    var imagesToDisplay = [];
9659    if (selectedModel.length >= 3) {
9660      imagesToDisplay.push(selectedModel[0], selectedModel[2]);
9661    } else if (selectedModel.length >= 1 && imageObject.prod.length >= 1) {
9662      imagesToDisplay.push(selectedModel[0], imageObject.prod[0]);
9663    } else {
9664      imagesToDisplay.push(imageObject.prod[0]);
9665    }
9666
9667    return imagesToDisplay;
9668  }
9669
9670  function imageBannerErrorHandler(e) {
9671    var $failedImage = $(e.target);
9672    var hasFixedErrorBefore = $failedImage.closest('.image-fail-fix').length > 0;
9673
9674    if (hasFixedErrorBefore) {
9675      $failedImage.parent().remove();
9676    } else {
9677      var imageIdParts = $failedImage.data('image-id').split('_');
9678
9679      // hard coding the prod1 image type here, since Image data is stale/broken at this point
9680      var imageId = imageIdParts[0] + '_' + imageIdParts[1] + '_prod1';
9681
9682      var fallbackSrc = ANFImage.instance()
9683        .setImageName(imageId)
9684        .setWidth(800)
9685        .url;
9686
9687      $failedImage.attr('src', fallbackSrc);
9688
9689      $failedImage.closest('.size-guide-images').addClass('image-fail-fix');
9690    }
9691  }
9692
9693  var publicMembers = {
9694    bindEvents: function bindEvents() {
9695      $(document).on('dsModal:Open', '[class*="details__size-guide-modal"]', publicMembers.handleSizeGuideOpen);
9696    },
9697
9698    handleSizeGuideOpen: function handleSizeGuideOpen(event) {
9699      var $productSection = $(event.currentTarget).closest(productSectionSelector);
9700      var $infoPanel = $productSection.find(infoPanelSelector);
9701      var productId = $productSection.data('productid');
9702
9703      publicMembers.setSizeGuideFitRecommendation($productSection);
9704      publicMembers.sizeGuideImageHandler($productSection, productId);
9705      publicMembers.setSizeGuideInfoPanel($infoPanel, productId);
9706      publicMembers.setGarmentMeasurements(productId, $productSection, $infoPanel);
9707      dsTooltip.default().init();
9708    },
9709
9710    setSizeGuideInfoPanel: function setSizeGuideInfoPanel($infoPanel, productId) {
9711      var productData = Utils.getProductData(productId);
9712      // Related with from product/base/js/modules/product/productDetails.js
9713      var defaultModelStr = window.selectedModelSegment || Utils.getValueFromObject(productData, 'productAttrs.ModelData.defaultModel', null);
9714      var selectedModel = defaultModelStr && productData.productAttrs.ModelData ? productData.productAttrs.ModelData[defaultModelStr] : null;
9715
9716      var modelHeight = selectedModel ? selectedModel.height : Utils.getValueFromObject(productData, 'productAttrs.OFPModelHeight', '');
9717      var modelSize = selectedModel ? selectedModel.size : Utils.getValueFromObject(productData, 'productAttrs.OFPModelSize', '');
9718
9719      $infoPanel.find(detailsHeightSelector).html(modelHeight);
9720      $infoPanel.find(detailsSizeSelector).html(modelSize);
9721    },
9722
9723    setGarmentMeasurements: function setGarmentMeasurements(productId, $productSection, $infoPanel) {
9724      var anfObject = Utils.getANFObject();
9725      var $measurementContainer = $infoPanel.find(garmentMeasurementsSelector);
9726      var garmentData = garmentMeasurements.getGarmentMeasurementData(productId, anfObject, $productSection);
9727      $measurementContainer.html(template.renderTemplate('garmentMeasurements', garmentData));
9728    },
9729
9730    setSizeGuideFitRecommendation: function setSizeGuideFitRecommendation($productSection) {
9731      var $recommendedFit = $productSection.find(sizeGuideRecommendedFitSelector);
9732
9733      if ($recommendedFit.html()) {
9734        return;
9735      }
9736
9737      var fitRec = $productSection.find(reviewRecommendedFitSelector).first();
9738      if (fitRec.length > 0 && fitRec.css('display') === 'block') {
9739        $recommendedFit.append(fitRec.html());
9740        $recommendedFit.find('a').contents().unwrap();
9741      }
9742    },
9743
9744    sizeGuideImageHandler: function sizeGuideImageHandler($productSection, productId) {
9745      var imageObject = $productSection.data('imageDataModel');
9746
9747      if (!imageObject) {
9748        return;
9749      }
9750
9751      var defaultModelStr = window.selectedModelSegment || Utils.getValueFromObject(Utils.getProductData(productId), 'productAttrs.ModelData.defaultModel', null);
9752      var model = defaultModelStr ? StringUtils.camelize(defaultModelStr, false) : 'model';
9753      // double check that we have the correct model
9754      var selectedModel = imageObject[model] ? imageObject[model] : imageObject.model;
9755
9756      var imagesToDisplay = gatherImagesToDisplay(selectedModel, imageObject);
9757      var images = [];
9758      imagesToDisplay.forEach(function addSrc(image) {
9759        var imageToDisplay = {
9760          src: ANFImage.instance()
9761            .setImageName(image.imageId)
9762            .setWidth(800)
9763            .url,
9764          altText: image.imageId.indexOf('prod') > -1 ? 'prod' : 'model',
9765          imageId: image.imageId
9766        };
9767
9768        images.push(imageToDisplay);
9769      });
9770
9771      var markup = template.renderTemplate('sizeGuideImages', {images: images});
9772      var $imageBannerWrapper = $productSection.find(sizeGuideImagesSelector);
9773
9774      document.querySelector(sizeGuideImagesSelector).addEventListener('error', imageBannerErrorHandler, true);
9775
9776      $imageBannerWrapper.html(markup);
9777    }
9778  };
9779
9780  return publicMembers;
9781});
9782
9783redesign.define('productModules/product/sizeGuide/sizeGuideAnalytics',[], function SizeGuideAnalytics() {
9784  'use strict';
9785
9786  var unitTabContainerSelector = '.details__size-guide-modal .size-guide__unit-toggle-wrapper .toggle-block';
9787  var measurementGuideTabSelector = 'button[id^="size-guide__tab-guide"]';
9788  var sizeChartTabSelectorId = 'button[id^="size-guide__tab-chart"]';
9789  var sizeGuideLinkSelector = '.details__link-size-chart, .product-page__info-size-chart, .size-fit__accordion .view-size-fit-btn';
9790  var sizeGuideRegionSelector = '.size-guide-region-selector select';
9791
9792  function handleMeasurementGuideTabClick() {
9793    $(window).trigger('analytics.modalAction', {
9794      'name': 'size & fit guide',
9795      'action': 'tab click',
9796      'attribute': 'how to measure'
9797    });
9798  }
9799  function handleRegionChange(event) {
9800    $(window).trigger('analytics.modalAction', {
9801      'name': 'size & fit guide',
9802      'action': 'region selected',
9803      'attribute': event.currentTarget.value
9804    });
9805  }
9806  function handleSizeGuideLinkClick() {
9807    $(window).trigger('analytics.miscProductFeature', {
9808      'type': 'size & fit guide',
9809      'action': 'click'
9810    });
9811  }
9812  function handleSizeChartTabClick() {
9813    $(window).trigger('analytics.modalAction', {
9814      'name': 'size & fit guide',
9815      'action': 'tab click',
9816      'attribute': 'chart'
9817    });
9818  }
9819  function handleUnitToggleChange(event) {
9820    var unit = $(event.currentTarget).find('input').val();
9821
9822    $(window).trigger('analytics.modalAction', {
9823      'name': 'size & fit guide',
9824      'action': 'unit change',
9825      'attribute': unit
9826    });
9827  }
9828  var publicMembers = {
9829    bindEvents: function bindEvents() {
9830      var $document = $(document);
9831
9832      $document.on('click', measurementGuideTabSelector, handleMeasurementGuideTabClick);
9833      $document.on('click', sizeChartTabSelectorId, handleSizeChartTabClick);
9834      $document.on('click', sizeGuideLinkSelector, handleSizeGuideLinkClick);
9835
9836      $document.on('change', sizeGuideRegionSelector, handleRegionChange);
9837      $document.on('change', unitTabContainerSelector, handleUnitToggleChange);
9838    }
9839
9840  };
9841
9842  return publicMembers;
9843});
9844
9845redesign.define('productServices/product/retrieveFabricCareAttrs',['productModules/helpers/Utils'], function RetrieveFabricCareAttrs(Utils) {
9846  'use strict';
9847
9848  function isArrayOfValues(content) {
9849    return typeof content.values !== 'undefined' && content.values !== null;
9850  }
9851
9852  function isSingleValue(content) {
9853    return typeof content.value !== 'undefined' && content.value !== null;
9854  }
9855
9856  function getCurrentData(productId) {
9857    var productData = Utils.getProductData(productId);
9858    var data = (
9859      typeof productData !== 'undefined'
9860    ) ? productData.productAttrsComplex : {};
9861
9862    return data;
9863  }
9864
9865  function fromContentValues(content) {
9866    var data = [];
9867    if (typeof content !== 'undefined') {
9868      if (isArrayOfValues(content)) {
9869        $(content.values).each(function each() {
9870          data.push(this.value);
9871        });
9872      } else if (isSingleValue(content)) {
9873        data = [content.value];
9874      }
9875    }
9876    return data;
9877  }
9878
9879  var publicMembers = {
9880
9881    getFabricCareData: function getFabricCareData(productId) {
9882      var fabric = [];
9883      var care = [];
9884
9885      if (typeof productId !== 'undefined') {
9886        var productData = getCurrentData(productId);
9887
9888        fabric = fromContentValues(productData.FiberContent);
9889        care = fromContentValues(productData.CareInstructions);
9890      }
9891
9892      return {
9893        fabric: fabric,
9894        care: care
9895      };
9896    }
9897  };
9898
9899  return publicMembers;
9900});
9901
9902redesign.define('productModules/product/productFabricCare',[
9903  'productServices/product/retrieveFabricCareAttrs',
9904  'productModules/helpers/Utils'
9905], function ProductFabricCare(fabricCareService, Utils) {
9906  'use strict';
9907
9908  var messageBus = $(ANF);
9909
9910  var fabricCareContainerSelectorClass = '.fabric-care__container';
9911  var fabricCareListSelectorClass = '.fabric-care__list';
9912  var productV2SelectorClass = '.product-page-v2-modules';
9913  var quickviewProductSelector = '.product-quickview__modal .product-page-v2-modules';
9914  var productV2Class = 'product-page-v2-modules';
9915  var fiberContentContainer = '.fiber-content__label';
9916
9917  function getFabricCareInfo(DOMElement) {
9918    var $productSection = $(DOMElement).hasClass(productV2Class) ? $(DOMElement) : $(DOMElement).closest(productV2SelectorClass);
9919
9920    var fabricCareInfo = {
9921      $fabricCareContainer: $productSection.find(fabricCareContainerSelectorClass),
9922      $fiberContentContainer: $productSection.find(fiberContentContainer),
9923      $fabricCareList: $productSection.find(fabricCareListSelectorClass),
9924      productId: $productSection.data('productid')
9925    };
9926
9927    return fabricCareInfo;
9928  }
9929
9930  var publicMembers = {
9931    createFabricCareListItem: function createFabricCareListItem(text) {
9932      return $('<li></li>').text(text);
9933    },
9934
9935    renderFabricCareList: function renderFabricCareList(fabricCareInfo) {
9936      var fabricCareData = fabricCareService.getFabricCareData(fabricCareInfo.productId);
9937      var $careListItems;
9938
9939      fabricCareInfo.$fiberContentContainer.html(fabricCareData.fabric.join(' / '));
9940      $careListItems = $.map(fabricCareData.care, publicMembers.createFabricCareListItem);
9941      fabricCareInfo.$fabricCareList.empty().append($careListItems);
9942
9943      // We still want to empty the fabricCareList if there are no care instructions, but also not show the container
9944      var hasCareData = fabricCareData.length > 0 || (fabricCareData.care.length > 0 && fabricCareData.fabric.length > 0);
9945
9946      if (hasCareData) {
9947        fabricCareInfo.$fabricCareContainer.addClass('has-care-data');
9948      } else {
9949        fabricCareInfo.$fabricCareContainer.removeClass('has-care-data');
9950      }
9951    },
9952
9953    handleSwatchSelect: function handleSwatchSelect(e, swatch) {
9954      var fabricCareInfo = getFabricCareInfo(swatch);
9955
9956      publicMembers.renderFabricCareList(fabricCareInfo);
9957    },
9958
9959    handleFabricCareLoad: function handleFabricCareLoad(e, isQuickview) {
9960      var $products = isQuickview ? $(quickviewProductSelector) : $(productV2SelectorClass);
9961      if (!isQuickview && Utils.hasProductMFEEnabled()) {
9962        return;
9963      }
9964      $products.each(function products(idx, $product) {
9965        var fabricCareInfo = getFabricCareInfo($product);
9966        publicMembers.renderFabricCareList(fabricCareInfo);
9967      });
9968    }
9969
9970  };
9971
9972  publicMembers.listen = function listen() {
9973    messageBus.on('productPageInfo:swatchSelected', publicMembers.handleSwatchSelect);
9974    messageBus.on('productFabricCare:load', publicMembers.handleFabricCareLoad);
9975  };
9976
9977
9978  return publicMembers;
9979});
9980
9981redesign.define('productModules/product/productRecommendationAnalytics',['productModules/helpers/Utils'],
9982  function ProductRecommendationAnalytics(Utils) {
9983    'use strict';
9984
9985    return function ProductRecommendationAnalyticsClosure(productIntersectionObserver) {
9986      function wireIntersectionObserver(targetContainer) {
9987        var productSliderObserver = new productIntersectionObserver.IntersectionObserver(
9988          function productIntersectionObserverCallback(entries) {
9989            for (var i = 0, len = entries.length; i < len; i++) {
9990              var recContainer = entries[i];
9991
9992              if (recContainer.isIntersecting) {
9993                productSliderObserver.unobserve(recContainer.target);
9994                var ProductRecommendationId = $(recContainer.target).attr('data-sli
9994der-id');
9995                var ProductRecommendationContainer = document.querySelector('[data-slider-id=' + ProductRecommendationId + ']');
9996                if (ProductRecommendationContainer.hasChildNodes()) {
9997                  window.digitalData.trigger('universal_scroll', {
9998                    Tealium_event: 'scroll',
9999                    data_text: 'user scrolled to',
10000                    data_action: ProductRecommendationId
10001                  });
10002                }
10003              }
10004            }
10005          },
10006          {
10007            threshold: 0
10008          }
10009        );
10010
10011        productSliderObserver.observe(targetContainer);
10012      }
10013
10014      function init() {
10015        var $productRecContainers = $('.product-page-user-content__recommendations .js-recommendation-slider');
10016
10017        $productRecContainers.each(function recContainerWireLoop(i, container) {
10018          wireIntersectionObserver(container);
10019        });
10020      }
10021
10022      var publicMembers = {
10023        'bindEvents': function bindEvents() {
10024          if (!Utils.isExternalUser()) {
10025            init();
10026          }
10027        }
10028      };
10029
10030      return publicMembers;
10031    };
10032  });
10033
10034redesign.define('productModules/product/productSizeMessaging',['productServices/product/template',
10035  'productModules/helpers/Utils'
10036], function ProductSizeMessaging(template, Utils) {
10037  'use strict';
10038
10039  function handleSizeMessaging(e, $selectedSwatch, $productSection, productId, ANFObject) {
10040    var sizeChartName = Utils.getProductData(productId).sizeChartName;
10041    var templateData = ANFObject.messaging.catalogV2.sizeMessaging[sizeChartName];
10042    var markup;
10043
10044    if (templateData) {
10045      markup = template.renderTemplate('productSizeMessaging', templateData);
10046      var $sizeMessagingContainer = $productSection
10047        .find('.size-messaging-container')
10048        .append(markup)
10049        .show();
10050
10051      $sizeMessagingContainer
10052        .eq(1)
10053        .find('.size-messaging__header')
10054        .addClass('h2');
10055    }
10056  }
10057
10058  var publicMembers = {
10059    listen: function listen() {
10060      $(ANF).on('productPageInfo:swatchOnLoad', handleSizeMessaging);
10061    }
10062  };
10063
10064  return publicMembers;
10065});
10066
10067redesign.define('productModules/product/sizebaySetup',['productModules/helpers/Utils',
10068  'productModules/helpers/featureSwitchHelper'
10069], function SizeBaySetup(Utils, featureSwitchHelper) {
10070  'use strict';
10071
10072  function listen() {
10073    $(ANF).on('productPageInfo:swatchOnLoad', checkForSizebayEnabledAndSetup);
10074  }
10075
10076  function checkForSizebayEnabledAndSetup(e, $selectedSwatch, $productSection, productId) {
10077    if (Utils.isJeansProduct(productId)) {
10078      featureSwitchHelper.checkFeatureSwitchAndSplitTest('sizebay-enabled', setupSizeBay);
10079    }
10080  }
10081
10082  function setupSizeBay() {
10083    if ($('#sizebay-vfr-v4').length === 0) {
10084      var $sizebayScript = $('<script id="sizebay-vfr-v4" />')
10085        .attr('src', Utils.getANFObject().params.urls.thirdParty.sizebayUrl);
10086
10087      $('head').append($sizebayScript);
10088    }
10089  }
10090
10091  var publicMembers = {
10092    listen: listen
10093  };
10094
10095  return publicMembers;
10096});
10097
10098redesign.define('productModules/product/productMemberEarlyAccess',[
10099  'globalServices/userState',
10100  'productModules/helpers/Utils'
10101], function productMemberEarlyAccess(userStateService, Utils) {
10102  'use strict';
10103
10104  var messageBus = $(ANF);
10105  var nonEarlyAccess = 'non-early-access-member';
10106  var quickviewLoginButton = '.product-quickview__modal .js-product-login-button';
10107
10108  function handleMemberEarlyAccess(e, $selectedSwatch, $productSection, productId) {
10109    var earlyAccessFlag = Utils.productHasEarlyAccessIndicator(productId);
10110    var isLoyaltyRegion = ANF.params.storeAttributes.loyalty.enabled;
10111    var atbWrapper = $productSection.find('.atb-member-wrapper');
10112
10113    if (isLoyaltyRegion && earlyAccessFlag && !userStateService.isLoggedIn()) {
10114      atbWrapper.addClass(nonEarlyAccess);
10115    } else {
10116      atbWrapper.removeClass(nonEarlyAccess);
10117    }
10118  }
10119  var publicMembers = {
10120    listen: function listen() {
10121      messageBus.on('productPageInfo:swatchOnLoad productPageInfo:swatchSelected', handleMemberEarlyAccess);
10122    },
10123    bindEvents: function bindEvents() {
10124      $(document).on('click', quickviewLoginButton, function quickviewLoginClicked() {
10125        messageBus.trigger('quickviewLogin:clicked');
10126      });
10127    }
10128  };
10129
10130  return publicMembers;
10131});
10132
10133redesign.define('productModules/product/productReviewsLegalText',[
10134  'productModules/helpers/Utils'
10135],
10136function ReviewsLegalText(Utils) {
10137  'use strict';
10138
10139  var legalCopyTextSelectorClass = '.reviews-legal-text';
10140  var legalCopyContainerSelectorClass = '.reviews-legal-text-container';
10141
10142  function showLegalCopy() {
10143    var hasReviewLegalText = window.digitalData.get('flag.pdp-reviews-legal-text', false);
10144
10145    if (!Utils.isQuickviewOpened && hasReviewLegalText) {
10146      var legalTextRaw = Utils.getANFObject().messaging.product.PDP_REVIEWS_LEGAL_TEXT;
10147      var legalTextWithLink = legalTextRaw.replace('{0}', Utils.getANFObject().params.urls.catalogV2.reviewsLegalTextUrl);
10148      var $legalCopyContainer = $(legalCopyContainerSelectorClass);
10149      var $legalCopyText = $legalCopyContainer.find(legalCopyTextSelectorClass);
10150
10151      $legalCopyText.append(legalTextWithLink);
10152      $legalCopyContainer.addClass('show');
10153    }
10154  }
10155
10156  var publicMembers = {
10157    listen: function listen() {
10158      $(ANF).on('productPageInfo:swatchOnLoad mfe:SwatchSelected', showLegalCopy);
10159    }
10160  };
10161
10162  return publicMembers;
10163});
10164
10165redesign.define('productModules/product/finalSale',['productModules/helpers/Utils'], function ProductDetailsAccordion(Utils) {
10166  'use strict';
10167
10168  var messageBus = $(ANF);
10169
10170  function checkForFinalSale(e, $selectedSwatch, $productSection) {
10171    if (Utils.hasFinalSaleEnabled()) {
10172      var productId = $productSection.data('productid');
10173      var isFinalSaleProduct = Utils.getProductData(productId).isFinalSale;
10174      var $finalSaleContainer = $productSection.find('.final-sale-container');
10175
10176      if (isFinalSaleProduct) {
10177        $finalSaleContainer.show();
10178      } else {
10179        $finalSaleContainer.hide();
10180      }
10181    }
10182  }
10183
10184  var publicMembers = {
10185    listen: function listen() {
10186      messageBus.on('productPageInfo:swatchOnLoad productPageInfo:swatchSelected', checkForFinalSale);
10187    }
10188  };
10189
10190  return publicMembers;
10191});
10192
10193redesign.define('productModules/helpers/analyticsHelper',[],
10194  function AnalyticsHelper() {
10195    'use strict';
10196
10197    var completeTheLookLinkSelectorClass = '.product-main-images__wrapper.scope-1892 a.stylitics-jumplink.jumplink';
10198
10199    function handleAccordionOpen(event) {
10200      var accordionType = event.target.dataset && event.target.dataset.accordionName;
10201
10202      if (accordionType) {
10203        window.digitalData.trigger('analytics.pdp_accordion_open', {
10204          tealium_event: 'click',
10205          data_text: accordionType,
10206          data_action: 'open'
10207        });
10208      }
10209    }
10210
10211    function getConfig(configName) {
10212      var triggerConfig = {
10213        sizeGuideClick: {
10214          analytics: 'analytics.pdp_size_guide_click',
10215          data_text: 'size guide',
10216          data_action: 'open'
10217        },
10218        howToMeasure: {
10219          analytics: 'pdp_size_guide_how_to_measure_click',
10220          data_text: 'size guide - how to measure',
10221          data_action: 'open'
10222        },
10223        completeTheLook: {
10224          analytics: 'pdp_stylitics_complete_this_look_click',
10225          data_text: 'stylitics-complete-this-look',
10226          data_action: 'click'
10227        },
10228        viewLook: {
10229          analytics: 'pdp_stylitics_view_this_look_click',
10230          data_text: 'stylitics-view-this-look',
10231          data_action: 'open'
10232        }
10233      };
10234
10235      if (triggerConfig[configName]) {
10236        var defaultConfig = {
10237          analytics: triggerConfig[configName].analytics,
10238          data: {
10239            tealium_event: 'click',
10240            data_text: triggerConfig[configName].data_text,
10241            data_action: triggerConfig[configName].data_action
10242          }
10243        };
10244        return defaultConfig;
10245      }
10246      return null;
10247    }
10248
10249    function handleProductAnalytics(event) {
10250      var configName = event.data.configName;
10251      var config = getConfig(configName);
10252
10253      if (config) {
10254        window.digitalData.trigger(config.analytics, config.data);
10255      }
10256    }
10257
10258    var publicMembers = {
10259      bindEvents: function bindEvents() {
10260        $(document).off('click', '.product-page__info-size-chart.js-open-modal').on('click', '.product-page__info-size-chart.js-open-modal', function handleModalClick() {
10261          handleProductAnalytics({ data: { configName: 'sizeGuideClick' } });
10262        });
10263        $(document).on('dsAccordion:Open', handleAccordionOpen);
10264        $(document).on('guideSize:howToMeasure', {configName: 'howToMeasure'}, handleProductAnalytics);
10265        $(completeTheLookLinkSelectorClass).on('click', {configName: 'completeTheLook'}, handleProductAnalytics);
10266        $(window).on('styliticsV3Item:viewLook', {configName: 'viewLook'}, handleProductAnalytics);
10267      }
10268    };
10269
10270    return publicMembers;
10271  });
10272
10273redesign.define('productModules/product/productExitRateAnalytics',['productModules/helpers/Utils'],
10274  function ProductExitRateAnalytics(Utils) {
10275    'use strict';
10276
10277    return function ProductShopSimilarAnalyticsClosure(productIntersectionObserver) {
10278      function wireIntersectionObserver(targetContainer) {
10279        var shopSimilarObserver = new productIntersectionObserver.IntersectionObserver(
10280          function productIntersectionObserverCallback(entries) {
10281            for (var i = 0, len = entries.length; i < len; i++) {
10282              var shopSimilarContainer = entries[i];
10283
10284              if (shopSimilarContainer.isIntersecting) {
10285                shopSimilarObserver.unobserve(shopSimilarContainer.target);
10286                window.digitalData.trigger('universal_scroll', {
10287                  event_name: 'scroll',
10288                  data_text: 'user scrolled to',
10289                  data_action: 'pdp shop similar grid'
10290                });
10291              }
10292            }
10293          },
10294          {
10295            threshold: 0
10296          }
10297        );
10298
10299        shopSimilarObserver.observe(targetContainer);
10300      }
10301
10302      function init() {
10303        var $productShopSimilarContainer = $('.pdp-grid-container');
10304        if (Utils.isExternalUser() && !Utils.isQuickviewOpened && !Utils.hasProductMFEEnabled) {
10305          wireIntersectionObserver($productShopSimilarContainer[0]);
10306        }
10307      }
10308
10309      var publicMembers = {
10310        'bindEvents': function bindEvents() {
10311          if (Utils.isPdpPage) {
10312            init();
10313          }
10314        }
10315      };
10316
10317      return publicMembers;
10318    };
10319  });
10320
10321redesign.define('productSections/product/productPageInfo',[
10322  'coreSectionHelpers',
10323  'productModules/product/productSizes',
10324  'productModules/product/productMultipleAttributeFilter',
10325  'productModules/product/productSwatches',
10326  'productModules/product/productPrice',
10327  'productModules/product/addToBag/pdpAddToBag',
10328  'productModules/product/addToBag/quickviewAddToBag',
10329  'productModules/product/productNameAndDescription',
10330  'productModules/product/addToBag/productStickyAddToBag',
10331  'productModules/product/productDetailBadging',
10332  'productModules/product/buyGridAccordions/productDetailsAccordion',
10333  'productModules/product/buyGridAccordions/productSizeFitAccordion',
10334  'productModules/product/sizeGuide/productSizeGuide',
10335  'productModules/product/sizeGuide/sizeGuideHeader',
10336  'productModules/product/sizeGuide/sizeGuideChartControls',
10337  'productModules/product/sizeGuide/sizeGuideAnalytics',
10338  'productModules/product/productFabricCare',
10339  'productModules/product/productRecommendationAnalytics',
10340  'productModules/helpers/productIntersectionObserver',
10341  'productModules/product/productSizeMessaging',
10342  'productModules/product/sizebaySetup',
10343  'productModules/product/productMemberEarlyAccess',
10344  'productModules/product/productReviewsLegalText',
10345  'productModules/helpers/featureSwitchHelper',
10346  'productModules/product/finalSale',
10347  'productModules/helpers/analyticsHelper',
10348  'productModules/helpers/ProductMFEAdapter',
10349  'productModules/product/productExitRateAnalytics'
10350], function ProductPageInfo(
10351  coreSectionHelpers,
10352  productSizes,
10353  productMultipleAttributeFilter,
10354  productSwatches,
10355  productPrice,
10356  pdpAddToBag,
10357  quickviewAddToBag,
10358  productNameAndDescription,
10359  productStickyAddToBag,
10360  productDetailBadging,
10361  productDetailsAccordion,
10362  productSizeFitAccordion,
10363  sizeGuide,
10364  sizeGuideHeader,
10365  sizeGuideControls,
10366  sizeGuideAnalytics,
10367  productFabricCare,
10368  productRecommendationAnalytics,
10369  productIntersectionObserver,
10370  productSizeMessaging,
10371  sizebaySetup,
10372  productMemberEarlyAccess,
10373  productReviewsLegalText,
10374  featureSwitchHelper,
10375  finalSale,
10376  analyticsHelper,
10377  productMFEAdapter,
10378  productExitRateAnalytics
10379) {
10380  'use strict';
10381
10382  var privateMembers = {
10383    DEFAULT_MODULES: {
10384      productSizes: productSizes,
10385      productMultipleAttributeFilter: productMultipleAttributeFilter,
10386      productSwatches: productSwatches,
10387      productPrice: productPrice,
10388      pdpAddToBag: pdpAddToBag,
10389      quickviewAddToBag: quickviewAddToBag,
10390      productNameAndDescription: productNameAndDescription,
10391      productStickyAddToBag: productStickyAddToBag(productIntersectionObserver),
10392      productDetailBadging: productDetailBadging,
10393      productDetailsAccordion: productDetailsAccordion,
10394      productSizeFitAccordion: productSizeFitAccordion,
10395      '.details__size-chart-modal': sizeGuide,
10396      sizeGuideHeader: sizeGuideHeader,
10397      sizeGuideControls: sizeGuideControls,
10398      sizeGuideAnalytics: sizeGuideAnalytics,
10399      productFabricCare: productFabricCare,
10400      productRecommendationAnalytics: productRecommendationAnalytics(productIntersectionObserver),
10401      productSizeMessaging: productSizeMessaging,
10402      sizebaySetup: sizebaySetup,
10403      productMemberEarlyAccess: productMemberEarlyAccess,
10404      productReviewsLegalText: productReviewsLegalText,
10405      finalSale: finalSale,
10406      analyticsHelper: analyticsHelper,
10407      productMFEAdapter: productMFEAdapter,
10408      productExitRateAnalytics: productExitRateAnalytics(productIntersectionObserver)
10409    },
10410    GLOBAL_SCOPE: '',
10411    MODULES: {},
10412    parentPage: ''
10413  };
10414
10415  return function scope(settings) {
10416    privateMembers.GLOBAL_SCOPE = settings.scope;
10417    privateMembers.parentPage = settings.parentPage;
10418    privateMembers.MODULES = privateMembers.DEFAULT_MODULES;
10419
10420    if (typeof settings.modules === 'object') {
10421      $.extend(true, privateMembers.MODULES, settings.modules);
10422    }
10423
10424    var messageBus = $(ANF);
10425
10426    return {
10427      'init': function init() {
10428        coreSectionHelpers.init({
10429          'modules': privateMembers.MODULES,
10430          'scope': privateMembers.GLOBAL_SCOPE
10431        });
10432
10433        productDetailBadging.init();
10434      },
10435      'subscribe': function subscribe() {
10436        messageBus.on('productPageMain:init', privateMembers.parentPage.productPageInfo.productPageInfoLoad);
10437        messageBus.on('productPageMain:init', privateMembers.parentPage.productPageInfo.productFabricCareLoad);
10438      },
10439      'productPageInfoLoad': function productPageInfoLoad() {
10440        messageBus.trigger('productPageInfo:load');
10441        featureSwitchHelper.styleFitDesc();
10442        featureSwitchHelper.shortDescriptorSplitTest();
10443      },
10444      'productFabricCareLoad': function productFabricCareLoad() {
10445        messageBus.trigger('productFabricCare:load');
10446      }
10447    };
10448  };
10449});
10450
10451redesign.define('coreServices/helpers/featureSwitch',[], function featureSwitch() {
10452  'use strict';
10453
10454  var publicMembers = {
10455
10456    checkFeatureSwitchAndSplitTest: function checkFeatureSwitchAndSplitTest(featureAndSplitTestKey, cb) {
10457      var deferredResult = new $.Deferred();
10458      var featureFlagKey = 'flag.' + featureAndSplitTestKey;
10459      var splitTestKey = 'test.' + featureAndSplitTestKey;
10460      if (window.digitalData.get(featureFlagKey, false ) || window.digitalData.get(splitTestKey, false)) {
10461        deferredResult.resolve(true);
10462      } else {
10463        var digitalDataSubscription = window.digitalData.subscribe(splitTestKey, function checkTestSegment(segment) {
10464          if (typeof segment !== 'undefined') {
10465            this.unsubscribe();
10466            deferredResult.resolve(segment);
10467          }
10468        });
10469        setTimeout(function setTimeout() {
10470          digitalDataSubscription.unsubscribe();
10471          deferredResult.resolve(false);
10472        }, 2000);
10473      }
10474      deferredResult.promise()
10475        .then(function checkSegment(isEnabled) {
10476          return cb(isEnabled);
10477        });
10478    },
10479    checkFeatureSwitchAndSplitTestValue: function checkFeatureSwitchAndSplitTestValue(featureAndSplitTestKey, cb) {
10480      var deferredResult = new $.Deferred();
10481      var featureFlagKey = 'flag.' + featureAndSplitTestKey;
10482      deferredResult.resolve(window.digitalData.get(featureFlagKey, null ));
10483      deferredResult.promise()
10484        .then(function checkSegment(value) {
10485          return cb(value);
10486        });
10487    },
10488    getLocationSearch: function getLocationSearch() {
10489      return window.location.search;
10490    },
10491    getDigitalDataFlagValue: function getDigitalDataFlagValue(key) {
10492      var storeAttributeFlags = window.digitalData && window.digitalData.export() && window.digitalData.export().flag;
10493      // The return value can be undefined if LD is not setup, so implementer needs to handle this.
10494      // supports comma separates like "?ldo=ful-123:1,ful-456:0,;purx-123:1"
10495      try {
10496        var locationSearch = this.getLocationSearch();
10497        if (locationSearch) {
10498          var modeField = locationSearch.match(/ldo=(([\w-0-9]+:[01],?)+)&?/);
10499          var modeFieldValue = (modeField && modeField[1]);
10500          if (modeFieldValue) {
10501            var modeFields = modeFieldValue.split(',');
10502            var overrides = modeFields.reduce(function reduceOverrides(accum, override) {
10503              if (!override) {
10504                return accum;
10505              }
10506              var parts = override.split(':');
10507              var data = {};
10508              data[parts[0]] = parseInt(parts[1], 10);
10509              return $.extend({}, accum, data);
10510            }, {});
10511            if (key in overrides) {
10512              return overrides[key];
10513            }
10514          }
10515        }
10516        if (JSON.parse(sessionStorage.getItem('debug_mode')) &&
10517          JSON.parse(sessionStorage.getItem(key)) !== null) {
10518          // returned overridden value from sessionStorage
10519          return JSON.parse(sessionStorage.getItem(key));
10520        }
10521      } catch (e) {
10522        // eslint-disable-next-line no-console
10523        console.error(e);
10524      }
10525
10526      return storeAttributeFlags[key];
10527    }
10528  };
10529  return publicMembers;
10530});
10531
10532redesign.define('productModules/product/quickview/quickview',[
10533  'anfcore/components/statefulButton',
10534  'anfcore/components/modal',
10535  'anfcore/components/dropDown',
10536  'anfcore/components/accordion',
10537  'productModules/helpers/Utils',
10538  'productModules/helpers/breakpoints',
10539  'coreServices/storage',
10540  'productModules/helpers/featureSwitchHelper',
10541  'coreServices/helpers/featureSwitch',
10542  'util/analytics/enum/dataPoint',
10543  'util/analytics/enum/subscriptionName',
10544  'anfUtil/constants',
10545  'coreServices/geoLocationService'
10546], function ProductQuickview(
10547  statefulButton,
10548  modal,
10549  dropDown,
10550  accordion,
10551  Utils,
10552  breakpoints,
10553  storage,
10554  featureSwitchHelper,
10555  featureSwitch,
10556  analyticsDataPoints,
10557  analyticSubscriptionName,
10558  constants
10559) {
10560  'use strict';
10561  var dsModal = modal.default();
10562
10563  var quickviewModalSelectorClass = '.product-quickview__modal';
10564  var quickviewButtonSelectorClass  = '.product-quickview__button';
10565  var editQuickviewButtonClass  = 'product-quickview__edit-button';
10566  var quickviewProductSectionSelector = '.product-quickview__content .product-page-v2-modules';
10567  var quickviewContentSelectorClass = '.product-quickview__content';
10568  var addToBagButtonSelector = '.product-page-add-to-bag__button';
10569  var definingAttrSelectorClass = '.product-attrs__attr';
10570  var quickviewEditModalSelector = '.product-quickview__modal.edit-product';
10571  var quickviewEditModalClass = 'edit-product';
10572  var detailsSelectorClass = '.details';
10573  var addToBagFormSelector = '.product-page-add-to-bag__container';
10574  var quickviewDetailsWrapperHookSelector = '#quickview-details__wrapper-hook .accordion-panel-content';
10575  var fullProductLinkSelector = '.product-quickview__modal .product-quickview__view-full-product-link';
10576  var quickviewSoldOutSelectorClass = '.product-quickview__sold-out';
10577  var exchangesModalButtonClass = 'exchanges-quickview__button';
10578  var exchangesModalClass = 'exchanges-quickview__modal';
10579  var exchangesSaveButtonSelector = '.exchanges-quickview__save-button';
10580  var exchangesEditModalClass = 'exchanges-quickview__modal-edit';
10581  var exchangesNoLongerAvailableSelector = '#exchangesNoLongerExists';
10582  var changeLinkClass = 'return-change_link';
10583  var shoppingCartQVSelectorClass = '#checkout-cart button.js-pc-edit-button';
10584  var styliticsQuickviewButtonClass = 'stylitics-widget-item-container';
10585  var styliticsModalClass = 'stylitics-quickview';
10586  var isEditFromMiniBag = false;
10587
10588  var messageBus = $(ANF);
10589
10590  var openExtraAnalyticsData = {};
10591
10592  function getFaceoutValue($quickviewLink, quickviewLinkAttrs) {
10593    var faceout = 'prod';
10594    var hasOfpAttr = typeof quickviewLinkAttrs.showOfp !== 'undefined' && quickviewLinkAttrs.showOfp;
10595    var $imageWrapperLink = $quickviewLink.closest('.product-template').find('.product-card__image-link');
10596    var hasImageWrapperLinkOfp = $imageWrapperLink.length > 0 && $imageWrapperLink.attr('href').indexOf('ofp=true') > -1;
10597    if (typeof quickviewLinkAttrs.faceout !== 'undefined') {
10598      faceout = quickviewLinkAttrs.faceout.replace(/[0-9]/g, '');// remove number character
10599    } else if (hasOfpAttr || hasImageWrapperLinkOfp) {
10600      faceout = 'model';
10601    }
10602    return faceout;
10603  }
10604
10605  function getReturnFocus($quickviewLink) {
10606    var $returnFocus = $quickviewLink;
10607    // if the link clicked to open qv was edit in minibag, focus will go to bag icon on modal close
10608    var $shoppingBagParent = $quickviewLink.parents('.rs-nav__util-item--shopping-bag');
10609    if ($shoppingBagParent.length > 0) {
10610      $returnFocus = $shoppingBagParent.find('.rs-nav-icon--shopping-bag');
10611    }
10612    return $returnFocus;
10613  }
10614
10615  function constructQuickviewURL(quickviewState) {
10616    var quickviewParams = {
10617      productId: quickviewState.productId,
10618      collectionId: quickviewState.collectionId,
10619      seq: quickviewState.seq,
10620      faceout: quickviewState.faceout
10621    };
10622    if (quickviewState.isSoldOutInCart) {
10623      quickviewParams.isSoldOutInCart = true;
10624    }
10625    if (quickviewState.categoryId) {
10626      quickviewParams.categoryId = quickviewState.categoryId;
10627    }
10628    if (quickviewState.origin) {
10629      quickviewParams.origin = quickviewState.origin;
10630    }
10631    if (quickviewState.afsource) {
10632      quickviewParams.afsource = quickviewState.afsource;
10633    }
10634
10635    if (quickviewState.pagevm) {
10636      quickviewParams.pagevm = quickviewState.pagevm;
10637    }
10638
10639    if (quickviewState.prodvm) {
10640      quickviewParams.prodvm = quickviewState.prodvm;
10641    }
10642
10643    // PRO-1479: Add dataText and dataAction to the quickview URL
10644    // These are specific to recommendations swatch click analytics
10645    if (quickviewState.dataText) {
10646      quickviewParams.dataText = quickviewState.dataText;
10647    }
10648
10649    if (quickviewState.dataAction) {
10650      quickviewParams.dataAction = quickviewState.dataAction;
10651    }
10652
10653    var baseUrl = ANF.params.urls.ajax.productQuickView;
10654
10655    return baseUrl + '&' + $.param(quickviewParams);
10656  }
10657
10658  function getBadgeDataFromProduct(productId, key) {
10659    var productData = Utils.getProductData(productId);
10660    if (!productData) {
10661      return null;
10662    }
10663    var keys = key.split('.');
10664    return keys.reduce(function _reduce(acc, currKey) {
10665      return (acc && acc.hasOwnProperty(currKey)) ? acc[currKey] : null;
10666    }, productData);
10667  }
10668
10669  function getProductBadge(productId) {
10670    var isNewArrival = getBadgeDataFromProduct(productId, 'newArrival');
10671    var earlyAccessFlag = getBadgeDataFromProduct(productId, 'productAttrs.EarlyAccessIndicator');
10672    var isEarlyAccess = earlyAccessFlag ? earlyAccessFlag.toString().toLowerCase() === 'true' : false;
10673    var isTopRated = getBadgeDataFromProduct(productId, 'productAttrs.topRated');
10674    var isBestSeller = getBadgeDataFromProduct(productId, 'productAttrs.bestSeller');
10675    return [isNewArrival ? 'new' : '', isEarlyAccess ? 'early access' : '', isTopRated ? 'top rated' : '', isBestSeller ? 'top seller' : ''].filter(Boolean).join(', ');
10676  }
10677
10678  function getIndividualProductShortDescriptor(firstShortDescriptor, secondShortDescriptor) {
10679    var shortDescriptor = firstShortDescriptor || secondShortDescriptor;
10680    var hasBothShortDescriptors = firstShortDescriptor && secondShortDescriptor;
10681
10682    if (hasBothShortDescriptors) return firstShortDescriptor + ' | ' + secondShortDescriptor;
10683
10684    return shortDescriptor || 'null';
10685  }
10686
10687  function fireDelayedQuickviewEvents() {
10688    if (Utils.isQuickviewOpened) {
10689      var $productSection = $(quickviewProductSectionSelector);
10690      var productId = $productSection.attr('data-productid');
10691      var shortSku = $productSection.find('select[name="sku"]').val();
10692      var dataPointEmptyValue = 'null';
10693
10694      var orEmptyObject = function orEmptyObjectFn(value) {
10695        return value || {};
10696      };
10697
10698      var productData = Utils.getProductData(productId);
10699      var listPrice = orEmptyObject(
10700        Object.values(
10701          orEmptyObject(
10702            orEmptyObject(
10703              productPrices[productId]
10704            ).items
10705          )
10706        ).pop()
10707      ).listPrice;
10708
10709      var listPriceUsd = orEmptyObject(
10710        Object.values(
10711          orEmptyObject(
10712            orEmptyObject(
10713              productPrices[productId]
10714            ).items
10715          )
10716        ).pop()
10717      ).listPriceUSD;
10718
10719      var offerPrice = orEmptyObject(
10720        Object.values(
10721          orEmptyObject(
10722            orEmptyObject(
10723              productPrices[productId]
10724            ).items
10725          )
10726        ).pop()
10727      ).offerPrice;
10728
10729      var categoryId = orEmptyObject(
10730        orEmptyObject(
10731          orEmptyObject(
10732            ANF
10733          ).catalog
10734        ).data
10735      ).categoryId;
10736
10737      var longSku = orEmptyObject(
10738        orEmptyObject(
10739          document.querySelector('.product-page-v2-modules.js-quickview')
10740        ).dataset
10741      ).longSku;
10742
10743      // Deprecated
10744      $(window).trigger('analytics.quickViewComplete', [openExtraAnalyticsData]);
10745
10746      var eventData = {};
10747      var primaryShortDescriptor = productData ? productData.shortDesc1 : '';
10748      var secondaryShortDescriptor = productData ? productData.shortDesc2 : '';
10749
10750      if ($(exchangesNoLongerAvailableSelector).length) {
10751        try {
10752          window.digitalData.trigger(
10753            'universal_click', {
10754              event_name: 'click',
10755              data_text: 'invalid submit',
10756              data_action: 'the item you wish to exchange is no longer available'
10757            });
10758        } catch (error) {
10759        // error
10760        }
10761      } else {
10762        eventData[analyticsDataPoints.BRAND] = productData.productAttrs && productData.productAttrs.brand || dataPointEmptyValue;
10763        eventData[analyticsDataPoints.COLLECTION_ID] = productData.collection || dataPointEmptyValue;
10764        eventData[analyticsDataPoints.KEY_ITEM_COLOR] = productData.kicId || dataPointEmptyValue;
10765        eventData[analyticsDataPoints.PRICE_LIST_LOCAL] = listPrice || dataPointEmptyValue;
10766        eventData[analyticsDataPoints.PRICE_LIST_USD] = listPriceUsd || dataPointEmptyValue;
10767        eventData[analyticsDataPoints.PRICE_OFFER_LOCAL] = offerPrice || dataPointEmptyValue;
10768        eventData[analyticsDataPoints.CATEGORY_ID] = categoryId || dataPointEmptyValue;
10769        eventData[analyticsDataPoints.PRICE_FLAG] = productData.priceFlag || dataPointEmptyValue;
10770        eventData[analyticsDataPoints.LONG_SKU] = longSku || dataPointEmptyValue;
10771        eventData[analyticsDataPoints.PRODUCT_ID] = productId || dataPointEmptyValue;
10772        eventData[analyticsDataPoints.PRODUCT_NAME] = productData.name || dataPointEmptyValue;
10773        eventData[analyticsDataPoints.PAGE_DESCRIPTION] = productData.name || dataPointEmptyValue;
10774        eventData[analyticsDataPoints.PRODUCT_BADGE] = getProductBadge(productId) || dataPointEmptyValue;
10775        eventData[analyticsDataPoints.SHORT_DESCRIPTOR] = getIndividualProductShortDescriptor(getIndividualProductShortDescriptor(primaryShortDescriptor, secondaryShortDescriptor));
10776        window.digitalData.trigger(analyticSubscriptionName.VIEW.QUICK_VIEW, eventData);
10777
10778        try {
10779          window.digitalData.trigger(
10780            'productQuickview.load-complete',
10781            $.extend(
10782              {
10783                brand: productData.productAttrs.brand,
10784                gender: productData.productAttrs.gender,
10785                kic: productData.kicId,
10786                priceFlag: productData.priceFlag,
10787                productId: productId,
10788                shortSku: shortSku
10789              },
10790              openExtraAnalyticsData
10791            )
10792          );
10793        } catch (error) {
10794        // error
10795        } finally {
10796          openExtraAnalyticsData = {};
10797        }
10798      }
10799    }
10800  }
10801
10802  function initQuickviewFromData(event) {
10803    var quickviewState = $.extend(event.detail, {
10804      $returnFocus: $(event.detail.returnFocus),
10805      $modal: $(quickviewModalSelectorClass),
10806      quickviewUrl: constructQuickviewURL(event.detail)
10807    });
10808
10809    openQuickviewModal(quickviewState);
10810    isEditFromMiniBag = false;
10811  }
10812
10813  /*
10814  * TODO: Find a better way to pass additional data from an event that opens a QV model to analytics
10815  * We are removing analytics from the details to prevent side effects caused by it being there
10816  */
10817  function initializeQuickviewFromClick(e) {
10818    e.preventDefault();
10819    var $currentTarget = $(e.currentTarget);
10820    var isMySaves = $(e.currentTarget).parents('.mysaves-content').length > 0;
10821    if (isMySaves
10822        && featureSwitch.getDigitalDataFlagValue('quickview-mfe-checkout-my-saves')
10823    ) {
10824      var productId = $currentTarget.attr('data-productid');
10825      var collectionId = $currentTarget.attr('data-collectionid');
10826      var eventData = {
10827        productId: productId,
10828        collectionId: collectionId,
10829        returnFocus: $currentTarget,
10830        pageViewMethod: 'modal-quickview',
10831        productViewMethod: 'navigation-my saves'
10832      };
10833      var mfeQVEvent = new CustomEvent('quickview:mfe:openModal', { detail: eventData });
10834      document.dispatchEvent(mfeQVEvent);
10835    } else {
10836      try {
10837        // TODO: Find a better way to pass additional data from an event that opens a QV model to analytics
10838        openExtraAnalyticsData = e.originalEvent.analytics || {};
10839      } catch (ewww) {
10840        openExtraAnalyticsData = {};
10841      }
10842      initializeQuickview($currentTarget);
10843      isEditFromMiniBag = false;
10844    }
10845  }
10846
10847  function initializeQuickviewFromMySaves(e, data) {
10848    initializeQuickview(data.currentTarget);
10849  }
10850
10851  function initializeQuickviewFromCart(e) {
10852    e.preventDefault();
10853    var $quickviewLink = $(e.currentTarget).parents('.product-template');
10854    initializeQuickview($quickviewLink);
10855    isEditFromMiniBag = false;
10856  }
10857
10858  function initializeEditModalOnPDP(e) {
10859    var quickviewState = $.extend(e.detail, {
10860      $returnFocus: $(e.detail.returnFocus),
10861      $modal: $(quickviewModalSelectorClass),
10862      quickviewUrl: constructQuickviewURL(e.detail)
10863    });
10864
10865    setEditModalAttributes(quickviewState);
10866    openQuickviewModal(quickviewState);
10867    isEditFromMiniBag = false;
10868  }
10869
10870  function initializeQuickview($quickviewLink) {
10871    var quickviewState = initQuickviewState($quickviewLink);
10872
10873    if (quickviewState.isEdit) {
10874      setEditModalAttributes(quickviewState);
10875    } else if (quickviewState.isExchange) {
10876      addExchangesModalClassesAndSku(quickviewState);
10877    }
10878
10879    openQuickviewModal(quickviewState);
10880  }
10881
10882  function initQuickviewState($quickviewLink) {
10883    var quickviewLinkAttrs = $quickviewLink.data();
10884    var quickviewState = {
10885      $modal: $(quickviewModalSelectorClass),
10886      isExchange: $quickviewLink.hasClass(exchangesModalButtonClass),
10887      isEdit: $quickviewLink.hasClass(editQuickviewButtonClass) || ($quickviewLink.parents('.shopping-bag-list').length > 0) || quickviewLinkAttrs.isedit,
10888      isSoldOutInCart: $quickviewLink.data('status') === 'Sold Out',
10889      isStylitics: $quickviewLink.hasClass(styliticsQuickviewButtonClass),
10890      hasChangeLink: $quickviewLink.hasClass(changeLinkClass),
10891      seq: quickviewLinkAttrs.seq,
10892      sku: quickviewLinkAttrs.sku && quickviewLinkAttrs.sku.toString(),
10893      orderItemId: quickviewLinkAttrs.orderitemid || $quickviewLink.closest(detailsSelectorClass).attr('data-orderitemid'),
10894      productId: quickviewLinkAttrs.productid,
10895      collectionId: quickviewLinkAttrs.collectionid || quickviewLinkAttrs.collection,
10896      faceout: getFaceoutValue($quickviewLink, quickviewLinkAttrs),
10897      $returnFocus: getReturnFocus($quickviewLink)
10898    };
10899    quickviewState.quickviewUrl = constructQuickviewURL(quickviewState);
10900    return quickviewState;
10901  }
10902
10903  function setEditModalAttributes(quickviewState) {
10904    quickviewState.$modal.attr('data-orderitemid', quickviewState.orderItemId);
10905    quickviewState.$modal
10906      .addClass(quickviewEditModalClass)
10907      .find(quickviewContentSelectorClass)
10908      .data('sku', quickviewState.sku);
10909  }
10910
10911  function addExchangesModalClassesAndSku(quickviewState) {
10912    if (quickviewState.hasChangeLink) {
10913      quickviewState.$modal.addClass(exchangesEditModalClass);
10914    }
10915    quickviewState.$modal
10916      .addClass(exchangesModalClass)
10917      .find(quickviewContentSelectorClass)
10918      .data('sku', quickviewState.sku);
10919  }
10920  function isMobile() {
10921    return (constants.anf('params.env.isMobile') === 'true');
10922  }
10923  function isShoppingBagPage() {
10924    return $('body').hasClass('cart-view');
10925  }
10926
10927  function setMfeQuickviewData(quickviewState) {
10928    var quickviewType = 'default';
10929    if (quickviewState.isEdit) {
10930      quickviewType = 'edit';
10931    } else if (quickviewState.isExchange) {
10932      quickviewType = 'exchange';
10933    }
10934    var quickviewData = {
10935      productId: quickviewState.productId,
10936      collectionId: quickviewState.collectionId,
10937      categoryId: '',
10938      sku: quickviewState.sku,
10939      faceout: quickviewState.faceout,
10940      type: quickviewType,
10941      orderItemId: quickviewState.orderItemId,
10942      isStylitics: quickviewState.isStylitics,
10943      returnFocus: quickviewState.$returnFocus[0]
10944    };
10945    return quickviewData;
10946  }
10947
10948  function checkForLocalStorageOverrideMFEQuickviewEnabled() {
10949    var isDebugModeEnabled = storage.session.get('debug_mode');
10950    var hasLocalStorageOverrideMFEQuickviewEnabled = storage.session.get('pe-has-quickview-mfe-dev-enabled');
10951    return isDebugModeEnabled && hasLocalStorageOverrideMFEQuickviewEnabled;
10952  }
10953
10954  function openQuickviewModal(quickviewState) {
10955    if (Utils.hasQuickviewMfeEnabled() && (checkForLocalStorageOverrideMFEQuickviewEnabled() || window.digitalData.get('flag.pe-has-quickview-mfe-dev-enabled', false))) {
10956      document.dispatchEvent(new CustomEvent('quickview:mfe:openModal', {detail: setMfeQuickviewData(quickviewState)}));
10957    } else {
10958      dsModal.openModal('product-quickview__modal');
10959      quickviewState.$modal.find('.js-modal-heading').focus();
10960
10961      // DS modal Close event
10962      quickviewState.$modal.on('dsModal:Close', function handleClose(closeEvent) {
10963        if ($(closeEvent.target).is(quickviewState.$modal)) {
10964          quickviewState.$returnFocus.focus();
10965          resetQuickview(quickviewState);
10966          storage.local.remove('storedQuickviewProductId');
10967          quickviewState.$modal.off('dsModal:Close', handleClose);
10968          if (publicMembers.isEditFromMiniBagFn() && !isMobile() && !isShoppingBagPage()) {
10969            var event = new Event('miniBag-toaster:open');
10970            window.dispatchEvent(event);
10971          }
10972        }
10973      });
10974      loadQuickview(quickviewState);
10975    }
10976  }
10977
10978  function resetQuickview(quickviewState) {
10979    // removing classes and content so next opening of quickview is fresh
10980    quickviewState.$modal
10981      .removeClass(quickviewEditModalClass)
10982      .find(quickviewContentSelectorClass).html('');
10983  }
10984
10985  function loadQuickview(quickviewState) {
10986    $.ajax({
10987      url: quickviewState.quickviewUrl
10988    }).done(function success(data) {
10989      setUpQuickview(quickviewState, data);
10990    });
10991  }
10992
10993  function setUpQuickview(quickviewState, data) {
10994    var $quickviewContent = quickviewState.$modal.find(quickviewContentSelectorClass);
10995    $quickviewContent.html(data);
10996    if (quickviewState.$modal.attr('data-open') === 'false') {
10997      $quickviewContent.empty();
10998    } else {
10999      if ($(quickviewSoldOutSelectorClass).length === 0) {
11000        setupInStockQuickview(quickviewState);
11001      } else {
11002        $quickviewContent.fadeIn(500);
11003      }
11004
11005      modal.default().init();
11006    }
11007  }
11008
11009  function setupInStockQuickview(quickviewState) {
11010    if (quickviewState.isEdit) {
11011      setupEditModal(quickviewState);
11012    } else if (quickviewState.isExchange) {
11013      setupExchangeModal(quickviewState);
11014    } else if (quickviewState.isStylitics) {
11015      setupStyliticsClass(quickviewState);
11016    }
11017
11018    triggerQuickviewLoadEvents(quickviewState);
11019    quickviewState.$modal.find(quickviewProductSectionSelector).data('quickviewProductOpened', quickviewState.productId);
11020
11021    quickviewState.$modal.find(detailsSelectorClass).appendTo(quickviewDetailsWrapperHookSelector);
11022    accordion.default().init();
11023  }
11024
11025  function setupEditModal(quickviewState) {
11026    var $button = quickviewState.$modal.find(addToBagButtonSelector);
11027    preSelectProductSize(quickviewState);
11028    statefulButton.default().changeState({button: $button[0], state: 'updateInitial'});
11029    $button.attr('disabled', true);
11030  }
11031
11032  function setupExchangeModal(quickviewState) {
11033    quickviewState.$modal.find(exchangesSaveButtonSelector).attr('disabled', true);
11034    dropDown.default().init();
11035  }
11036
11037  function setupStyliticsClass(quickviewState) {
11038    quickviewState.$modal.addClass(styliticsModalClass);
11039  }
11040
11041  function triggerQuickviewLoadEvents(quickviewState) {
11042    if (quickviewState.$modal.find('.details__modals .details__size-guide-modal').length > 0) {
11043      messageBus.trigger('productSizeCharts:load');
11044    }
11045    messageBus.trigger('productPageImages:load', {URL: quickviewState.quickviewUrl, isQuickview: true});
11046    messageBus.trigger('productPageInfo:load');
11047    messageBus.trigger('productFabricCare:load', true);
11048    featureSwitchHelper.styleFitDesc();
11049  }
11050
11051  function preSelectProductSize(quickviewState) {
11052    var $addToBagForm = quickviewState.$modal.find(addToBagFormSelector);
11053    var skuNum = quickviewState.$modal.find(quickviewContentSelectorClass).data('sku');
11054    var $skuOptions = $addToBagForm.find('.product-page__skus option[value="' + skuNum + '"]');
11055    var	sizePrimary = $skuOptions.data('size-primary');
11056    var	sizeSecondary = $skuOptions.data('size-secondary');
11057
11058    if (typeof sizePrimary !== 'undefined' && (sizePrimary.length > 0 || typeof sizePrimary === 'number')) {
11059      var	sizeInputPrimary = $addToBagForm.find('.product-sizes input[value="' + sizePrimary + '"]');
11060      if (sizeInputPrimary.length > 0) {
11061        sizeInputPrimary.prop('checked', true);
11062        sizeInputPrimary.closest(definingAttrSelectorClass).addClass('selected');
11063      }
11064    }
11065
11066    if (typeof sizeSecondary !== 'undefined' && (sizePrimary.length > 0 || typeof sizePrimary === 'number')) {
11067      var	sizeInputSecondary = $addToBagForm.find('.product-sizes input[value="' + sizeSecondary + '"]');
11068      if (sizeInputSecondary.length > 0) {
11069        sizeInputSecondary.prop('checked', true);
11070        sizeInputSecondary.closest(definingAttrSelectorClass).addClass('selected');
11071      }
11072    }
11073  }
11074
11075  function toggleUpdateButtonState(e, data) {
11076    var $editQuickview = $(quickviewEditModalSelector);
11077    if ($editQuickview.length > 0) {
11078      var currentSKU = $editQuickview.find(quickviewContentSelectorClass).data('sku');
11079      var newSKU = data.sku;
11080      var disabledValue = newSKU && currentSKU && (newSKU !== currentSKU) ? false : 'disabled';
11081      $editQuickview.find(addToBagButtonSelector).attr('disabled', disabledValue);
11082    }
11083  }
11084
11085  function updateViewFullProductLink(e, link) {
11086    var $fullProductLinkSelector = $(fullProductLinkSelector);
11087    var analyticsParams = $fullProductLinkSelector.parent().attr('data-analytics-params');
11088    $(fullProductLinkSelector).attr('href', link + analyticsParams);
11089  }
11090
11091  function storeQuickviewState() {
11092    var initialProductId = $(quickviewProductSectionSelector).data('quickviewProductOpened');
11093    storage.local.set('storedQuickviewProductId', initialProductId);
11094  }
11095
11096  function checkForStoredQuickviewState() {
11097    var storedQuickviewProductId = storage.local.get('storedQuickviewProductId');
11098    var $quickviewButton = $(quickviewButtonSelectorClass + '[data-productid="' + storedQuickviewProductId + '"]');
11099    if ($quickviewButton.length > 0) {
11100      $quickviewButton.click();
11101    }
11102  }
11103
11104  var publicMembers = {
11105    initQuickviewFromData: initQuickviewFromData,
11106    'listen': function listen() {
11107      messageBus.on('mysaves:quickviewInitialize', initializeQuickviewFromMySaves);
11108      messageBus.on('quickview:updateFullProductLink', updateViewFullProductLink);
11109      messageBus.on('productSize:skuSelected', toggleUpdateButtonState);
11110      messageBus.on('quickviewLifecycle:complete', fireDelayedQuickviewEvents);
11111      messageBus.on('quickviewLogin:clicked', storeQuickviewState);
11112      messageBus.on('quickviewModules:loaded', checkForStoredQuickviewState);
11113
11114      window.addEventListener('quickview:openModal', initQuickviewFromData);
11115      window.addEventListener('quickview:openEditModalOnPDP', initializeEditModalOnPDP);
11116    },
11117
11118    'bindEvents': function bindEvents() {
11119      $(document).on('click', shoppingCartQVSelectorClass, initializeQuickviewFromCart);
11120      $(document).on('click', quickviewButtonSelectorClass, initializeQuickviewFromClick);
11121
11122      // ACR-14504 MFE MiniBag initialize Quick View Event
11123      window.addEventListener('initializeQuickViewFromMiniBag', function initializeQuickviewFromMiniBag(e) {
11124        e.preventDefault();
11125        var divRef = e.quickViewLinkAttrs.pdpDivElement;
11126        initializeQuickview($(divRef));
11127        var quickviewLinkAttrs = $(divRef).data();
11128        $(window).trigger('analytics.cartItemEdited', {
11129          'collectionId': quickviewLinkAttrs.collectionId,
11130          'longSku': quickviewLinkAttrs.longSku,
11131          'shortSku': quickviewLinkAttrs.sku,
11132          'inventoryAvailability': quickviewLinkAttrs.inventoryAvailability
11133        });
11134        isEditFromMiniBag = true;
11135      }, false);
11136    },
11137    'isEditFromMiniBagFn': function isEditFromMiniBagFn() {
11138      return isEditFromMiniBag;
11139    }
11140  };
11141
11142  return publicMembers;
11143});
11144
11145/*!
11146	Zoom 1.7.18
11147	license: MIT
11148	http://www.jacklmoore.com/zoom
11149*/
11150(function ($) {
11151	var defaults = {
11152		url: false,
11153		callback: false,
11154		target: false,
11155		duration: 120,
11156		on: 'mouseover', // other options: grab, click, toggle
11157		touch: true, // enables a touch fallback
11158		onZoomIn: false,
11159		onZoomOut: false,
11160		magnify: 1
11161	};
11162
11163	// Core Zoom Logic, independent of event listeners.
11164	$.zoom = function(target, source, img, magnify) {
11165		var targetHeight,
11166			targetWidth,
11167			sourceHeight,
11168			sourceWidth,
11169			xRatio,
11170			yRatio,
11171			offset,
11172			$target = $(target),
11173			position = $target.css('position'),
11174			$source = $(source);
11175
11176		// The parent element needs positioning so that the zoomed element can be correctly positioned within.
11177		target.style.position = /(absolute|fixed)/.test(position) ? position : 'relative';
11178		target.style.overflow = 'hidden';
11179		img.style.width = img.style.height = '';
11180
11181		$(img)
11182			.addClass('zoomImg')
11183			.css({
11184				position: 'absolute',
11185				top: 0,
11186				left: 0,
11187				opacity: 0,
11188				width: img.width * magnify,
11189				height: img.height * magnify,
11190				border: 'none',
11191				maxWidth: 'none',
11192				maxHeight: 'none'
11193			})
11194			.appendTo(target);
11195
11196		return {
11197			init: function() {
11198				targetWidth = $target.outerWidth();
11199				targetHeight = $target.outerHeight();
11200
11201				if (source === target) {
11202					sourceWidth = targetWidth;
11203					sourceHeight = targetHeight;
11204				} else {
11205					sourceWidth = $source.outerWidth();
11206					sourceHeight = $source.outerHeight();
11207				}
11208
11209				xRatio = (img.width - targetWidth) / sourceWidth;
11210				yRatio = (img.height - targetHeight) / sourceHeight;
11211
11212				offset = $source.offset();
11213			},
11214			move: function (e) {
11215				var left = (e.pageX - offset.left),
11216					top = (e.pageY - offset.top);
11217
11218				top = Math.max(Math.min(top, sourceHeight), 0);
11219				left = Math.max(Math.min(left, sourceWidth), 0);
11220
11221				img.style.left = (left * -xRatio) + 'px';
11222				img.style.top = (top * -yRatio) + 'px';
11223			}
11224		};
11225	};
11226
11227	$.fn.zoom = function (options) {
11228		return this.each(function () {
11229			var
11230			settings = $.extend({}, defaults, options || {}),
11231			//target will display the zoomed image
11232			target = settings.target && $(settings.target)[0] || this,
11233			//source will provide zoom location info (thumbnail)
11234			source = this,
11235			$source = $(source),
11236			img = document.createElement('img'),
11237			$img = $(img),
11238			mousemove = 'mousemove.zoom',
11239			clicked = false,
11240			touched = false;
11241
11242			// If a url wasn't specified, look for an image element.
11243			if (!settings.url) {
11244				var srcElement = source.querySelector('img');
11245				if (srcElement) {
11246					settings.url = srcElement.getAttribute('data-src') || srcElement.currentSrc || srcElement.src;
11247				}
11248				if (!settings.url) {
11249					return;
11250				}
11251			}
11252
11253			$source.one('zoom.destroy', function(position, overflow){
11254				$source.off(".zoom");
11255				target.style.position = position;
11256				target.style.overflow = overflow;
11257				img.onload = null;
11258				$img.remove();
11259			}.bind(this, target.style.position, target.style.overflow));
11260
11261			img.onload = function () {
11262				var zoom = $.zoom(target, source, img, settings.magnify);
11263
11264				function start(e) {
11265					zoom.init();
11266					zoom.move(e);
11267
11268					// Skip the fade-in for IE8 and lower since it chokes on fading-in
11269					// and changing position based on mousemovement at the same time.
11270					$img.stop()
11271					.fadeTo($.support.opacity ? settings.duration : 0, 1, $.isFunction(settings.onZoomIn) ? settings.onZoomIn.call(img) : false);
11272				}
11273
11274				function stop() {
11275					$img.stop()
11276					.fadeTo(settings.duration, 0, $.isFunction(settings.onZoomOut) ? settings.onZoomOut.call(img) : false);
11277				}
11278
11279				// Mouse events
11280				if (settings.on === 'grab') {
11281					$source
11282						.on('mousedown.zoom',
11283							function (e) {
11284								if (e.which === 1) {
11285									$(document).one('mouseup.zoom',
11286										function () {
11287											stop();
11288
11289											$(document).off(mousemove, zoom.move);
11290										}
11291									);
11292
11293									start(e);
11294
11295									$(document).on(mousemove, zoom.move);
11296
11297									e.preventDefault();
11298								}
11299							}
11300						);
11301				} else if (settings.on === 'click') {
11302					$source.on('click.zoom',
11303						function (e) {
11304							if (clicked) {
11305								// bubble the event up to the document to trigger the unbind.
11306								return;
11307							} else {
11308								clicked = true;
11309								start(e);
11310								$(document).on(mousemove, zoom.move);
11311								$(document).one('click.zoom',
11312									function () {
11313										stop();
11314										clicked = false;
11315										$(document).off(mousemove, zoom.move);
11316									}
11317								);
11318								return false;
11319							}
11320						}
11321					);
11322				} else if (settings.on === 'toggle') {
11323					$source.on('click.zoom',
11324						function (e) {
11325							if (clicked) {
11326								stop();
11327							} else {
11328								start(e);
11329							}
11330							clicked = !clicked;
11331						}
11332					);
11333				} else if (settings.on === 'mouseover') {
11334					zoom.init(); // Preemptively call init because IE7 will fire the mousemove handler before the hover handler.
11335
11336					$source
11337						.on('mouseenter.zoom', start)
11338						.on('mouseleave.zoom', stop)
11339						.on(mousemove, zoom.move);
11340				}
11341
11342				// Touch fallback
11343				if (settings.touch) {
11344					$source
11345						.on('touchstart.zoom', function (e) {
11346							e.preventDefault();
11347							if (touched) {
11348								touched = false;
11349								stop();
11350							} else {
11351								touched = true;
11352								start( e.originalEvent.touches[0] || e.originalEvent.changedTouches[0] );
11353							}
11354						})
11355						.on('touchmove.zoom', function (e) {
11356							e.preventDefault();
11357							zoom.move( e.originalEvent.touches[0] || e.originalEvent.changedTouches[0] );
11358						})
11359						.on('touchend.zoom', function (e) {
11360							e.preventDefault();
11361							if (touched) {
11362								touched = false;
11363								stop();
11364							}
11365						});
11366				}
11367
11368				if ($.isFunction(settings.callback)) {
11369					settings.callback.call(img);
11370				}
11371			};
11372
11373			img.src = settings.url;
11374		});
11375	};
11376
11377	$.fn.zoom.defaults = defaults;
11378}(window.jQuery));
11379
11380redesign.define("jquery_zoom", function(){});
11381
11382redesign.define('productModules/product/quickview/quickviewImages',[
11383  'coreClass/ANFImage',
11384  'jquery_zoom'
11385], function ProductQuickviewImages(ANFImage) {
11386  'use strict';
11387
11388  var quickviewNonUGCMainImageWapperSelectorClass = '.product-main-images__image:not(.product-main-images__image--ugc)';
11389  var quickviewModalSelectorClass = '.product-quickview__modal';
11390  var tabFocusClass = 'tab-focused';
11391
11392  var isClick = null;
11393  var isMobile = ANF.params.env.isMobile;
11394  var magnifyWidth = 1200;
11395
11396  var messageBus = $(ANF);
11397
11398  function handleZoomImageBlur(e) {
11399    var image = $(e.currentTarget).removeClass(tabFocusClass);
11400    image.scrollTop(0);
11401    image.scrollLeft(0);
11402  }
11403
11404  function setupMagnifyQuickviewImage(e, productSection) {
11405    if (isMobile === 'true') {
11406      return;
11407    }
11408
11409    var getSetZoomAltText = function getSetZoomAltText(alt) {
11410      return function setZoomAltText() {
11411        $(this).attr('alt', alt);
11412      };
11413    };
11414
11415    $(productSection).find(quickviewNonUGCMainImageWapperSelectorClass).each(function iterateProductImages(_i, imageContainer) {
11416      var $imageContainer = $(imageContainer);
11417      var $productImage = $imageContainer.find('img');
11418      var altText = $productImage.attr('alt');
11419
11420      var magnifyImageSrc = ANFImage.instance()
11421        .setImageName($productImage.data().imageId)
11422        .setWidth(magnifyWidth)
11423        .url;
11424
11425      $imageContainer.zoom({
11426        callback: getSetZoomAltText(altText),
11427        duration: 300, // Fade-in blocked for lte IE
11428        icon: false,
11429        url: magnifyImageSrc
11430      });
11431
11432      $imageContainer.on('focusin', zoomFocus);
11433      $imageContainer.on('focusout', handleZoomImageBlur);
11434    });
11435  }
11436
11437  function zoomFocus(e) {
11438    setTimeout( function setTimeout() {
11439      if (!isClick) {
11440        var image = $(e.target);
11441        image.addClass(tabFocusClass);
11442        image.scrollTop(0);
11443        image.scrollLeft(0);
11444        image.find('.zoomImg').css({'top': 0, 'left': 0});
11445      }
11446    }, 150);
11447  }
11448
11449  var publicMembers = {
11450    // This function should only be called for setting private module vars during unit tests. P.S. I hate this.
11451    unitTestSetup: function unitTestSetup(obj) {
11452      isMobile = obj.isMobile;
11453      magnifyWidth = obj.magnifyWidth;
11454    },
11455
11456    'listen': function listen() {
11457      messageBus.on('quickviewImages:mainImageLoaded', setupMagnifyQuickviewImage);
11458    },
11459
11460    'bindEvents': function bindEvents() {
11461      $(document).on('click', quickviewModalSelectorClass, function click() {isClick = true; });
11462      $(document).on('keydown', quickviewModalSelectorClass, function keydown() {isClick = false; });
11463    }
11464  };
11465  return publicMembers;
11466});
11467
11468redesign.define('productModules/product/quickview/quickviewLifecycle',[], function QuickviewLifecycle() {
11469  'use strict';
11470
11471  var quickviewButtonSelectorClass  = '.product-quickview__button, button.js-pc-edit-button';
11472  var shoppingCartQVImageSelector = '#checkout-cart .product-image:not(.gift-card-image-container) + .product-image-overlay';
11473  var quickviewModalSelectorClass = '.product-quickview__modal';
11474  var soldOutSelector = '.product-quickview__sold-out';
11475  var quickviewURLMatcher = 'QuickView';
11476
11477  var messageBus = $(ANF);
11478
11479  var quickviewCompleteEvents = [];
11480  var $quickviewModal;
11481
11482  function onAjaxComplete(event, request, settings) {
11483    if (settings.url.indexOf(quickviewURLMatcher) !== -1) {
11484      messageBus.trigger('quickviewLifecycle:postAjax', [$quickviewModal]);
11485
11486      if ($quickviewModal.find(soldOutSelector).length) {
11487        messageBus.trigger('quickviewLifecycle:complete', [$quickviewModal]);
11488      }
11489    }
11490  }
11491
11492  function onAjaxSend(event, request, settings) {
11493    if (settings.url.indexOf(quickviewURLMatcher) !== -1) {
11494      messageBus.trigger('quickviewLifecycle:preAjax', [$quickviewModal]);
11495    }
11496  }
11497
11498  function onCompleteEvent(event) {
11499    quickviewCompleteEvents.push(event);
11500
11501    if (quickviewCompleteEvents.length > 1) {
11502      messageBus.trigger('quickviewLifecycle:complete', [$quickviewModal]);
11503      document.dispatchEvent(new CustomEvent('quickview:recs:openModal'));
11504    }
11505  }
11506
11507  function onQuickviewClose(event) {
11508    if ($(event.target).is($quickviewModal)) {
11509      messageBus.trigger('quickviewLifecycle:close', [$quickviewModal]);
11510
11511      $(document).off('ajaxSend', onAjaxSend);
11512      $(document).off('ajaxComplete', onAjaxComplete);
11513      $quickviewModal.off('dsModal:Close');
11514
11515      quickviewCompleteEvents = [];
11516    }
11517  }
11518
11519  function onQuickviewOpen() {
11520    $quickviewModal = $(quickviewModalSelectorClass);
11521    messageBus.trigger('quickviewLifecycle:open', [$quickviewModal]);
11522
11523    $(document).on('ajaxSend', onAjaxSend);
11524    $(document).on('ajaxComplete', onAjaxComplete);
11525
11526    $quickviewModal.on('dsModal:Close', onQuickviewClose);
11527
11528    messageBus.one('thumbnailSlider:InitComplete', onCompleteEvent);
11529    messageBus.one('quickviewImages:mainImageLoaded', onCompleteEvent);
11530  }
11531
11532  return {
11533    onQuickviewOpen: onQuickviewOpen,
11534    bindEvents: function bindEvents() {
11535      $(document).on('click', quickviewButtonSelectorClass, onQuickviewOpen);
11536      $(document).on('click', shoppingCartQVImageSelector, onQuickviewOpen);
11537    },
11538    listen: function listen() {
11539      messageBus.on('mysaves:quickviewInitialize', onQuickviewOpen);
11540      window.addEventListener('quickview:openModal', onQuickviewOpen);
11541      window.addEventListener('quickview:openEditModalOnPDP', onQuickviewOpen);
11542    }
11543  };
11544});
11545
11546redesign.define('productModules/product/quickview/quickviewPreload',[
11547  'productServices/product/template',
11548  'productModules/helpers/curry',
11549  'anfUtil/testFramework',
11550  'coreClass/ANFImage',
11551  'productModules/helpers/Utils'
11552], function QuickviewPreload(template, curry, test, ANFImage, Utils) {
11553  'use strict';
11554
11555  var quickviewButtonSelector  = '.product-quickview__button, button.js-pc-edit-button';
11556  var shoppingCartQVImageSelector = '#checkout-cart .product-image:not(.gift-card-image-container) + .product-image-overlay';
11557
11558  var quickviewModalSelector = '.product-quickview__modal';
11559  var quickviewPreloadContentSelector = '.product-quickview__preload-content';
11560
11561  var partialQuickviewTemplate = curry(template.renderTemplate)('quickviewPreload');
11562
11563  var messageBus = $(ANF);
11564
11565  function initPreload(event) {
11566    var $button = $(event.currentTarget);
11567    var $container = $button.closest('.product-template');
11568
11569    // On recommendations, the product container is actually nested under the button
11570    // On shop this look, the product container is product-card, not product-template
11571    // On stylitics outfitting and the grid mixer, the product container is the button :mind_blown:
11572    if (!$container.length) {
11573      if ($button.hasClass('stylitics-widget-item-container')) {
11574        $container = $button;
11575        var styliticsPreloadData = gatherPreloadDataForStylitics($container);
11576      } else if ($button.hasClass('grid-mixer-button')) {
11577        $container = $button;
11578        var gridMixerPreloadData = gatherPreloadDataForGridMixer($container);
11579      } else {
11580        $container = $button.find('.product-template, .product-card');
11581      }
11582    }
11583
11584    // If there's no recognized container to pull image/data from, just revert to original qv
11585    if ($container.length) {
11586      // check to see if the stylitics object has been compiled. if not call it with the contaner.
11587      var preloadDataObj = styliticsPreloadData || gridMixerPreloadData || collectProductData($container, $button);
11588      renderPreload(preloadDataObj);
11589    } else {
11590      teardownPreload();
11591    }
11592  }
11593
11594  function initPreloadFromMySaves(event, data) {
11595    initPreload(data);
11596  }
11597
11598  function initPreloadFromData(event) {
11599    var data = event.detail;
11600    var preloadImage = ANFImage.instance()
11601      .setImageName(data.imageId)
11602      .setWidth(400)
11603      .url;
11604
11605    var preloadImageElement = document.createElement('img');
11606    preloadImageElement.setAttribute('src', preloadImage);
11607    preloadImageElement.setAttribute('class', 'product-card__image');
11608
11609    var preloadDataObj = $.extend(data, {
11610      img: preloadImageElement.outerHTML,
11611      qtyLabel: Utils.getANFObject().messaging.product.GLB_QTY,
11612      atbLabel: Utils.getANFObject().messaging.product.GLB_ADDTOBAG
11613    });
11614
11615    renderPreload(preloadDataObj);
11616  }
11617
11618  function collectProductData($container, $button) {
11619    var img = $container.find('img');
11620    var shortDescription = $container.find('.short-description, .product-card__description');
11621    var $productName = $container.find('.product-name');
11622    var $productPrice = $container.find('.product-price');
11623    var productBrand = $button.data('product-brand') || ANF.params.urls.STATIC_DIR;
11624
11625    // Make sure we don't add a screen reader version of this text, usually on shopping cart
11626    $productName = $productName.children().length < 2 ? $productName : $productName.children().not('.screen-reader-text');
11627
11628    // Some qv link containers don't match the right size of the qv price label
11629    $productPrice.find('.product-price-font-size').addClass('ds-override');
11630
11631    return {
11632      img: test.type.defined(img[0], false) ? img[0].outerHTML : '',
11633      shortDescription: shortDescription.text(),
11634      productBrand: productBrand,
11635      productName: $productName.text(),
11636      productPrice: test.type.defined($productPrice[0], false) ? $productPrice[0].outerHTML : '',
11637      qtyLabel: ANF.messaging.product.GLB_QTY,
11638      atbLabel: ANF.messaging.product.GLB_ADDTOBAG
11639    };
11640  }
11641
11642  function gatherPreloadDataForStylitics($container) {
11643    // stylitics injects line break characters... lol i know.
11644    var productName = $container.find('.stylitics-widget-item-name a').text().trim() || '';
11645    var productPrice = $container.find('.stylitics-widget-item-price').text().trim() || '';
11646    var imageSource = ANFImage.instance()
11647      .setImageName($container.data('item-remote-id') + '_prod1')
11648      .setWidth(400)
11649      .url;
11650
11651    var preloadImageElement = document.createElement('img');
11652    preloadImageElement.setAttribute('src', imageSource);
11653    preloadImageElement.setAttribute('class', 'product-card__image');
11654
11655    return {
11656      img: preloadImageElement.outerHTML,
11657      productName: productName,
11658      productPrice: productPrice,
11659      qtyLabel: ANF.messaging.product.GLB_QTY,
11660      atbLabel: ANF.messaging.product.GLB_ADDTOBAG
11661    };
11662  }
11663
11664  function gatherPreloadDataForGridMixer($container) {
11665    var img = $container.find('img');
11666    var shortDescription = $container.data('shortDesc');
11667    var productName = $container.data('productName');
11668    var productBrand = $container.data('brand') || ANF.params.urls.STATIC_DIR;
11669
11670    /*
11671      Not populating "productPrice" for the grid mixer's preload data because we don't have the original product card
11672      to source the price from (there is extensive logic on the card to determine what the displayed price looks like
11673      for various pricing scenarios, and duplicating it here just for the sake of preload display would be overkill)
11674    */
11675
11676    return {
11677      img: test.type.defined(img[0], false) ? img[0].outerHTML : '',
11678      shortDescription: shortDescription,
11679      productBrand: productBrand,
11680      productName: productName,
11681      productPrice: '',
11682      qtyLabel: ANF.messaging.product.GLB_QTY,
11683      atbLabel: ANF.messaging.product.GLB_ADDTOBAG
11684    };
11685  }
11686
11687  function crossfadePreload(event, $modal) {
11688    $modal.addClass('crossfade');
11689  }
11690
11691  function renderPreload(data) {
11692    $(quickviewPreloadContentSelector).html(partialQuickviewTemplate(data));
11693  }
11694
11695  function teardownPreload(event, $modal) {
11696    var $modalCopy = $modal ? $modal : $(quickviewModalSelector);
11697
11698    $modalCopy.find(quickviewPreloadContentSelector).html('');
11699    $modalCopy.removeClass('crossfade');
11700  }
11701
11702  var publicMembers = {
11703    initPreloadFromData: initPreloadFromData,
11704    bindEvents: function bindEvents() {
11705      $(document).on('click', quickviewButtonSelector, initPreload);
11706      $(document).on('click', shoppingCartQVImageSelector, initPreload);
11707    },
11708    listen: function listen() {
11709      messageBus.on('mysaves:quickviewInitialize', initPreloadFromMySaves);
11710      messageBus.on('quickviewLifecycle:complete', crossfadePreload);
11711      messageBus.on('quickviewLifecycle:close', teardownPreload);
11712
11713      window.addEventListener('quickview:openModal', initPreloadFromData);
11714      window.addEventListener('quickview:openEditModalOnPDP', initPreloadFromData);
11715    }
11716  };
11717
11718  return publicMembers;
11719});
11720
11721redesign.define('productSections/product/quickviewModules',[
11722  'coreSectionHelpers',
11723  'productModules/product/quickview/quickview',
11724  'productModules/helpers/analyticsHelper',
11725  'productModules/product/quickview/quickviewImages',
11726  'productModules/product/quickview/quickviewLifecycle',
11727  'productModules/product/quickview/quickviewPreload'
11728], function QuickviewModules(coreSectionHelpers, quickview, analyticsHelper, quickviewImages, quickviewLifecycle, quickviewPreload) {
11729  'use strict';
11730
11731  var privateMembers = {
11732    'DEFAULT_MODULES': {
11733      'quickview': quickview,
11734      'quickviewImages': quickviewImages,
11735      'quickviewLifecycle': quickviewLifecycle,
11736      'quickviewPreload': quickviewPreload,
11737      'analyticsHelper': analyticsHelper
11738    },
11739    'GLOBAL_SCOPE': '',
11740    'MODULES': {},
11741    'parentPage': ''
11742  };
11743
11744  return function scope(settings) {
11745    privateMembers.GLOBAL_SCOPE	= settings.scope;
11746    privateMembers.parentPage = settings.parentPage;
11747    privateMembers.MODULES = privateMembers.DEFAULT_MODULES;
11748
11749    if (typeof settings.modules === 'object') {
11750      $.extend(true, privateMembers.MODULES, settings.modules);
11751    }
11752
11753    var messageBus = $(ANF);
11754
11755    return {
11756      'init': function init() {
11757        coreSectionHelpers.init({
11758          'modules': privateMembers.MODULES,
11759          'scope': privateMembers.GLOBAL_SCOPE
11760        });
11761
11762        messageBus.trigger('quickviewModules:loaded');
11763      }
11764    };
11765  };
11766});
11767
11768redesign.define('productPartial/pdp_preferredStore',['handlebars','dsPartial/selector','dsPartial/logo','wcsHelper/i18n','dsPartial/omni-info'], function(Handlebars) {
11769
11770this["ANF"] = this["ANF"] || {};
11771this["ANF"]["templates"] = this["ANF"]["templates"] || {};
11772
11773Handlebars.registerPartial("pdp_preferredStore", this["ANF"]["templates"]["pdp_preferredStore"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
11774    var stack1, alias1=container.lambda, alias2=container.escapeExpression, alias3=depth0 != null ? depth0 : (container.nullContext || {});
11775
11776  return "      <span class=\"selector-map-icon\" aria-hidden=\"true\"></span>\n      <span class=\"description\" data-brand=\""
11777    + alias2(alias1((depth0 != null ? depth0.brand : depth0), depth0))
11778    + "\">\n"
11779    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.showBranding : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11780    + "        <span>"
11781    + alias2(alias1((depth0 != null ? depth0.storeName : depth0), depth0))
11782    + "</span>\n"
11783    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.showBranding : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11784    + "      </span>\n";
11785},"2":function(container,depth0,helpers,partials,data) {
11786    var stack1;
11787
11788  return ((stack1 = container.invokePartial(partials.logo,depth0,{"name":"logo","hash":{"icon-aria-label":(depth0 != null ? depth0.brandName : depth0),"type":"horizontal","brand":(depth0 != null ? depth0.brand : depth0)},"data":data,"indent":"          ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
11789},"4":function(container,depth0,helpers,partials,data) {
11790    return "          <span class=\"screen-reader-text\">"
11791    + container.escapeExpression(container.lambda((depth0 != null ? depth0.checkStoreAvailability : depth0), depth0))
11792    + "</span>\n";
11793},"6":function(container,depth0,helpers,partials,data) {
11794    var stack1;
11795
11796  return "          <div class=\"preferred-store-module__choose-size-message item-availability-message\">\n"
11797    + ((stack1 = container.invokePartial(partials["omni-info"],(depth0 != null ? depth0.selectSizeCardInfo : depth0),{"name":"omni-info","data":data,"indent":"            ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
11798    + "          </div>\n";
11799},"8":function(container,depth0,helpers,partials,data) {
11800    var stack1;
11801
11802  return "          <div class=\"preferred-store-module-info item-availability-message\">\n            <div class=\"preferred-store-module__store-available preferred-store-module__inventory-status\">\n"
11803    + ((stack1 = container.invokePartial(partials["omni-info"],(depth0 != null ? depth0.isAvailableCardInfo : depth0),{"name":"omni-info","data":data,"indent":"              ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
11804    + "            </div>\n          </div>\n";
11805},"10":function(container,depth0,helpers,partials,data) {
11806    var stack1;
11807
11808  return "          <div class=\"preferred-store-module-info item-availability-message\">\n            <div class=\"preferred-store-module__store-not-available preferred-store-module__inventory-status not-available\">\n"
11809    + ((stack1 = container.invokePartial(partials["omni-info"],(depth0 != null ? depth0.noStockCardInfo : depth0),{"name":"omni-info","data":data,"indent":"              ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
11810    + "            </div>\n          </div>\n";
11811},"12":function(container,depth0,helpers,partials,data) {
11812    var stack1;
11813
11814  return "          <div class=\"preferred-store-module-info item-availability-message\">\n            <div class=\"preferred-store-module__store-available preferred-store-module__inventory-status\">\n"
11815    + ((stack1 = container.invokePartial(partials["omni-info"],(depth0 != null ? depth0.popinsCardInfo : depth0),{"name":"omni-info","data":data,"indent":"              ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
11816    + "            </div>\n          </div>\n";
11817},"14":function(container,depth0,helpers,partials,data) {
11818    var stack1;
11819
11820  return "          <div class=\"preferred-store-module-info item-availability-message\">\n            <div class=\"preferred-store-module__store-not-available preferred-store-module__inventory-status not-available\">\n"
11821    + ((stack1 = container.invokePartial(partials["omni-info"],(depth0 != null ? depth0.noPickupCardInfo : depth0),{"name":"omni-info","data":data,"indent":"              ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
11822    + "            </div>\n          </div>\n";
11823},"16":function(container,depth0,helpers,partials,data) {
11824    var stack1;
11825
11826  return "          <div class=\"preferred-store-module-info item-availability-message\">\n            <div class=\"preferred-store-module__store-not-available preferred-store-module__inventory-status not-available\">\n"
11827    + ((stack1 = container.invokePartial(partials["omni-info"],(depth0 != null ? depth0.notAvailableCardInfo : depth0),{"name":"omni-info","data":data,"indent":"              ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
11828    + "            </div>\n          </div>\n";
11829},"18":function(container,depth0,helpers,partials,data) {
11830    return "          <p class=\"store-messaging item-availability-message\">"
11831    + container.escapeExpression(container.lambda((depth0 != null ? depth0.storeMessage : depth0), depth0))
11832    + "</p>\n";
11833},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
11834    var stack1, alias1=container.lambda, alias2=container.escapeExpression, alias3=depth0 != null ? depth0 : (container.nullContext || {});
11835
11836  return "<div class=\"preferred-store-module__template\">\n  <div class=\"preferred-store-module\" data-storeid=\""
11837    + alias2(alias1((depth0 != null ? depth0.storeID : depth0), depth0))
11838    + "\" data-store-zip=\""
11839    + alias2(alias1((depth0 != null ? depth0.zipCode : depth0), depth0))
11840    + "\" data-store-city=\""
11841    + alias2(alias1((depth0 != null ? depth0.city : depth0), depth0))
11842    + "\">\n"
11843    + ((stack1 = container.invokePartial(partials.selector,depth0,{"name":"selector","hash":{"data-
11843prop":"data-modal='find-store-form__modal-wrapper'","class-list":"js-open-modal find-store-form__modal-wrapper"},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
11844    + "      <div class=\"preferred-store-module__content\">\n        <div class=\"preferred-store-module__popins-error\" data-property=\"GLB_PREFERRED_STORE_ITEM_ERROR\">\n          "
11845    + ((stack1 = helpers.i18n.call(alias3,"storelocator.GLB_PREFERRED_STORE_ITEM_ERROR",{"name":"i18n","hash":{},"data":data})) != null ? stack1 : "")
11846    + "\n        </div>\n\n"
11847    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.isSelectSizeMsg : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11848    + "\n"
11849    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.isAvailableInStore : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11850    + "\n"
11851    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.isNotInStock : depth0),{"name":"if","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11852    + "\n"
11853    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.isStorePopinsEligible : depth0),{"name":"if","hash":{},"fn":container.program(12, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11854    + "\n"
11855    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.isNotAvailableForPickup : depth0),{"name":"if","hash":{},"fn":container.program(14, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11856    + "\n"
11857    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.isNotAvailableAtLocation : depth0),{"name":"if","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11858    + "\n"
11859    + ((stack1 = helpers["if"].call(alias3,(depth0 != null ? depth0.storeMessage : depth0),{"name":"if","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
11860    + "      </div>\n  </div>\n</div>\n";
11861},"usePartial":true,"useData":true}));
11862
11863return this["ANF"];
11864
11865});
11866redesign.define('productModules/popins/preferredStore',[
11867  'anfUtil/testFramework',
11868  'coreServices/findastore/productAvailability',
11869  'coreModules/brandedPage',
11870  'productServices/product/brandMap',
11871  'anfcore/components/modal',
11872  'productModules/helpers/Utils',
11873  'jsCookie',
11874  'productPartial/pdp_preferredStore',
11875  'coreServices/geo/core'
11876], function PreferredStore(
11877  test,
11878  productAvailability,
11879  brandedPage,
11880  brandMap,
11881  modal,
11882  Utils,
11883  cookies,
11884  productPartialPdpPreferredStore,
11885  GeoCore
11886) {
11887  'use strict';
11888
11889
11890  var productSectionSelector = '.product-page-v2-modules';
11891  var availabilityWrapper = '.product__actions--availability-wrapper';
11892  var changeButton = '.preferred-store-module .selector, .preferred-store-module__change-store';
11893  var preferredStoreWidget = '.preferred-store-module';
11894  var selectedSizeVariant1 = '.product-sizes__select option:selected';
11895  var selectedSizeVariant2 = '.product-details__size-select option:selected';
11896  var selectedSizeVariant3 = '.size-select option:selected';
11897  var skuSelect = '.product-page__skus';
11898  var reserveError = '.preferred-store-module__popins-error';
11899  var preferredStoreBadgeSelectorClass = '.preferred-store-module__badge';
11900  var isAvailable = '.defining-attribute-value.selected';
11901  var catalogProductSelectorClass = '.catalog-product';
11902  var productViewSelectorClass = '.product-view';
11903  var productPageV2SelectorClass = '.product-page-v2';
11904  var preferredStoreDefaultClass = 'preferred-store-module__default-state';
11905  var itemAvailabilitySelectorClass = '.item-availability-message';
11906
11907  var storeObj = {};
11908  var scopeData = {};
11909
11910  function getPhysicalStore() {
11911    GeoCore.getService('default');
11912    // get from uPref cookie
11913    brandedPage.getStoreFromCookie()
11914      .done(function done(data) {
11915        storeObj = data;
11916        widgetSetup();
11917      })
11918      .fail(function fail() {
11919        // get from preferred store
11920        brandedPage.getStoreFromPreferredStore()
11921          .done(function failDone(data) {
11922            storeObj = data;
11923            widgetSetup();
11924          })
11925          .fail(function failFail() {
11926            // get from geolocation
11927            brandedPage.getGeolocatedStore()
11928              .done(function failFailDone(data) {
11929                storeObj = data;
11930                widgetSetup();
11931              })
11932              .fail(function failFailFail() {
11933                storeObj = {};
11934                widgetSetup();
11935              });
11936          });
11937      });
11938  }
11939
11940  // eslint-disable-next-line consistent-return
11941  function widgetSetup() {
11942    var dataObj = {};
11943    // In order to maintain focus after closing modal & re-rendering wrapper
11944    var selectorHasFocus = $(availabilityWrapper).find('.selector').is(':focus');
11945
11946    // This length used to be fetched in privateMembers, but now that this element is
11947    // rendered on client-side after an API call, it wouldn't exist when this check ran
11948    // So, we look in the DOM for this length HERE, instead of in privateMembers
11949    // This is kind of a hack, but at least it's just tweaking an existing hack, not
11950    // creating a new one.
11951    if ($('.ds-rs-facet-tile-location__wrapper').length) {
11952      return false;
11953    }
11954
11955    if (test.string.not.empty(storeObj.storeId, false)) {
11956      $(availabilityWrapper).html(productPartialPdpPreferredStore.templates.pdp_preferredStore(buildPreferredWidgetObj()));
11957
11958      updateProductAvailabilityHandler();
11959
11960      $(preferredStoreBadgeSelectorClass).addClass(storeObj.brand);
11961    } else {
11962      // set up the defaults
11963      dataObj.isSelectSizeMsg = false; // default to false cuz it should only be seen when geo located
11964      dataObj.storeName = ANF.messaging.catalogV2.defaultStoreAvailability; // set default 'store name'
11965      dataObj.defaultClass = preferredStoreDefaultClass; // set class for 'store name' styling
11966      dataObj.showBranding = false;
11967
11968      $(availabilityWrapper).html(productPartialPdpPreferredStore.templates.pdp_preferredStore(dataObj));
11969    }
11970
11971    if (selectorHasFocus) {
11972      $(availabilityWrapper).find('.selector').focus();
11973    }
11974    $(availabilityWrapper).fadeIn();
11975    reInitializeModal();
11976  }
11977
11978  function showPreferredStoreModal(e) {
11979    e.preventDefault();
11980    var shortSku = $(selectedSizeVariant1).val();
11981    var $productSection = $(e.target).closest(productSectionSelector);
11982    var templateData = {};
11983
11984    if (!shortSku && $(selectedSizeVariant2).length > 0) {
11985      shortSku = $(selectedSizeVariant2).val();
11986    } else if (!shortSku && $(selectedSizeVariant3).length > 0) {
11987      shortSku = $(selectedSizeVariant3).val();
11988    } else if ($(skuSelect).length > 0) {
11989      shortSku = $productSection.find(skuSelect).val();
11990    }
11991
11992    templateData.shortSku = shortSku ? shortSku : '';
11993
11994    $(ANF).trigger('FISModal:build', templateData);
11995  }
11996
11997  function buildPreferredWidgetObj(msgData) {
11998    var dataObj = {};
11999
12000    if (test.string.not.empty(storeObj.storeId, false)) {
12001      dataObj = {
12002        'brand': brandMap.dsBrandFromBrand(storeObj.brand),
12003        'brandName': brandMap.nameFromBrand(storeObj.brand),
12004        'storeName': storeObj.storeName,
12005        'storeID': storeObj.storeId,
12006        'zipCode': storeObj.zipCode,
12007        'city': storeObj.city,
12008        'showBranding': true
12009      };
12010    }
12011
12012    dataObj.isSelectSizeMsg = true;
12013
12014    if (msgData) {
12015      dataObj = $.extend({}, dataObj, msgData);
12016    }
12017
12018    // Once we know the FIS options, we need to set the store card's content and type before breaking.
12019    if (dataObj.isSelectSizeMsg) {
12020      dataObj.selectSizeCardInfo = {
12021        'state': 'initial',
12022        'main-text': {
12023          'text': ANF.messaging.popins.GLB_SELECT_SIZE_TO_SEE_INSTORE_AVAILABILITY
12024        }
12025      };
12026    }
12027
12028    if (dataObj.isAvailableInStore) {
12029      dataObj.isAvailableCardInfo = {
12030        'state': 'available',
12031        'main-text': {
12032          'text': ANF.messaging.popins.GLB_ITEMAVAILABLENOW
12033        }
12034      };
12035      if (ANF.params.env.region === 'US') {
12036        dataObj.isAvailableCardInfo['sub-text'] = {
12037          'text': ANF.messaging.popins.GLB_INELIGIBLEFORSAMEDAYDELIVERY
12038        };
12039      }
12040    }
12041
12042    if (dataObj.isNotInStock) {
12043      dataObj.noStockCardInfo = {
12044        'state': 'unavailable',
12045        'main-text': {
12046          'text': ANF.messaging.popins.GLB_NOTINSTOCKATSTORE
12047        }
12048      };
12049    }
12050
12051    if (dataObj.isStorePopinsEligible) {
12052      dataObj.popinsCardInfo = {
12053        'state': 'available',
12054        'main-text': {
12055          'text': ANF.messaging.popins.OMNI_POPINSAVAILABLE_PRIMARY,
12056          'help-button': {
12057            'aria-label': ANF.messaging.popins.OMNI_POPINSAVAILABLE_HELPBUTTONLABEL,
12058            'class-list': 'product__actions--popins-info js-open-modal',
12059            'data-prop': "data-modal='product__actions--popins-info-espot-v2'"
12060          }
12061        }
12062      };
12063    }
12064
12065    if (dataObj.isNotAvailableAtLocation) {
12066      dataObj.notAvailableCardInfo = {
12067        'state': 'unavailable',
12068        'main-text': {
12069          'text': ANF.messaging.popins.GLB_CLICKCOLLECT_NOTAVAILABLE
12070        }
12071      };
12072    }
12073
12074    if (dataObj.isNotAvailableForPickup) {
12075      dataObj.noPickupCardInfo = {
12076        'state': 'unavailable',
12077        'main-text': {
12078          'text': ANF.messaging.popins.GLB_NOTAVAILABLEFORPICKUP
12079        }
12080      };
12081    }
12082
12083    return dataObj;
12084  }
12085
12086  function updateProductAvailabilityHandler() {
12087    if (!Utils.isQuickviewOpened) {
12088      if (!scopeData) {
12089        scopeData = {
12090          $parentContainer: $(productSectionSelector)
12091        };
12092      }
12093
12094      updateProductAvailability();
12095    }
12096  }
12097
12098  function getStoreId() {
12099    return $(preferredStoreWidget).attr('data-storeid');
12100  }
12101
12102  function getOmniMfeCrsDataBridge() {
12103    var pdpDataBridge = {};
12104
12105    if (window.digitalData.export().pdp) {
12106      pdpDataBridge = window.digitalData.export().pdp.omniMfeCrsDataBridge || {};
12107    }
12108
12109    return pdpDataBridge;
12110  }
12111
12112  function updateProductAvailability() {
12113    var storeID = null;
12114    var skuEligibility = null;
12115    var tempObj = null;
12116    var omniMfeCrsDataBridge = getOmniMfeCrsDataBridge();
12117    var $productSection = $(productSectionSelector);
12118    var shortSku = omniMfeCrsDataBridge.qualifiedSku || $productSection.find(skuSelect).val();
12119
12120    if (
12121      test.string.not.empty(storeObj.storeId, false) &&
12122      test.string.not.empty(shortSku, false)
12123    ) {
12124      var productID = omniMfeCrsDataBridge.productId || $productSection.data('productid');
12125
12126      storeID = getStoreId();
12127      skuEligibility = productAvailability.checkSkuAvailability(productID, shortSku);
12128      productAvailability.retrieveStoreEligibility(storeID, shortSku, skuEligibility, updateWidget);
12129    } else if (test.string.not.empty(storeObj.storeId, false)) {
12130      tempObj = {
12131        'isPhase2Messaging': true,
12132        'isSelectSizeMsg': false,
12133        'isAvailableInStore': false,
12134        'isNotInStock': false,
12135        'isStorePopinsEligible': false,
12136        'isNotAvailableForPickup': false,
12137        'isNotAvailableAtLocation': false
12138      };
12139
12140      if ($productSection.find(isAvailable).hasClass('inactive')) {
12141        tempObj.isNotInStock = true;
12142      } else {
12143        tempObj.isSelectSizeMsg = true;
12144      }
12145
12146      updateWidget(tempObj);
12147    }
12148  }
12149
12150  function updateWidget(data) {
12151    var $errorContainer = $(reserveError);
12152    var templateData = buildPreferredWidgetObj(data);
12153    var processedTemplate = productPartialPdpPreferredStore.templates.pdp_preferredStore(templateData);
12154
12155    if ($errorContainer.hasClass('show')) {
12156      $errorContainer.removeClass('show');
12157    }
12158
12159    $(availabilityWrapper).html(processedTemplate);
12160
12161    if (test.string.not.empty(storeObj.brand, false)) {
12162      $(preferredStoreBadgeSelectorClass).addClass(storeObj.brand);
12163    }
12164
12165    $(availabilityWrapper).data('selected-store-hours-object', data.storeHours);
12166    reInitializeModal();
12167  }
12168
12169  function displayReserveError() {
12170    $(reserveError).addClass('show');
12171    $(itemAvailabilitySelectorClass).hide();
12172
12173    $(ANF).trigger('product:AJAXError');
12174  }
12175
12176  function hideReserveError() {
12177    $(reserveError).removeClass('show');
12178  }
12179
12180  function reInitializeModal() {
12181    modal.default().init();
12182  }
12183
12184  var publicMembers = {
12185    'bindEvents': function bindEvents() {
12186      $(document).on('click', changeButton, showPreferredStoreModal);
12187    },
12188    'listen': function listen() {
12189      var messageBus = $(ANF);
12190      var selectedStoreCookie = cookies.get('selectedStore');
12191      var $bodySelector = $('body');
12192
12193      messageBus.on('popins:getPhysicalStore', getPhysicalStore);
12194      messageBus.on('findAStore:storeCookied', widgetSetup);
12195      messageBus.on('findAStore:noStoreCookied', widgetSetup);
12196      window.addEventListener('omni-mfe-setup-crs-widget', widgetSetup);
12197      messageBus.on('product:availabilityError', displayReserveError);
12198      messageBus.on('product:availabilitySuccess', hideReserveError);
12199
12200      if (($bodySelector.is(catalogProductSelectorClass) || $bodySelector.is(productViewSelectorClass) || $bodySelector.is(productPageV2SelectorClass)) && selectedStoreCookie !== 'null') {
12201        messageBus.on('PDP:skuSelected', updateProductAvailabilityHandler);
12202        window.digitalData.subscribe('pdp.omniMfeCrsDataBridge.qualifiedSku', updateProductAvailabilityHandler);
12203      }
12204    }
12205  };
12206
12207  return publicMembers;
12208});
12209
12210redesign.define('productSections/product/popins',[
12211  'coreSectionHelpers',
12212  'coreModules/floatingLabels',
12213  'productModules/popins/preferredStore'
12214], function Popins(coreSectionHelpers, floatingLabels, preferredStore) {
12215  'use strict';
12216
12217
12218  var privateMembers = {
12219    'DEFAULT_MODULES': {
12220      'preferredStore': preferredStore,
12221      'floatingLabels': floatingLabels
12222    },
12223    'GLOBAL_SCOPE': '',
12224    'MODULES': {}
12225  };
12226
12227  return function setScope(settings) {
12228    privateMembers.GLOBAL_SCOPE = settings.scope;
12229
12230    privateMembers.MODULES = privateMembers.DEFAULT_MODULES;
12231
12232    if (typeof settings.modules === 'object') {
12233      $.extend(true, privateMembers.MODULES, settings.modules);
12234    }
12235
12236    return {
12237      'init': function init() {
12238        coreSectionHelpers.init({
12239          'modules': privateMembers.MODULES,
12240          'scope': privateMembers.GLOBAL_SCOPE
12241        });
12242      }
12243    };
12244  };
12245});
12246
12247redesign.define('polyfill/IntersectionObserver',[], function () {
12248  "use strict";
12249  /**
12250   * Copyright 2016 Google Inc. All Rights Reserved.
12251   *
12252   * Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
12253   *
12254   *  https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
12255   *
12256   */
12257  (function() {
12258  'use strict';
12259
12260  // Exit early if we're not running in a browser.
12261  if (typeof window !== 'object') {
12262    return;
12263  }
12264
12265  // Exit early if all IntersectionObserver and IntersectionObserverEntry
12266  // features are natively supported.
12267  if ('IntersectionObserver' in window &&
12268      'IntersectionObserverEntry' in window &&
12269      'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
12270
12271    // Minimal polyfill for Edge 15's lack of `isIntersecting`
12272    // See: https://github.com/w3c/IntersectionObserver/issues/211
12273    if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
12274      Object.defineProperty(window.IntersectionObserverEntry.prototype,
12275        'isIntersecting', {
12276        get: function () {
12277          return this.intersectionRatio > 0;
12278        }
12279      });
12280    }
12281    return;
12282  }
12283
12284
12285  /**
12286   * A local reference to the document.
12287   */
12288  var document = window.document;
12289
12290
12291  /**
12292   * An IntersectionObserver registry. This registry exists to hold a strong
12293   * reference to IntersectionObserver instances currently observing a target
12294   * element. Without this registry, instances without another reference may be
12295   * garbage collected.
12296   */
12297  var registry = [];
12298
12299
12300  /**
12301   * Creates the global IntersectionObserverEntry constructor.
12302   * https://w3c.github.io/IntersectionObserver/#intersection-observer-entry
12303   * @param {Object} entry A dictionary of instance properties.
12304   * @constructor
12305   */
12306  function IntersectionObserverEntry(entry) {
12307    this.time = entry.time;
12308    this.target = entry.target;
12309    this.rootBounds = entry.rootBounds;
12310    this.boundingClientRect = entry.boundingClientRect;
12311    this.intersectionRect = entry.intersectionRect || getEmptyRect();
12312    this.isIntersecting = !!entry.intersectionRect;
12313
12314    // Calculates the intersection ratio.
12315    var targetRect = this.boundingClientRect;
12316    var targetArea = targetRect.width * targetRect.height;
12317    var intersectionRect = this.intersectionRect;
12318    var intersectionArea = intersectionRect.width * intersectionRect.height;
12319
12320    // Sets intersection ratio.
12321    if (targetArea) {
12322      // Round the intersection ratio to avoid floating point math issues:
12323      // https://github.com/w3c/IntersectionObserver/issues/324
12324      this.intersectionRatio = Number((intersectionArea / targetArea).toFixed(4));
12325    } else {
12326      // If area is zero and is intersecting, sets to 1, otherwise to 0
12327      this.intersectionRatio = this.isIntersecting ? 1 : 0;
12328    }
12329  }
12330
12331
12332  /**
12333   * Creates the global IntersectionObserver constructor.
12334   * https://w3c.github.io/IntersectionObserver/#intersection-observer-interface
12335   * @param {Function} callback The function to be invoked after intersection
12336   *     changes have queued. The function is not invoked if the queue has
12337   *     been emptied by calling the `takeRecords` method.
12338   * @param {Object=} opt_options Optional configuration options.
12339   * @constructor
12340   */
12341  function IntersectionObserver(callback, opt_options) {
12342
12343    var options = opt_options || {};
12344
12345    if (typeof callback != 'function') {
12346      throw new Error('callback must be a function');
12347    }
12348
12349    if (options.root && options.root.nodeType != 1) {
12350      throw new Error('root must be an Element');
12351    }
12352
12353    // Binds and throttles `this._checkForIntersections`.
12354    this._checkForIntersections = throttle(
12355        this._checkForIntersections.bind(this), this.THROTTLE_TIMEOUT);
12356
12357    // Private properties.
12358    this._callback = callback;
12359    this._observationTargets = [];
12360    this._queuedEntries = [];
12361    this._rootMarginValues = this._parseRootMargin(options.rootMargin);
12362
12363    // Public properties.
12364    this.thresholds = this._initThresholds(options.threshold);
12365    this.root = options.root || null;
12366    this.rootMargin = this._rootMarginValues.map(function(margin) {
12367      return margin.value + margin.unit;
12368    }).join(' ');
12369  }
12370
12371
12372  /**
12373   * The minimum interval within which the document will be checked for
12374   * intersection changes.
12375   */
12376  IntersectionObserver.prototype.THROTTLE_TIMEOUT = 100;
12377
12378
12379  /**
12380   * The frequency in which the polyfill polls for intersection changes.
12381   * this can be updated on a per instance basis and must be set prior to
12382   * calling `observe` on the first target.
12383   */
12384  IntersectionObserver.prototype.POLL_INTERVAL = null;
12385
12386  /**
12387   * Use a mutation observer on the root element
12388   * to detect intersection changes.
12389   */
12390  IntersectionObserver.prototype.USE_MUTATION_OBSERVER = true;
12391
12392
12393  /**
12394   * Starts observing a target element for intersection changes based on
12395   * the thresholds values.
12396   * @param {Element} target The DOM element to observe.
12397   */
12398  IntersectionObserver.prototype.observe = function(target) {
12399    var isTargetAlreadyObserved = this._observationTargets.some(function(item) {
12400      return item.element == target;
12401    });
12402
12403    if (isTargetAlreadyObserved) {
12404      return;
12405    }
12406
12407    if (!(target && target.nodeType == 1)) {
12408      throw new Error('target must be an Element');
12409    }
12410
12411    this._registerInstance();
12412    this._observationTargets.push({element: target, entry: null});
12413    this._monitorIntersections();
12414    this._checkForIntersections();
12415  };
12416
12417
12418  /**
12419   * Stops observing a target element for intersection changes.
12420   * @param {Element} target The DOM element to observe.
12421   */
12422  IntersectionObserver.prototype.unobserve = function(target) {
12423    this._observationTargets =
12424        this._observationTargets.filter(function(item) {
12425
12426      return item.element != target;
12427    });
12428    if (!this._observationTargets.length) {
12429      this._unmonitorIntersections();
12430      this._unregisterInstance();
12431    }
12432  };
12433
12434
12435  /**
12436   * Stops observing all target elements for intersection changes.
12437   */
12438  IntersectionObserver.prototype.disconnect = function() {
12439    this._observationTargets = [];
12440    this._unmonitorIntersections();
12441    this._unregisterInstance();
12442  };
12443
12444
12445  /**
12446   * Returns any queue entries that have not yet been reported to the
12447   * callback and clears the queue. This can be used in conjunction with the
12448   * callback to obtain the absolute most up-to-date intersection information.
12449   * @return {Array} The currently queued entries.
12450   */
12451  IntersectionObserver.prototype.takeRecords = function() {
12452    var records = this._queuedEntries.slice();
12453    this._queuedEntries = [];
12454    return records;
12455  };
12456
12457
12458  /**
12459   * Accepts the threshold value from the user configuration object and
12460   * returns a sorted array of unique threshold values. If a value is not
12461   * between 0 and 1 and error is thrown.
12462   * @private
12463   * @param {Array|number=} opt_threshold An optional threshold value or
12464   *     a list of threshold values, defaulting to [0].
12465   * @return {Array} A sorted list of unique and valid threshold values.
12466   */
12467  IntersectionObserver.prototype._initThresholds = function(opt_threshold) {
12468    var threshold = opt_threshold || [0];
12469    if (!Array.isArray(threshold)) threshold = [threshold];
12470
12471    return threshold.sort().filter(function(t, i, a) {
12472      if (typeof t != 'number' || isNaN(t) || t < 0 || t > 1) {
12473        throw new Error('threshold must be a number between 0 and 1 inclusively');
12474      }
12475      return t !== a[i - 1];
12476    });
12477  };
12478
12479
12480  /**
12481   * Accepts the rootMargin value from the user configuration object
12482   * and returns an array of the four margin values as an object c
12482ontaining
12483   * the value and unit properties. If any of the values are not properly
12484   * formatted or use a unit other than px or %, and error is thrown.
12485   * @private
12486   * @param {string=} opt_rootMargin An optional rootMargin value,
12487   *     defaulting to '0px'.
12488   * @return {Array<Object>} An array of margin objects with the keys
12489   *     value and unit.
12490   */
12491  IntersectionObserver.prototype._parseRootMargin = function(opt_rootMargin) {
12492    var marginString = opt_rootMargin || '0px';
12493    var margins = marginString.split(/\s+/).map(function(margin) {
12494      var parts = /^(-?\d*\.?\d+)(px|%)$/.exec(margin);
12495      if (!parts) {
12496        throw new Error('rootMargin must be specified in pixels or percent');
12497      }
12498      return {value: parseFloat(parts[1]), unit: parts[2]};
12499    });
12500
12501    // Handles shorthand.
12502    margins[1] = margins[1] || margins[0];
12503    margins[2] = margins[2] || margins[0];
12504    margins[3] = margins[3] || margins[1];
12505
12506    return margins;
12507  };
12508
12509
12510  /**
12511   * Starts polling for intersection changes if the polling is not already
12512   * happening, and if the page's visibility state is visible.
12513   * @private
12514   */
12515  IntersectionObserver.prototype._monitorIntersections = function() {
12516    if (!this._monitoringIntersections) {
12517      this._monitoringIntersections = true;
12518
12519      // If a poll interval is set, use polling instead of listening to
12520      // resize and scroll events or DOM mutations.
12521      if (this.POLL_INTERVAL) {
12522        this._monitoringInterval = setInterval(
12523            this._checkForIntersections, this.POLL_INTERVAL);
12524      }
12525      else {
12526        addEvent(window, 'resize', this._checkForIntersections, true);
12527        addEvent(document, 'scroll', this._checkForIntersections, true);
12528
12529        if (this.USE_MUTATION_OBSERVER && 'MutationObserver' in window) {
12530          this._domObserver = new MutationObserver(this._checkForIntersections);
12531          this._domObserver.observe(document, {
12532            attributes: true,
12533            childList: true,
12534            characterData: true,
12535            subtree: true
12536          });
12537        }
12538      }
12539    }
12540  };
12541
12542
12543  /**
12544   * Stops polling for intersection changes.
12545   * @private
12546   */
12547  IntersectionObserver.prototype._unmonitorIntersections = function() {
12548    if (this._monitoringIntersections) {
12549      this._monitoringIntersections = false;
12550
12551      clearInterval(this._monitoringInterval);
12552      this._monitoringInterval = null;
12553
12554      removeEvent(window, 'resize', this._checkForIntersections, true);
12555      removeEvent(document, 'scroll', this._checkForIntersections, true);
12556
12557      if (this._domObserver) {
12558        this._domObserver.disconnect();
12559        this._domObserver = null;
12560      }
12561    }
12562  };
12563
12564
12565  /**
12566   * Scans each observation target for intersection changes and adds them
12567   * to the internal entries queue. If new entries are found, it
12568   * schedules the callback to be invoked.
12569   * @private
12570   */
12571  IntersectionObserver.prototype._checkForIntersections = function() {
12572    var rootIsInDom = this._rootIsInDom();
12573    var rootRect = rootIsInDom ? this._getRootRect() : getEmptyRect();
12574
12575    this._observationTargets.forEach(function(item) {
12576      var target = item.element;
12577      var targetRect = getBoundingClientRect(target);
12578      var rootContainsTarget = this._rootContainsTarget(target);
12579      var oldEntry = item.entry;
12580      var intersectionRect = rootIsInDom && rootContainsTarget &&
12581          this._computeTargetAndRootIntersection(target, rootRect);
12582
12583      var newEntry = item.entry = new IntersectionObserverEntry({
12584        time: now(),
12585        target: target,
12586        boundingClientRect: targetRect,
12587        rootBounds: rootRect,
12588        intersectionRect: intersectionRect
12589      });
12590
12591      if (!oldEntry) {
12592        this._queuedEntries.push(newEntry);
12593      } else if (rootIsInDom && rootContainsTarget) {
12594        // If the new entry intersection ratio has crossed any of the
12595        // thresholds, add a new entry.
12596        if (this._hasCrossedThreshold(oldEntry, newEntry)) {
12597          this._queuedEntries.push(newEntry);
12598        }
12599      } else {
12600        // If the root is not in the DOM or target is not contained within
12601        // root but the previous entry for this target had an intersection,
12602        // add a new record indicating removal.
12603        if (oldEntry && oldEntry.isIntersecting) {
12604          this._queuedEntries.push(newEntry);
12605        }
12606      }
12607    }, this);
12608
12609    if (this._queuedEntries.length) {
12610      this._callback(this.takeRecords(), this);
12611    }
12612  };
12613
12614
12615  /**
12616   * Accepts a target and root rect computes the intersection between then
12617   * following the algorithm in the spec.
12618   * TODO(philipwalton): at this time clip-path is not considered.
12619   * https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo
12620   * @param {Element} target The target DOM element
12621   * @param {Object} rootRect The bounding rect of the root after being
12622   *     expanded by the rootMargin value.
12623   * @return {?Object} The final intersection rect object or undefined if no
12624   *     intersection is found.
12625   * @private
12626   */
12627  IntersectionObserver.prototype._computeTargetAndRootIntersection =
12628      function(target, rootRect) {
12629
12630    // If the element isn't displayed, an intersection can't happen.
12631    if (window.getComputedStyle(target).display == 'none') return;
12632
12633    var targetRect = getBoundingClientRect(target);
12634    var intersectionRect = targetRect;
12635    var parent = getParentNode(target);
12636    var atRoot = false;
vendor: 8,734 bytes, lines 12637-12907
12637
12638    while (!atRoot) {
12639      var parentRect = null;
12640      var parentComputedStyle = parent.nodeType == 1 ?
12641          window.getComputedStyle(parent) : {};
12642
12643      // If the parent isn't displayed, an intersection can't happen.
12644      if (parentComputedStyle.display == 'none') return;
12645
12646      if (parent == this.root || parent == document) {
12647        atRoot = true;
12648        parentRect = rootRect;
12649      } else {
12650        // If the element has a non-visible overflow, and it's not the <body>
12651        // or <html> element, update the intersection rect.
12652        // Note: <body> and <html> cannot be clipped to a rect that's not also
12653        // the document rect, so no need to compute a new intersection.
12654        if (parent != document.body &&
12655            parent != document.documentElement &&
12656            parentComputedStyle.overflow != 'visible') {
12657          parentRect = getBoundingClientRect(parent);
12658        }
12659      }
12660
12661      // If either of the above conditionals set a new parentRect,
12662      // calculate new intersection data.
12663      if (parentRect) {
12664        intersectionRect = computeRectIntersection(parentRect, intersectionRect);
12665
12666        if (!intersectionRect) break;
12667      }
12668      parent = getParentNode(parent);
12669    }
12670    return intersectionRect;
12671  };
12672
12673
12674  /**
12675   * Returns the root rect after being expanded by the rootMargin value.
12676   * @return {Object} The expanded root rect.
12677   * @private
12678   */
12679  IntersectionObserver.prototype._getRootRect = function() {
12680    var rootRect;
12681    if (this.root) {
12682      rootRect = getBoundingClientRect(this.root);
12683    } else {
12684      // Use <html>/<body> instead of window since scroll bars affect size.
12685      var html = document.documentElement;
12686      var body = document.body;
12687      rootRect = {
12688        top: 0,
12689        left: 0,
12690        right: html.clientWidth || body.clientWidth,
12691        width: html.clientWidth || body.clientWidth,
12692        bottom: html.clientHeight || body.clientHeight,
12693        height: html.clientHeight || body.clientHeight
12694      };
12695    }
12696    return this._expandRectByRootMargin(rootRect);
12697  };
12698
12699
12700  /**
12701   * Accepts a rect and expands it by the rootMargin value.
12702   * @param {Object} rect The rect object to expand.
12703   * @return {Object} The expanded rect.
12704   * @private
12705   */
12706  IntersectionObserver.prototype._expandRectByRootMargin = function(rect) {
12707    var margins = this._rootMarginValues.map(function(margin, i) {
12708      return margin.unit == 'px' ? margin.value :
12709          margin.value * (i % 2 ? rect.width : rect.height) / 100;
12710    });
12711    var newRect = {
12712      top: rect.top - margins[0],
12713      right: rect.right + margins[1],
12714      bottom: rect.bottom + margins[2],
12715      left: rect.left - margins[3]
12716    };
12717    newRect.width = newRect.right - newRect.left;
12718    newRect.height = newRect.bottom - newRect.top;
12719
12720    return newRect;
12721  };
12722
12723
12724  /**
12725   * Accepts an old and new entry and returns true if at least one of the
12726   * threshold values has been crossed.
12727   * @param {?IntersectionObserverEntry} oldEntry The previous entry for a
12728   *    particular target element or null if no previous entry exists.
12729   * @param {IntersectionObserverEntry} newEntry The current entry for a
12730   *    particular target element.
12731   * @return {boolean} Returns true if a any threshold has been crossed.
12732   * @private
12733   */
12734  IntersectionObserver.prototype._hasCrossedThreshold =
12735      function(oldEntry, newEntry) {
12736
12737    // To make comparing easier, an entry that has a ratio of 0
12738    // but does not actually intersect is given a value of -1
12739    var oldRatio = oldEntry && oldEntry.isIntersecting ?
12740        oldEntry.intersectionRatio || 0 : -1;
12741    var newRatio = newEntry.isIntersecting ?
12742        newEntry.intersectionRatio || 0 : -1;
12743
12744    // Ignore unchanged ratios
12745    if (oldRatio === newRatio) return;
12746
12747    for (var i = 0; i < this.thresholds.length; i++) {
12748      var threshold = this.thresholds[i];
12749
12750      // Return true if an entry matches a threshold or if the new ratio
12751      // and the old ratio are on the opposite sides of a threshold.
12752      if (threshold == oldRatio || threshold == newRatio ||
12753          threshold < oldRatio !== threshold < newRatio) {
12754        return true;
12755      }
12756    }
12757  };
12758
12759
12760  /**
12761   * Returns whether or not the root element is an element and is in the DOM.
12762   * @return {boolean} True if the root element is an element and is in the DOM.
12763   * @private
12764   */
12765  IntersectionObserver.prototype._rootIsInDom = function() {
12766    return !this.root || containsDeep(document, this.root);
12767  };
12768
12769
12770  /**
12771   * Returns whether or not the target element is a child of root.
12772   * @param {Element} target The target element to check.
12773   * @return {boolean} True if the target element is a child of root.
12774   * @private
12775   */
12776  IntersectionObserver.prototype._rootContainsTarget = function(target) {
12777    return containsDeep(this.root || document, target);
12778  };
12779
12780
12781  /**
12782   * Adds the instance to the global IntersectionObserver registry if it isn't
12783   * already present.
12784   * @private
12785   */
12786  IntersectionObserver.prototype._registerInstance = function() {
12787    if (registry.indexOf(this) < 0) {
12788      registry.push(this);
12789    }
12790  };
12791
12792
12793  /**
12794   * Removes the instance from the global IntersectionObserver registry.
12795   * @private
12796   */
12797  IntersectionObserver.prototype._unregisterInstance = function() {
12798    var index = registry.indexOf(this);
12799    if (index != -1) registry.splice(index, 1);
12800  };
12801
12802
12803  /**
12804   * Returns the result of the performance.now() method or null in browsers
12805   * that don't support the API.
12806   * @return {number} The elapsed time since the page was requested.
12807   */
12808  function now() {
12809    return window.performance && performance.now && performance.now();
12810  }
12811
12812
12813  /**
12814   * Throttles a function and delays its execution, so it's only called at most
12815   * once within a given time period.
12816   * @param {Function} fn The function to throttle.
12817   * @param {number} timeout The amount of time that must pass before the
12818   *     function can be called again.
12819   * @return {Function} The throttled function.
12820   */
12821  function throttle(fn, timeout) {
12822    var timer = null;
12823    return function () {
12824      if (!timer) {
12825        timer = setTimeout(function() {
12826          fn();
12827          timer = null;
12828        }, timeout);
12829      }
12830    };
12831  }
12832
12833
12834  /**
12835   * Adds an event handler to a DOM node ensuring cross-browser compatibility.
12836   * @param {Node} node The DOM node to add the event handler to.
12837   * @param {string} event The event name.
12838   * @param {Function} fn The event handler to add.
12839   * @param {boolean} opt_useCapture Optionally adds the even to the capture
12840   *     phase. Note: this only works in modern browsers.
12841   */
12842  function addEvent(node, event, fn, opt_useCapture) {
12843    if (typeof node.addEventListener == 'function') {
12844      node.addEventListener(event, fn, opt_useCapture || false);
12845    }
12846    else if (typeof node.attachEvent == 'function') {
12847      node.attachEvent('on' + event, fn);
12848    }
12849  }
12850
12851
12852  /**
12853   * Removes a previously added event handler from a DOM node.
12854   * @param {Node} node The DOM node to remove the event handler from.
12855   * @param {string} event The event name.
12856   * @param {Function} fn The event handler to remove.
12857   * @param {boolean} opt_useCapture If the event handler was added with this
12858   *     flag set to true, it should be set to true here in order to remove it.
12859   */
12860  function removeEvent(node, event, fn, opt_useCapture) {
12861    if (typeof node.removeEventListener == 'function') {
12862      node.removeEventListener(event, fn, opt_useCapture || false);
12863    }
12864    else if (typeof node.detatchEvent == 'function') {
12865      node.detatchEvent('on' + event, fn);
12866    }
12867  }
12868
12869
12870  /**
12871   * Returns the intersection between two rect objects.
12872   * @param {Object} rect1 The first rect.
12873   * @param {Object} rect2 The second rect.
12874   * @return {?Object} The intersection rect or undefined if no intersection
12875   *     is found.
12876   */
12877  function computeRectIntersection(rect1, rect2) {
12878    var top = Math.max(rect1.top, rect2.top);
12879    var bottom = Math.min(rect1.bottom, rect2.bottom);
12880    var left = Math.max(rect1.left, rect2.left);
12881    var right = Math.min(rect1.right, rect2.right);
12882    var width = right - left;
12883    var height = bottom - top;
12884
12885    return (width >= 0 && height >= 0) && {
12886      top: top,
12887      bottom: bottom,
12888      left: left,
12889      right: right,
12890      width: width,
12891      height: height
12892    };
12893  }
12894
12895
12896  /**
12897   * Shims the native getBoundingClientRect for compatibility with older IE.
12898   * @param {Element} el The element whose bounding rect to get.
12899   * @return {Object} The (possibly shimmed) rect of the element.
12900   */
12901  function getBoundingClientRect(el) {
12902    var rect;
12903
12904    try {
12905      rect = el.getBoundingClientRect();
12906    } catch (err) {
12907      // Ignore Windows 7 IE11 "Unspecified error"
12908      // https://github.com/w3c/IntersectionObserver/pull/205
12909    }
12910
12911    if (!rect) return getEmptyRect();
12912
12913    // Older IE
12914    if (!(rect.width && rect.height)) {
12915      rect = {
12916        top: rect.top,
12917        right: rect.right,
12918        bottom: rect.bottom,
12919        left: rect.left,
12920        width: rect.right - rect.left,
12921        height: rect.bottom - rect.top
12922      };
12923    }
12924    return rect;
12925  }
12926
12927
12928  /**
12929   * Returns an empty rect object. An empty rect is returned when an element
12930   * is not in the DOM.
12931   * @return {Object} The empty rect.
12932   */
12933  function getEmptyRect() {
12934    return {
12935      top: 0,
12936      bottom: 0,
12937      left: 0,
12938      right: 0,
12939      width: 0,
12940      height: 0
12941    };
12942  }
12943
12944  /**
12945   * Checks to see if a parent element contains a child element (including inside
12946   * shadow DOM).
12947   * @param {Node} parent The parent element.
12948   * @param {Node} child The child element.
12949   * @return {boolean} True if the parent node contains the child node.
12950   */
12951  function containsDeep(parent, child) {
12952    var node = child;
12953    while (node) {
12954      if (node == parent) return true;
12955
12956      node = getParentNode(node);
12957    }
12958    return false;
12959  }
12960
12961
12962  /**
12963   * Gets the parent node of an element or its host element if the parent node
12964   * is a shadow root.
12965   * @param {Node} node The node whose parent to get.
12966   * @return {Node|null} The parent node or null if no parent exists.
12967   */
12968  function getParentNode(node) {
12969    var parent = node.parentNode;
12970
12971    if (parent && parent.nodeType == 11 && parent.host) {
12972      // If the parent is a shadow root, return the host element.
12973      return parent.host;
12974    }
12975
12976    if (parent && parent.assignedSlot) {
12977      // If the parent is distributed in a <slot>, return the parent of a slot.
12978      return parent.assignedSlot.parentNode;
12979    }
12980
12981    return parent;
12982  }
12983
12984
12985  // Exposes the constructors globally.
12986  window.IntersectionObserver = IntersectionObserver;
12987  window.IntersectionObserverEntry = IntersectionObserverEntry;
12988
12989  }());
12990
12991    return window.IntersectionObserver;
12992  });
12993redesign.define('productModules/helpers/productIntersectionObserverSetup',[
12994  'productModules/helpers/productIntersectionObserver',
12995  'polyfill/IntersectionObserver'
12996], function productIntersectionObserverSetup(productIntersectionObserver, IntersectionObserver) {
12997  'use strict';
12998
12999  var getIntersectionObserver = function getIntersectionObserver() {
13000    return IntersectionObserver;
13001  };
13002
13003  var publicMembers = {
13004    init: function init() {
13005      productIntersectionObserver.create('IntersectionObserver', getIntersectionObserver);
13006    }
13007  };
13008
13009  return publicMembers;
13010});
13011
13012redesign.define('productModules/product/productGridSaves',[
13013  'coreServices/mysaves',
13014  'globalModulesHelpers/mysavesUtility'
13015],
13016function productGridSaves(savesService, savesUtility) {
13017  'use strict';
13018
13019  var retryCount = 1;
13020  function callSavesApi(serviceMethod, products) {
13021    var savesApiPromise = savesService[serviceMethod]({
13022      serviceMethod: serviceMethod,
13023      products: products
13024    });
13025
13026    savesApiPromise.done(function saveApiPromiseDone(response) {
13027      var APIResponseCode = response.reason;
13028      var isFirstTimeSaveResponseCode = 5;
13029      var isFirstTimeSave = APIResponseCode === isFirstTimeSaveResponseCode;
13030      var itemSaved = serviceMethod === 'add';
13031
13032      if (itemSaved) {
13033        savesUtility.saveSuccess(isFirstTimeSave);
13034      }
13035
13036      $(window.ANF).trigger('mySaves:updatedMySavesCount');
13037    });
13038
13039    savesApiPromise.fail(function onFailure() {
13040      if (retryCount < 3) {
13041        retryCount++;
13042        callSavesApi(serviceMethod, products);
13043      }
13044    });
13045  }
13046
13047  var productAddSaveListener = function addSaveListener(e) {
13048    callSavesApi('add', [e.detail]);
13049  };
13050
13051  var productRemoveSaveListener = function removeSaveListener(e) {
13052    callSavesApi('remove', [e.detail]);
13053  };
13054
13055  var publicMembers = {
13056    gridSavesPublicFunctions: function gridSavesPublicFunctions() {
13057      window.addEventListener('mfe:productAddSave', productAddSaveListener);
13058      window.addEventListener('mfe:productRemoveSave', productRemoveSaveListener);
13059    }
13060  };
13061
13062  return publicMembers;
13063});
13064
13065
13066redesign.define('productPages/productPageMain',[
13067  'productSections/product/productPageImages',
13068  'productSections/product/productPageReviews',
13069  'productSections/product/productPageInfo',
13070  'productSections/product/quickviewModules',
13071  'productSections/product/popins',
13072  'productModules/helpers/productIntersectionObserverSetup',
13073  'productModules/helpers/Utils',
13074  'productModules/product/productGridSaves'
13075], function ProductPageMain(productPageImages, productPageReviews, productPageInfo, quickviewModules, popins, productIntersectionObserverSetup, Utils, productGridSaves) {
13076  'use strict';
13077
13078  function main() {
13079    if (typeof ANF.product !== 'object') {
13080      ANF.product = {};
13081    }
13082
13083    function isPdP() {
13084      return $('body').is('#catalog-productpageview, #catalog-product, .product-page-v2');
13085    }
13086    function hasLocationFilter() {
13087      return $('.ds-rs-facet-tile-location__wrapper').length;
13088    }
13089
13090    ANF.product.productPageMain = (function productPageMain($, ANF) {
13091      var messageBus = $(ANF);
13092
13093      var publicMembers = {
13094        init: function init() {
13095          ANF.product.productPageMain.start.productPageImagesStart({
13096            'scope': 'body',
13097            'parentPage': ANF.product.productPageMain
13098          });
13099          ANF.product.productPageMain.start.productPageReviewsStart({
13100            'scope': 'body',
13101            'parentPage': ANF.product.productPageMain
13102          });
13103          ANF.product.productPageMain.start.productPageInfoStart({
13104            'scope': 'body',
13105            'parentPage': ANF.product.productPageMain
13106          });
13107          ANF.product.productPageMain.start.quickviewModulesStart({
13108            'scope': 'body',
13109            'parentPage': ANF.product.productPageMain
13110          });
13111          ANF.product.productPageMain.start.popinsStart({
13112            'scope': '.product__actions--availability'
13113          });
13114        },
13115        start: {
13116          productPageImagesStart: function productPageImagesStart(settings) {
13117            ANF.product.productPageMain.productPageImages = productPageImages(settings);
13118            ANF.product.productPageMain.productPageImages.init();
13119            ANF.product.productPageMain.productPageImages.subscribe();
13120          },
13121          productPageReviewsStart: function productPageReviewsStart(settings) {
13122            if (ANF.params.storeAttributes.catalogV2.hasBazaarVoiceEnable) {
13123              ANF.product.productPageMain.productPageReviews = productPageReviews(settings);
13124              ANF.product.productPageMain.productPageReviews.init();
13125              ANF.product.productPageMain.productPageReviews.subscribe();
13126            }
13127          },
13128          productPageInfoStart: function productPageInfoStart(settings) {
13129            ANF.product.productPageMain.productPageInfo = productPageInfo(settings);
13130            ANF.product.productPageMain.productPageInfo.init();
13131            ANF.product.productPageMain.productPageInfo.subscribe();
13132          },
13133          quickviewModulesStart: function quickviewModulesStart(settings) {
13134            ANF.product.productPageMain.quickviewModules = quickviewModules(settings);
13135            ANF.product.productPageMain.quickviewModules.init();
13136          },
13137          popinsStart: function popinsStart(settings) {
13138            if (isPdP() || hasLocationFilter()) {
13139              ANF.product.productPageMain.popins = popins(settings);
13140              ANF.product.productPageMain.popins.init();
13141            }
13142          }
13143        },
13144        ajaxInContent: function ajaxInContent() {
13145          messageBus.trigger('productPageMain:init');
13146
13147          if (Utils.isExternalUser() && !Utils.isQuickviewOpened) {
13148            productGridSaves.gridSavesPublicFunctions();
13149          }
13150          if (isPdP()) {
13151            messageBus.trigger('popins:getPhysicalStore');
13152          }
13153        }
13154      };
13155
13156      return publicMembers;
13157    })(jQuery, ANF);
13158
13159    ANF.deferredStart = ANF.deferredStart || $.deferred();
13160    ANF.deferredStart.then(function deferredStart() {
13161      // this is needed to set up the productIntersectionObserver module which has the Intersection Observer API
13162      productIntersectionObserverSetup.init();
13163      ANF.product.productPageMain.init();
13164      ANF.product.productPageMain.ajaxInContent();
13165    });
13166  }
13167
13168  return main;
13169});
13170
13171redesign.define('productSections/product/quickviewImages',[
13172  'coreSectionHelpers',
13173  'productModules/product/productThumbnails',
13174  'productModules/product/productMainImage',
13175  'productModules/product/productImageLoader'
13176], function QuickviewImages(coreSectionHelpers, thumbnails, mainImage, imageLoader) {
13177  'use strict';
13178
13179  var privateMembers = {
13180    'DEFAULT_MODULES': {
13181      '.product-thumbnails': thumbnails,
13182      '.product-main-images': mainImage,
13183      'product-main-images;=': imageLoader
13184    },
13185    'GLOBAL_SCOPE': '',
13186    'parentPage': '',
13187    'MODULES': {}
13188  };
13189
13190  return function quickviewImagesScope(settings) {
13191    privateMembers.GLOBAL_SCOPE = settings.scope;
13192    privateMembers.parentPage = settings.parentPage;
13193    privateMembers.MODULES = privateMembers.DEFAULT_MODULES;
13194
13195    if (typeof settings.modules === 'object') {
13196      $.extend(true, privateMembers.MODULES, settings.modules);
13197    }
13198
13199    // var messageBus = $(ANF);
13200
13201    return {
13202      'init': function quickviewImagesInit() {
13203        coreSectionHelpers.init({
13204          'modules': privateMembers.MODULES,
13205          'scope': privateMembers.GLOBAL_SCOPE
13206        });
13207      }
13208    };
13209  };
13210});
13211
13212redesign.define('productPages/quickviewMain',[
13213  'productSections/product/quickviewModules',
13214  'productSections/product/quickviewImages',
13215  'productSections/product/productPageInfo',
13216  'productSections/product/productPageReviews'
13217], function QuickviewMain(quickviewModules, quickviewImages, productPageInfo, productPageReviews) {
13218  'use strict';
13219
13220  function main() {
13221    if (typeof ANF.product !== 'object') {
13222      ANF.product = {};
13223    }
13224
13225    ANF.product.quickviewMain = (function quickviewMain($, ANF) {
13226      var publicMembers = {
13227        init: function init() {
13228          ANF.product.quickviewMain.start.quickviewModulesStart({
13229            'scope': 'body',
13230            'parentPage': ANF.product.quickviewMain
13231          });
13232          ANF.product.quickviewMain.start.quickviewImagesStart({
13233            'scope': 'body',
13234            'parentPage': ANF.product.quickviewMain
13235          });
13236          ANF.product.quickviewMain.start.productPageInfoStart({
13237            'scope': 'body',
13238            'parentPage': ANF.product.quickviewMain
13239          });
13240          ANF.product.quickviewMain.start.productPageReviewsStart({
13241            'scope': 'body',
13242            'parentPage': ANF.product.quickviewMain
13243          });
13244        },
13245        start: {
13246          quickviewModulesStart: function quickviewModulesStart(settings) {
13247            ANF.product.quickviewMain.quickviewModules = quickviewModules(settings);
13248            ANF.product.quickviewMain.quickviewModules.init();
13249          },
13250          quickviewImagesStart: function quickviewImagesStart(settings) {
13251            ANF.product.quickviewMain.quickviewImages = quickviewImages(settings);
13252            ANF.product.quickviewMain.quickviewImages.init();
13253          },
13254          productPageInfoStart: function productPageInfoStart(settings) {
13255            ANF.product.quickviewMain.productPageInfo = productPageInfo(settings);
13256            ANF.product.quickviewMain.productPageInfo.init();
13257          },
13258          productPageReviewsStart: function productPageReviewsStart(settings) {
13259            if (ANF.params.storeAttributes.catalogV2.hasBazaarVoiceEnable) {
13260              ANF.product.quickviewMain.productPageReviews = productPageReviews(settings);
13261              ANF.product.quickviewMain.productPageReviews.init();
13262              ANF.product.quickviewMain.productPageReviews.subscribe();
13263            }
13264          }
13265        }
13266      };
13267
13268      return publicMembers;
13269    })(jQuery, ANF);
13270
13271    ANF.deferredStart = ANF.deferredStart || $.deferred();
13272    ANF.deferredStart.then(function deferredStart() {
13273      ANF.product.quickviewMain.init();
13274    });
13275  }
13276
13277  return main;
13278});
13279
13280redesign.require([
13281  'productPages/productPageMain',
13282  'productPages/quickviewMain'
13283], function ProductV2(productPageMain, quickview) {
13284  'use strict';
13285
13286  var ANF = ANF || {};
13287
13288  function isProductPage() {
13289    return $('body').hasClass('product-page-v2');
13290  }
13291
13292  function product() {
13293    if (!isProductPage()) {
13294      quickview();
13295    } else {
13296      productPageMain();
13297    }
13298  }
13299
13300  ANF.product = product();
13301});
13302
13303redesign.define("src/hol/js/productV2.js", function(){});
13304

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.