PageSourceSearch

https://www.bcliquorstores.com/modules/custom/bcls/js/ViewModels/BCLS.ProductListVM.js?tlwdk9

js bcliquorstores.com collected 2026-09-25 02:52:05 UTC 51,466 bytes, 1,465 lines download raw bytes

1// / <reference path="../bcls-config.js" />
2// / <reference path="../lib/lodash.min.js" />
3
4var BCLS = BCLS || {};
5var VMInitialRequest = 0;
6
7BCLS.ProductListVM = function ProductListVM() {
8  var $this = this;
9  var InitialParam = '';
10  var cidersOrigin = getParameterByName('type');
11
12  this.LS_KEY = 'bcls.details-aggregations';
13  this.LS_FILTER_KEY = 'bcls.filter-state';
14
15  this.MainContainerDefaultPadding = jQuery('.bcls-main-container').css('padding-top');
16  this.ControlBarTemplate = ko.observable('product-list-control-bar');
17  this.Page = ko.observable(1);
18  this.TotalPages = ko.observable(0);
19  this.PageSize = 24;
20  this.Category = ko.observable(null);
21  this.SubCategory = ko.observable(null);
22  this.SubSubCategory = ko.observable(null);
23  this.Style = ko.observable(null);
24  this.SubCategoryUrl = ko.observable(null);
25  this.SubSubCategoryUrl = ko.observable('#');
26  this.StyleUrl = ko.observable(null);
27  this.breadcrumbGroup = getParameterByName('group');
28  this.SearchQuery = ko.observable('');
29  this.SearchTerms= ko.observable('');
30  this.ProductResults = ko.observableArray();
31  this.TotalProducts = ko.observable();
32  this.GrabbingProducts = ko.observable(false);
33  this.Sort = ko.observable('name.raw');
34  this.SortLast = ko.observable(null);
35  this.SortDirection = ko.observable('asc');
36  this.FilterAggregations = ko.observable();
37  this.NoMoreProducts = false;
38  this.ProductDefinition = null;
39  this.FilterAggregationsSummary = ko.observable();
40  this.MobileFiltersVisible = ko.observable(false);
41  this.SlideoutProducts = ko.observable(false);
42  this.LayoutType = ko.observable(Cookies.get(BCLS.Config.ProductListViewCookieKey) || 'grid');
43  this.PromotionData = ko.observable(null);
44  this.MaxFilterItems = 8;
45  this.FieldsToCollapse = [
46    'Price',
47    'Volume'
48  ];
49  this.InitialRequestBody = null;
50  this.NonFacets = ['class.id', 'category.id', 'clause', 'subCategory.id'];
51  this.LastSection = null;
52  this.loading = ko.observable(true);
53  this.updateFilter = ko.observable(false);
54  this.filterKeys = ko.observable(false);
55
56  function getParameterByName(name, url) {
57    if (!url) {
58      url = window.location.href;
59    }
60    name = new URLSearchParams(url).get(name);
61    name = name.replace('coolers/ciders', 'coolers & ciders');
62
63    return name;
64  }
65
66
67
68  function createAppendUrl(filterKeys) {
69    var newAppendUrl = '';
70    _.forIn(filterKeys, function(value, key){
71      key = convertFilterTags(key);
72      if(value == "Cider" && cidersOrigin != null){
73          value = cidersOrigin;
74      }
75
76      if ( key == 'price' ) {
77        var priceAdjustedForES = [];
78        value.forEach( function( price ) {
79          if ( price !== undefined ) {
80            price = price.replace('-10.0', '-9.99')
81              .replace('-20.0', '-19.99')
82              .replace('-50.0', '-49.99')
83              .replace('-100.0', '-99.99')
84              .replace('-200.0', '-199.99')
85              .replace('-500.0', '-499.99');
86
87            priceAdjustedForES.push(price);
88          }
89        })
90        value = priceAdjustedForES;
91      }
92
93      if ( key == 'volume' ) {
94        var volumeAdjustedForES = [];
95        value.forEach( function( volume ) {
96          if ( volume !== undefined ) {
97            volume = volume.replace('-0.25', '-0.249')
98              .replace('-0.5', '-0.499')
99              .replace('-0.75', '-0.749')
100              .replace('-1.0', '-0.999')
101              .replace('-1.25', '-1.249')
102              .replace('-1.5', '-1.499')
103              .replace('-1.75', '-1.749')
104              .replace('-2.0', '-1.999')
105              .replace('-3.0', '-2.999')
106              .replace('-4.0', '-3.999');
107            volumeAdjustedForES.push(volume);
108          }
109        })
110        value = volumeAdjustedForES;
111      }
112      newAppendUrl += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(value);
113    });
114    return newAppendUrl.toLowerCase();
115  }
116
117  function convertFilterTags(filterTag) {
118
119    switch(filterTag) {
120        case 'productType':
121            return 'type';
122        case 'productCategory':
123            return 'maincategory';
124        case 'productSubCategory':
125            return 'subcategory';
126        case 'redVarietal':
127            return 'red';
128        case 'featured':
129            return 'special';
130        case 'countryName.raw':
131            return 'country';
132        case 'region.raw':
133            return 'region';
134        case 'whiteVarietal':
135            return 'white';
136        case 'currentPrice':
137            return 'price';
138        case 'certificates':
139            return 'cert';
140        case 'class.description':
141            return 'subtype';
142        case 'category.description':
143            return 'categoryclass';
144        default:
145            break;
146    }
147    return filterTag;
148  }
149
150  this.LayoutType.subscribe(function (newVal) {
151    Cookies.set(BCLS.Config.ProductListViewCookieKey, newVal);
152  });
153
154  this.ItemsWithCounts = function (items) {
155    return _.filter(items, function (item) {
156      return item.item.doc_count > 0 || item.isSelected();
157    });
158  };
159
160  this.FallBackImgSrcs = BCLS.Config.FallBackImgSrcs;
161
162  this.ToggleSlideoutFilters = function () {
163    var lastItem = $this.SlideoutProducts();
164    $this.SlideoutProducts(!$this.SlideoutProducts());
165  };
166
167  this.CategoryUrl = ko.computed(function () {
168    if ($this.SubCategory() == 'Filtered') {
169      return window.location.href;
170    } else if ($this.SubCategory() != undefined) {
171      return '/product-catalogue?category=' + encodeURIComponent($this.Category());
172    }
173    return '#';
174  });
175
176  this.HasItemCheckedBelowShowMore = function (section) {
177    return _.findLastIndex($this.ItemsWithCounts(section.Items), function (sec) { return sec.isSelected(); }) >= $this.MaxFilterItems;
178  };
179
180  this.updateSubCategoryUrl = function () {
181    var sub_url = '#';
182
183    if ($this.SubCategory() != null) {
184      var param = 'type';
185      if ( $this.SubCategory() == 'featured' || $this.SubCategory() == 'promotions' || $this.SubCategory() == 'country' ) {
186        param = 'group';
187      }
188      if ( $this.Category() == 'beer' ) {
189        param = 'maincategory';
190      }
191
192      if ( $this.SubSubCategory() != null && $this.SubCategory() == 'other wine') { // remove SubSubCategory() != null to fix other wine > all other wine conflict
193        param = 'group';
194      }
195
196      // make featured subsubcategory -> subcatagory
197      if($this.SubSubCategory() === 'featured') {
198        sub_url = '/product-catalogue?category=' + encodeURIComponent($this.Category()) + '&' + param + '=' + encodeURIComponent($this.SubSubCategory());
199      } else {
200        sub_url = '/product-catalogue?category=' + encodeURIComponent($this.Category()) + '&' + param + '=' + encodeURIComponent($this.SubCategory());
201      }
202
203      if ($this.SubCategory() == 'bc vqa') {
204        param = 'special';
205        sub_url = '/product-catalogue?category=' + encodeURIComponent($this.Category()) + '&' + param + '=' + encodeURIComponent($this.SubCategory());
206      }
207
208      if ($this.SubCategory() == 'sale') {
209        sub_url = '/product-catalogue?group=sale&special=on%20sale'
210      }
211
212      if ($this.SubCategory() == 'promotions') {
213        sub_url = '/product-catalogue?' + param + '=' + encodeURIComponent($this.SubCategory());
214      }
215    }
216    $this.SubCategoryUrl(sub_url);
217  };
218
219  this.updateSubSubCategoryUrl = function (item) {
220    var sub_url = $this.SubCategoryUrl();
221    var subsub_url = sub_url;
222    if ( item !== null ) {
223      if ( item.key === 'type' && item.term === 'other wine' ) {
224        subsub_url = sub_url + '&' + item.key + '=' + encodeURIComponent('all other wine');
225      } else {
226        subsub_url = sub_url + '&' + item.key + '=' + encodeURIComponent(item.term);
227      }
228    }
229    $this.SubSubCategoryUrl(subsub_url);
230  };
231
232  this.updateStyleUrl = function () {
233    var sub_url = '#';
234
235    if ($this.Category() != null ) {
236      var param = 'type';
237
238      if ( $this.Category() == 'beer' ) {
239        param = 'style';
240      }
241
242      sub_url = '/product-catalogue?category=' + encodeURIComponent($this.Category()) + '&' + param + '=' + encodeURIComponent($this.Style());
243    }
244
245    $this.StyleUrl(sub_url);
246  };
247
248  this.HasPromotion = ko.computed(function () {
249    return getParameterByName('promotionId') != null;
250  });
251
252  this.ShowListView = function () {
253    $this.LayoutType('list');
254    $this.UpdateAvailability($this.ProductResults());
255  };
256
257  this.ShowGridiew = function () {
258    $this.LayoutType('grid');
259    $this.UpdateAvailability($this.ProductResults());
260  };
261
262  this.ToggleView = function () {
263    $this.LayoutType($this.LayoutType() == 'grid' ? 'list' : 'grid');
264
265  };
266
267  this.GetFilterCounts = function (section) {
268    return _($this.FilterAggregationsSummary())
269      .filter(function (x) { return ((section || '') == '' || x.key == section); })
270      .map(function (x) { return x.Items; })
271      .flatten()
272      .filter(function (x) { return x.isSelected(); })
273      .value()
274      .length;
275  };
276
277  this.SelectedFilters = ko.computed(function (section) {
278    let paramGroup = getParameterByName('group');
279    let paramCategoryclass = getParameterByName('categoryclass');
280
281    return _($this.FilterAggregationsSummary())
282      .filter(function (x) { return ((section || '') == '' || x.key == section); })
283      .map(function (x) { return x.Items; })
284      .flatten()
285      .filter(function (x) {
286        if ( (paramGroup == 'sale' || paramGroup == 'promotions' ) && paramCategoryclass) {
287          switch(x.item.key) {
288            case 'Beer':
289            case 'Spirits':
290            case 'Coolers & Ciders':
291            case 'Wine':
292              let newCategory = paramCategoryclass.split(',')[0];
293              if (newCategory !== x.item.key.toLowerCase()) {
294                x.isSelected(false);
295              }
296              break;
297            default:
298              break;
299          }
300        }
301        return x.isSelected();
302      })
303      .value();
304  });
305
306  this.FiltersSelected = ko.computed(function (section) {
307    return $this.SelectedFilters().length > 0 || false;
308  });
309
310  this.GroupedResults = ko.computed(function () {
311    return _($this.ProductResults())
312      .map(function (x, i) { return {item: x, index: i}; })
313      .groupBy(function (x) { return Math.floor(x.index / 4); })
314      .map(function (x) {
315        var items = _.map(x, function (x) { return x.item; });
316
317        return [items.slice(0, 2), items.slice(2)];
318      }).value();
319  });
320
321  this.ClearAllFilters = function (section) {
322    $this.GrabbingProducts(true);
323
324    _($this.FilterAggregationsSummary())
325      .filter(function (x) { return ((section || '') == '' || x.key == section); })
326      .map(function (x) { return x.Items; })
327      .flatten()
328      .each(function (x) {
329        if (x.item.key == 'On Sale' && getParameterByName('group') == 'sale') {
330          x.isSelected(true);
331        } else if (x.item.key == 'BCL Select' && getParameterByName('group') == 'promotions' && getParameterByName('special').includes('bcl select' )) {
332          x.isSelected(true);
333        }
334        else if (x.item.key == 'New Product' && getParameterByName('group') == 'promotions' && getParameterByName('special').includes('new product')) {
335          x.isSelected(true);
336        }
337          else{
338          x.isSelected(false);
339        }
340      });
341
342
343    $this.GrabbingProducts(false);
344    $this.GrabProducts(1, true);
345  };
346
347  this.HideMobileFilters = function () {
348    $this.MobileFiltersVisible(false);
349  };
350
351  this.ShowMobileFilters = function () {
352    if (window.scrollY) {
353      window.scroll(0, 0); // reset the scroll position to the top left of the document.
354    }
355
356    $this.MobileFiltersVisible(!$this.MobileFiltersVisible());
357  };
358
359  this.FormatedSearchQuery = ko.computed(function () {
360    //return ($this.SearchQuery() || '').replace(/\+/g, ' ').replace(/"/g, '');
361    return ($this.SearchQuery() || '').replace(/\+/g, ' ');
362  });
363
364  this.SectionHasItems = function (section) {
365    return _.sum(
366      _.map(
367        section.Items, function (x) {
368          return x.item.doc_count;
369        }
370      )
371    ) > 0;
372  };
373
374  this.GetFilterKeys = function (filterData) {
375    if (filterData == null) { return {}; }
376    return _.map(filterData, function (item) {
377      return _(item.Items)
378        .filter(function (x) {
379          if (x.item.key == 'On Sale' && getParameterByName('group') == 'sale') { // Do not let users to deselect Sale filter
380            x.isSelected(true);
381          }
382
383          if ((x.item.key == 'BCL Select') && getParameterByName('group') == 'promotions' && getParameterByName('special').includes('bcl select')) { // Do not let users to deselect Promotions filter
384            x.isSelected(true);
385          }
386
387          if (( x.item.key == 'New Product') && getParameterByName('group') == 'promotions' && getParameterByName('special').includes('new product')) { // Do n
387ot let users to deselect Promotions filter
388            x.isSelected(true);
389          }
390
391          return x.isSelected();
392        })
393        .map(function (x) {
394          return '(' + item.key + ':' + (item.type === 'range' ? '[' + x.item.key.toString().replace(/\-/g, '+TO+') + ']' : '"' + encodeURIComponent(x.item.key.toString()) + '"') + ')';
395        })
396        .value();
397    });
398  };
399
400  this.ToggleSort = function (sortKey) {
401    if (($this.SortLast() == null || ($this.SortLast() != 'name.raw' && $this.Sort() !== sortKey)) && getParameterByName('search') !== null) {
402      $this.SortLast(sortKey);
403      if (sortKey == 'name.raw') {
404        $this.SortDirection('asc')
405      } else {
406        $this.SortDirection('desc')
407      }
408      $this.Sort(sortKey);
409
410      $this.Page(1);
411      $this.GrabProducts(1, true);
412    } else {
413      $this.SortLast(sortKey);
414      if ($this.Sort() == sortKey) {
415        $this.SortDirection($this.SortDirection() == 'asc' ? 'desc' : 'asc');
416      }
417      else {
418        if (sortKey == 'name.raw') {
419          $this.SortDirection('asc')
420        } else {
421          $this.SortDirection('desc')
422        }
423        $this.Sort(sortKey);
424      }
425
426      $this.Page(1);
427      $this.GrabProducts(1, true);
428    }
429  };
430
431  this.GetFilterBuckets = function (aggData) {
432    if (aggData.buckets) {
433      return aggData.buckets;
434    }
435    else if (aggData.varietals) {
436      return aggData.varietals.buckets;
437    }
438
439    return null;
440  };
441
442  this.IESpacingFixCheck = function (item) {
443    var ua = window.navigator.userAgent;
444
445    if (ua.indexOf('Trident/') > 0 || ua.indexOf('MSIE ') > 0) // If Internet Explorer, return version number
446    {
447      item.innerText = '         ' + item.innerText;
448    }
449  };
450
451  this.GrabProducts = function GrabProducts(page, clearResults, scrollToTop) {
452
453
454    VMInitialRequest += 1;
455
456    if (page === undefined || page === null ) {
457      // $this.GrabbingProducts(false);
458      return;
459    }
460
461    if ($this.GrabbingProducts() == true) { return; }
462
463    $this.GrabbingProducts(true);
464
465    var this_sort = $this.Sort() + ':' + $this.SortDirection();
466
467    if ( $this.SortLast() == null && getParameterByName('search') != null ) {
468      this_sort = '_score:';
469      // apparently by not doing custom sorting will allow search results to actually show all of it
470    }
471
472    if (VMInitialRequest == 1) {
473        InitialParam = (getParameterByName('category') != null ? 'category=' + encodeURIComponent(getParameterByName('category')) : '') +
474        (getParameterByName('search') != null ? '&search=' + encodeURIComponent(getParameterByName('search')) : '')+
475        (getParameterByName('type') != null ? '&type=' + encodeURIComponent(getParameterByName('type')) : '')+
476        ($this.PromotionData() != null ? '&promotion=' + encodeURIComponent($this.PromotionData().short_title) + '&sku=' : '') +
477        ($this.PromotionData() != null && $this.PromotionData().skus != null ? encodeURIComponent($this.PromotionData().skus.map(function (item) { return item; }).join(',')) : '');
478        // override to do sort by score with pages
479        if ( getParameterByName('search') != null ) {
480          // this_sort = '_score:desc';
481          $this.Sort('_score');
482          this_sort = '_score:desc';
483        }
484
485        if (getParameterByName('group') == 'sale' || getParameterByName('group') == 'promotions' ) {
486          InitialParam = '';
487        }
488    }
489    var filters = $this.GetFilterKeys($this.FilterAggregationsSummary());
490    var searchUrl = BCLS.Config.SearchEndPoint;
491    var filterCount = _.filter(filters, function (x) { return x.length > 0;}).length;
492    var urlParams =
493      (getParameterByName('category') != null ? '&category=' + encodeURIComponent(getParameterByName('category')) : '') +
494      (getParameterByName('categoryclass') != null ? '&categoryclass=' + encodeURIComponent(getParameterByName('categoryclass')) : '') +
495      (getParameterByName('search') != null ? '&search=' + encodeURIComponent(getParameterByName('search')) : '') +
496      (getParameterByName('subtype') != null ? '&subtype=' + encodeURIComponent(getParameterByName('subtype')) : '') +
497      (getParameterByName('maincategory') != null ? '&maincategory=' + encodeURIComponent(getParameterByName('maincategory')) : '') +
498      (getParameterByName('subcategory') != null ? '&subcategory=' + encodeURIComponent(getParameterByName('subcategory')) : '') +
499      (getParameterByName('style') != null ? '&style=' + encodeURIComponent(getParameterByName('style')) : '') +
500      (getParameterByName('group') != null ? '&group=' + encodeURIComponent(getParameterByName('group')) : '') +
501      (getParameterByName('special') != null ? '&special=' + encodeURIComponent(getParameterByName('special')) : '') +
502      (getParameterByName('sub') != null ? '&sub=' + encodeURIComponent(getParameterByName('sub')) : '') +
503      (getParameterByName('subsub') != null ? '&subsub=' + encodeURIComponent(getParameterByName('subsub')) : '') +
504      (getParameterByName('red') != null ? '&red=' + encodeURIComponent(getParameterByName('red')) : '') +
505      (getParameterByName('white') != null ? '&white=' + encodeURIComponent(getParameterByName('white')) : '') +
506      (getParameterByName('cert') != null ? '&cert=' + encodeURIComponent(getParameterByName('cert')) : '') +
507      (getParameterByName('sku') != null ? '&sku=' + encodeURIComponent(getParameterByName('sku')) : '') +
508      (getParameterByName('type') != null ? '&type=' + encodeURIComponent(getParameterByName('type')) : '') +
509      (getParameterByName('price') != null ? '&price=' + encodeURIComponent(getParameterByName('price')) : '') +
510      (getParameterByName('volume') != null ? '&volume=' + encodeURIComponent(getParameterByName('volume')) : '') +
511      (getParameterByName('country') != null ? '&country=' + encodeURIComponent(getParameterByName('country')) : '') +
512      (getParameterByName('region') != null ? '&region=' + encodeURIComponent(getParameterByName('region')) : '') +
513      (getParameterByName('sku') != null ? '&sku=' + encodeURIComponent(getParameterByName('sku')) : '') +
514      (getParameterByName('q') != null ? '&q=' + encodeURIComponent(getParameterByName('q')) : '') +
515      ($this.PromotionData() != null ? '&promotion=' + encodeURIComponent($this.PromotionData().short_title) + '&sku=' : '') +
516      ($this.PromotionData() != null && $this.PromotionData().skus != null ? encodeURIComponent($this.PromotionData().skus.map(function (item) { return item; }).join(',')) : '');
517    if(getParameterByName('type') === 'rose') {
518      urlParams = urlParams.replace('type=rose', 'type=rose%20wine')
519    }
520    var sortUrl = '&' +
521      ('sort=' + this_sort) +
522      ('&size=' + $this.PageSize) +
523      ('&page=' + $this.Page());
524
525
526    if (getParameterByName('sort') !== null) {
527      this_sort = getParameterByName('sort');
528    }
529
530    if (getParameterByName('page') !== null) {
531      $this.Page(getParameterByName('page'));
532    }
533
534
535
536    var url = searchUrl + '?' +
537      ('sort=' + this_sort) +
538      urlParams +
539      ('&size=' + $this.PageSize) +
540      ('&page=' + $this.Page());
541    // if there is no request body OR this is not an initial request (eg. A filter update)
542    if ($this.InitialRequestBody != null || VMInitialRequest > 1) {
543      var filterKeys = _($this.FilterAggregationsSummary())
544        .map(function (parent) { return _.map(_.filter(parent.Items, function (item) { return item.isSelected(); }), function (child) {
545          return {section: parent.key, item: child}; }); })
546        .flatten()
547        .groupBy(function (item) { return item.section; })
548        .mapValues(function (item) { return _.map(item, function (filter) { return filter.item.item.key; }); })
549        .value();
550
551      if (getParameterByName('categoryclass') != null) {
552        // limit category selection to only 1
553        let categoryArray = getParameterByName('categoryclass').split(',');
554        let newCategoryArray = filterKeys['category.description'] || [];
555        let categoryUpdate = [];
556        if (categoryArray.length == newCategoryArray.length) {
557          categoryUpdate = newCategoryArray;
558        } else {
559          categoryUpdate = _.filter(newCategoryArray, function (category) {
560            return categoryArray.indexOf(category.toLowerCase()) == -1;
561          })
562        }
563        if (categoryUpdate.length == 0) {
564          delete filterKeys['category.description'];
565        } else {
566          filterKeys['category.description'] = [categoryUpdate[0]];
567        }
568      }
569
570
571      // Clears any checked children filters if category is unchecked
572      if (getParameterByName('group') == 'sale' ||  getParameterByName('group') == 'promotions') {
573
574        if (!filterKeys['category.description']) {
575          delete filterKeys['productType'];
576          delete filterKeys['redVarietal'];
577          delete filterKeys['whiteVarietal'];
578          delete filterKeys['productCategory']; // Beer Type
579          delete filterKeys['productSubCategory']; // Beer Sub-type
580          delete filterKeys['style']; // Beer Style
581          delete filterKeys['class.description']; // Spirits Sub-type
582        }
583
584        if (!filterKeys['productCategory']) {
585          delete filterKeys['productSubCategory']; // Beer Sub-type
586        }
587
588        if (filterKeys['productType'] && !filterKeys['productType'].includes('Whisky / Whiskey')) {
589          delete filterKeys['class.description']; // Spirits > Whisky / Whiskey > Whisky filter section
590        }
591      }
592
593
594      $this.getCategories(filterKeys);
595      $this.filterKeys(filterKeys);
596
597      // function checks your your filters and generates an appending url to update url with
598      var appendUrl = createAppendUrl(filterKeys);
599      var group = getParameterByName('group');
600
601      if (group !== null) {
602        appendUrl = '&group=' + group + appendUrl;
603      }
604      if (InitialParam == '') {
605        appendUrl = appendUrl.replace('&', '');
606      }
607
608      var requestFunc = jQuery.post.bind($this, searchUrl + '?' + InitialParam + appendUrl + sortUrl, JSON.stringify(_.merge({},
609      $this.InitialRequestBody, filterKeys, {_lastSection: $this.LastSection})));
610      var stateObj = {test: "test"};
611      var newURL = 'product-catalogue?' + InitialParam + appendUrl + sortUrl;
612      history.replaceState(stateObj, "filtered", newURL);
613   } else {
614
615    if (getParameterByName('sort') !== null) {
616      this_sort = getParameterByName('sort');
617      var sorts = this_sort.split(':');
618      $this.Sort(sorts[0]);
619      $this.SortDirection(sorts[1]);
620    }
621
622    var requestFunc = jQuery.get.bind($this, url);
623    if (getParameterByName('page') !== null) {
624      page = getParameterByName('page');
625    }
626
627   }
628    requestFunc()
629      .done(function (data) {
630
631        if (clearResults || false) {
632          $this.NoMoreProducts = false;
633          $this.ProductResults([]);
634        }
635        $this.InitialRequestBody = _.pickBy(data.search, function (value, key) { return $this.NonFacets.indexOf(key) > -1; });
636        $this.InitialRequestBody = null;
637
638        let productHits = [];
639
640        if ( data.hits !== undefined ) {
641          productHits = data.hits.hits;
642        } else {
643          data.hits = {
644            total: 0,
645            total_pages: 0
646          };
647        }
648
649        // add search highlight
650        if ( $this.SearchTerms() !== '' && $this.SearchTerms().length > 0 ) {
651          var searchTerms = $this.SearchTerms().join(' ').toUpperCase().split(' ');
652          var newProductHits = productHits.map(function (hit, index) {
653            var newHit = hit;
654            var productNames = hit._source.name.split(' ');
655
656            var newNames = productNames.map(function (word) {
657              if ( searchTerms.indexOf(word) >= 0) {
658                return '<b>' + word + '</b>';
659              } else {
660                return word;
661              }
662            });
663
664            newNames = newNames.join(' ');
665
666            newHit._source.name = newNames;
667            return newHit;
668          });
669          productHits = newProductHits;
670        }
671
672        ko.utils.arrayPushAll($this.ProductResults, productHits);
673
674        // console.info(productHits.length);
675
676        if (productHits.length && productHits.length == 0) {
677          $this.NoMoreProducts = true;
678        }
679
680        $this.TotalProducts(data.hits.total);
681
682        var newFilterAggregations = data.aggregations;
683        var lastSectionKey = data.search._lastSection;
684        var lastSectionIndex = null;
685        var lastSectionData = null;
686
687        // if there is a last section, preserve last section
688        if ( lastSectionKey == null || lastSectionKey == undefined ) {
689          $this.FilterAggregations(data.aggregations);
690        } else if ( data.search[lastSectionKey] == undefined  ) {
691          $this.FilterAggregations(data.aggregations);
692        } else {
693          if (lastSectionKey == 'productType') {
694            lastSectionKey = 'Type';
695          }
696          if (lastSectionKey == 'redVarietal') {
697            lastSectionKey = 'Red Varietal';
698          }
699          if (lastSectionKey == 'whiteVarietal') {
700            lastSectionKey = 'White Varietal';
701          }
702          if (lastSectionKey == 'currentPrice') {
703            lastSectionKey = 'Price';
704          }
705          if (lastSectionKey == 'volume') {
706            lastSectionKey = 'Volume';
707          }
708          if (lastSectionKey == 'countryName.raw') {
709            lastSectionKey = 'Country';
710          }
711          if (lastSectionKey == 'region') {
712            lastSectionKey = 'Region';
713          }
714          if (lastSectionKey == 'style') {
715            lastSectionKey = 'Style';
716          }
717          if (lastSectionKey == 'certificates') {
718            lastSectionKey = 'Other';
719          }
720          if (lastSectionKey == 'class.description') {
721            lastSectionKey = 'Whisky';
722          }
723          if (lastSectionKey == 'category.description') {
724            lastSectionKey = 'Category';
725          }
726          if (lastSectionKey == 'productCategory') { // Beer's maincategory Type (space included)
727            lastSectionKey = 'Type ';
728          }
729          // get previous aggregations and replace current section with previous data
730          // to preserver data
731          var lastAggregation = $this.FilterAggregations();
732          if ( lastAggregation[lastSectionKey] !== undefined ) {
733            newFilterAggregations[lastSectionKey] = lastAggregation[lastSectionKey];
734          }
735          $this.FilterAggregations(newFilterAggregations);
736        }
737
738        $this.FilterAggregationsSummary(_.orderBy(_.map(newFilterAggregations, $this.BuildSummaryItem), 'order'));
739
740        $this.Page(page);
741        $this.TotalPages(data.hits.total_pages);
742
743        _(
744          _.intersectionWith(
745            $this.FilterAggregationsSummary(),
746            _.keys(data.search),
747            function(filter, key) {
748              return key == filter.key;
749            }
750          )
751        )
752          .map(function(item) {
753            return {
754              filter: item,
755              itemsToSelect:
756                data.search[item.key] instanceof Array
757                  ? data.search[item.key]
758                  : [data.search[item.key]],
759            };
760          })
761          .map(function(item) {
762            return _.intersectionWith(
763              item.filter.Items,
764              item.itemsToSelect,
765              function(item, selectKey) {
766                if (
767                  Object.prototype.toString.call(selectKey) ===
768                  '[object String]'
769                ) {
770                  // prices
771                  selectKey = selectKey
772                    .replace('-9.99', '-10.0')
773                    .replace('-19.99', '-20.0')
774                    .replace('-49.99', '-50.0')
775                    .replace('-99.99', '-100.0')
776                    .replace('-199.99', '-200.0')
777                    .replace('-499.99', '-500.0');
778
779                  // volumes
780                  selectKey = selectKey
781                    .replace('-0.249', '-0.25')
782                    .replace('-0.499', '-0.5')
783                    .replace('-0.749', '-0.75')
784                    .replace('-0.999', '-1.0')
785                    .replace('-1.249', '-1.25')
786                    .replace('-1.499', '-1.5')
787                    .replace('-1.749', '-1.75')
788                    .replace('-1.999', '-2.0')
789                    .replace('-2.999', '-3.0')
790                    .replace('-3.999', '-4.0');
791                }
792
793                if (
794                  _.isString(item.item.key) &&
795                  _.isString(selectKey)
796                ) {
797                  return (
798                    item.item.key.toLowerCase() ==
799                    selectKey.toLowerCase()
800                  );
801                } else {
802                  return item.item.key == selectKey;
803                }
804              }
805            );
806          })
807          .flattenDeep()
808          .each(function(item) {
809            item.isSelected(true);
810          });
811
812        if (window.localStorage) {
813          window.localStorage.setItem($this.LS_KEY, ko.toJSON($this.FilterAggregationsSummary()));
814          window.localStorage.setItem($this.LS_FILTER_KEY, true);
815        }
816
817        if ($this.SlideoutProducts()) {
818          _.each($this.FilterAggregationsSummary(), function (item) {
819            if (item.key != ($this.LastSection || '')) { item.expanded(false); }
820            else { item.expanded(true); }
821          });
822        }
823        else {
824          _.each(_.filter($this.FilterAggregationsSummary(), $this.HasCheckedItems), function (item) { item.expanded(true); });
825          _.each(_.filter($this.FilterAggregationsSummary(), $this.HasCheckedItems), function (item) { if ($this.HasItemCheckedBelowShowMore(item)) { item.expandMoreItems(true); } });
826        }
827
828        if (scrollToTop) {
829          window.scrollTo(0, 0);
830        }
831
832        setTimeout(function () {
833          // jQuery('.product-list-container .product-list-item h3').matchHeight({ byRow: false });
834          jQuery('.product-list-container .product-list-item .col-xs-8').matchHeight({byRow: false});
835          $this.loading(false);
836        }, 100);
837
838        $this.UpdateAvailability(productHits);
839        $this.GrabbingProducts(false);
840      })
841      .always(function (data) {
842        // console.info('always');
843        // remove loading even if response is 500
844        $this.loading(false);
845        $this.GrabbingProducts(false);
846      });
847  };
848
849  this.UpdateAvailability = function(productHits) {
850    if (productHits.length && productHits.length > 0 ) {
851      var skus_array = productHits.map( function( product ) {
852        if ( product._id !== undefined ) {
853          return product._id;
854        }
855      });
856
857      var skus = skus_array.join(',');
858      var url = BCLS.Config.ProductInventorySumEndpoint + '?skus=' + skus;
859
860      jQuery.get( url, function( data1 ) {
861      }).done(function(data) {
862        var inventory = 0;
863
864        skus_array.forEach(function( sku ) {
865          if (data[sku] !== undefined) {
866            inventory = data[sku].available;
867          }
868          if (inventory > 0) {
869            jQuery('#availability-' + sku).text('In Stock');
870          } else {
871            jQuery('#availability-' + sku).text('Out of Stock');
872          }
873          if (data[sku] === undefined){
874            jQuery('#availability-' + sku).text('Out of Stock');
875          }
876        });
877      })
878    }
879  }
880
881  var DisplayValueFormatters = {
882    ml: function (item) {
883      var from = item.from || 0;
884      var to = item.to || 0;
885      // minus 0.001 so it will show 0.999 instead of 1.0
886
887      if ( from < 0.999 ) {
888        from = ( from.toFixed(3)  * 1000 ) + ' mL';
889      } else {
890        from = ( from.toFixed(2) ) + ' L';
891      }
892
893      if ( to == 0 ) {
894        to = '+';
895      } else if ( to <= 1 ) {
896        to = ' - ' + ( ( to.toFixed(3) * 1000 ) - 1) + ' mL';
897      } else {
898        to = ' - ' + ( to.toFixed(3) - 0.001 ) + ' L';
899      }
900
901      return from + to;
902    },
903    dollars: function (item) {
904      // minus 0.01 so it shows 9.99 instead of 10
905      var from = '$' + (item.from || 0).toFixed(2);
906      var to = null;
907      if (item.to == null || item.to == undefined) {
908        to = '+';
909      } else {
910        to = ' - ' + (item.to - 0.01).toFixed(2);
911      }
912      return from + to;
913    }
914  };
915
916  function isSelectedUpdate(section) {
917    $this.LastSection = section.key;
918
919    if (!$this.SlideoutProducts()) {
920      // window.scrollTo(0, 0);
921    }
922
923    $this.GrabProducts(1, true);
924  }
925
926  var AggregatorFormatters = {
927    range: function (key, section, item) {
928      var unit = (BCLS.Config.ProductFilterDefinitionsUnits[key] || 'raw');
929      var isSelected = ko.observable(false);
930      isSelected.subscribe(isSelectedUpdate.bind(null, section));
931
932      return {
933        isSelected: isSelected,
934        displayValue: (DisplayValueFormatters[unit] ?
935          DisplayValueFormatters[unit](item) :
936          (item.from + ' - ' + item.to)),
937        item: item,
938        hide: (key == 'Price' ? item.doc_count == 0 : false)
939      };
940    },
941    terms: function (key, section, item) {
942      var unit = (BCLS.Config.ProductFilterDefinitionsUnits[key] || 'raw');
943      var isSelected = ko.observable(false);
944      var keyCapitalized = toCapitalized(item.key);
945      isSelected.subscribe(isSelectedUpdate.bind(null, section));
946
947      return {
948        displayValue: (DisplayValueFormatters[unit] ? DisplayValueFormatters[unit](item) : item.key),
949        isSelected: isSelected,
950        item: item,
951      };
952    }
953  };
954
955  this.ToggleSection = function (section) {
956    var curVal = section.expanded();
957
958    if ($this.SlideoutProducts() && !curVal) {
959      _.forEach($this.FilterAggregationsSummary(), function (item) { item.expanded(false); });
960    }
961
962    section.expanded(!curVal);
963
964    if ($this.SlideoutProducts() && !curVal) {
965      jQuery('.filters-container')[0].scrollTop = jQuery(".filters-container h3[data-skey='" + section.key + "']")[0].offsetTop;
966    }
967  };
968
969  this.HasCheckedItems = function (section) {
970    return _.reduce(section.Items, function (ag, item) { return item.isSelected() || ag; }, false);
971  };
972
973  this.BuildSummaryItem = function (item, key) {
974    var type = _.keys(BCLS.Config.ProductFilterDefinitions.aggs[key])[0];
975    var index = _.keys(BCLS.Config.ProductFilterDefinitions.aggs).indexOf(key);
976    var keyName = (BCLS.Config.ProductFilterDefinitions.aggs[key].terms || BCLS.Config.ProductFilterDefinitions.aggs[key].range).field;
977
978    var section = {
979      key: keyName,
980      type: type,
981      expanded: ko.observable(!($this.FieldsToCollapse.indexOf(key) > -1)),
982      expandMoreItems: ko.observable(false),
983      SummaryHeader: key, // .replace(/\-/g, ' ')
984      Items: null,
985      order: index
986    };
987
988    var items = _.map(item.buckets, AggregatorFormatters[type].bind(null, key, section));
989    section.Items = items;
990
991    let paramGroup = getParameterByName('group');
992    let paramCategoryclass = getParameterByName('categoryclass');
993    let paramType = getParameterByName('type') ? getParameterByName('type').split(',') : [];;
994    let paramSpecial = getParameterByName('special') ? getParameterByName('special').split(',') : [];
995    let paramCert = getParameterByName('cert') ? getParameterByName('cert').split(',') : [];
996    let paramBeerType = getParameterByName('maincategory') ? getParameterByName('maincategory').split(',') : [];
997
998    if (paramGroup == 'sale' || paramGroup == 'promotions'  ) {
999      switch (key) {
1000        case 'Category':
1001          sortedItems = [];
1002          _.each(section.Items, function (filter) {
1003            switch (filter.displayValue) {
1004              case 'Wine':
1005                sortedItems[0] = filter;
1006                break;
1007              case 'Beer':
1008                sortedItems[1] = filter;
1009                break;
1010              case 'Spirits':
1011                sortedItems[2] = filter;
1012                break;
1013              case 'Coolers & Ciders':
1014                sortedItems[3] = filter;
1015                break;
1016              default:
1017                break;
1018            }
1019          });
1020          section.Items = sortedItems;
1021          break;
1022        case 'Red Varietal':
1023        case 'White Varietal':
1024          if (paramCategoryclass == 'wine') {
1025            break;
1026          }
1027          section.Items = [];
1028          break;
1029        case 'Type':
1030          if (paramCategoryclass == 'spirits'  || paramCategoryclass == 'wine' || paramCategoryclass == 'coolers & ciders') {
1031            break;
1032          }
1033          section.Items = [];
1034          break;
1035        case 'Type ':
1036          if (paramCategoryclass == 'beer') {
1037            break;
1038          }
1039          section.Items = [];
1040          break;
1041        case 'Sub-type':
1042          if (paramCategoryclass == 'beer' && paramBeerType.includes('domestic beer')) {
1043            break;
1044          }
1045          section.Items = [];
1046          break;
1047        case 'Style':
1048          if (paramCategoryclass == 'beer') {
1049            break;
1050          }
1051          section.Items = [];
1052          break;
1053        case 'Whisky':
1054          if (paramType.includes('whisky / whiskey')) {
1055            break;
1056          }
1057          section.Items = [];
1058          break;
1059        default:
1060          break;
1061      }
1062
1063    } else {
1064      if (key == 'Category') {
1065        section.Items = [];
1066      }
1067    }
1068
1069    // hide all other temporary featured promotions
1070    if (key == 'Featured') {
1071      section.Items = _.map(section.Items, function (filter) {
1072        switch(filter.displayValue) {
1073          case 'BC VQA':
1074          case 'BCL Select':
1075          case 'New Product':
1076          case 'On Sale':
1077            return filter;
1078          default:
1079            filter.hide = true;
1080            filter.item.doc_count = 0;
1081            return filter;
1082        }
1083      })
1084    }
1085
1086    // hide custom BC VQA & VQA cert field filter in Other
1087    if (key == 'Other') {
1088      section.Items = _.map(section.Items, function (filter) {
1089        switch(filter.displayValue) {
1090          case 'BC VQA':
1091            filter.hide = true;
1092            filter.item.doc_count = 0;
1093            return filter;
1094          case 'All VQA':
1095            if (paramSpecial.includes('bc vqa') || paramCert.includes('vqa ontario') ) {
1096              filter.hide = true;
1097              filter.item.doc_count = 0;
1098            }
1099            return filter
1100          default:
1101            return filter;
1102        }
1103      })
1104    }
1105
1106    return section;
1107  };
1108
1109  this.IncrementPage = function (inc) {
1110    var nextPage = $this.Page() + (inc || 1);
1111    if (nextPage > $this.TotalPages() || nextPage < 1) { return; }
1112
1113    $this.Page(nextPage);
1114    $this.GrabProducts(nextPage, true, true);
1115  };
1116
1117  this.SetMobileFilterHeight = function () {
1118    // This calculation is for mobile filters:
1119    var windowHeight = jQuery(window).height();
1120    var filtersOffset = jQuery('.filters-column').offset().top;
1121    var clearApplyHeight = jQuery('.clear-apply-filter-container').height();
1122
1123
1124    jQuery('.filters-container').css('height', (windowHeight - filtersOffset - clearApplyHeight) + 'px');
1125    jQuery('body').css({height: windowHeight + 'px', overflow: 'hidden'});
1126  };
1127
1128  $this.SlideoutProducts.subscribe(function (val) {
1129    if (val) {
1130      _.forEach($this.FilterAggregationsSummary(), function (item) { item.expanded(false); });
1131      // window.scrollTo(0, 0);
1132      $this.SetMobileFilterHeight();
1133    }
1134    else {
1135      jQuery('.filters-container').css('height', 'auto');
1136      jQuery('body').css({height: 'auto', overflow: 'visible'});
1137      jQuery('.bcls-main-container').css({position: 'static'/* , "padding-top": $this.MainContainerDefaultPadding */});
1138    }
1139  });
1140
1141  $this.ToggleSubItemsExpanded = function (item) {
1142    item.expandMoreItems(!item.expandMoreItems());
1143  };
1144
1145  jQuery(window).resize(function () {
1146    if ($this.SlideoutProducts()) {
1147      $this.SetMobileFilterHeight();
1148    }
1149  });
1150
1151  this.getCategories = function (filterKeys) {
1152    var SubCategory = [];
1153    var SubSubCategory = [];
1154    var Style = [];
1155    var group = $this.breadcrumbGroup;
1156    var subsub_item = null;
1157    var subsub_item_key = null;
1158    // filterKeys will be null if user clicks menu, else redirected by filters
1159    if ( filterKeys == null ) {
1160      var category_description = getParameterByName('categoryclass');
1161      var type = getParameterByName('type');
1162      var subtype = getParameterByName('subtype');
1163      var special = getParameterByName('special');
1164      var countryName = getParameterByName('country');
1165      var region = getParameterByName('region');
1166      var red = getParameterByName('red');
1167      var white = getParameterByName('white');
1168      var cert = getParameterByName('cert');
1169      var maincategory = getParameterByName('maincategory');
1170      var subcategory = getParameterByName('subcategory');
1171      var style = getParameterByName('style');
1172    } else {
1173      var category_description = filterKeys['category.description'] ? filterKeys['category.description'] : null;
1174      var type = filterKeys.productType ? filterKeys.productType : null;
1175      var subtype = filterKeys['class.description'] ? filterKeys['class.description'] : null;
1176      var special = filterKeys.featured ? filterKeys.featured : null;
1177      var countryName = filterKeys['countryName.raw'] ? filterKeys['countryName.raw'] : null;
1178      var region = filterKeys['region.raw'] ? filterKeys['region.raw'] : null;
1179      var red = filterKeys.redVarietal ? filterKeys.redVarietal : null;
1180      var white = filterKeys.whiteVarietal ? filterKeys.whiteVarietal : null;
1181      var cert = filterKeys['certificates'] ? filterKeys['certificates'] : null;
1182      var maincategory = filterKeys['productCategory'] ? filterKeys['productCategory'] : null;
1183      var subcategory = filterKeys['productSubCategory'] ? filterKeys['productSubCategory'] : null;
1184      var style = filterKeys['style'] ? filterKeys['style'] : null;
1185
1186      if (maincategory !== null) {
1187        type = filterKeys.productCategory;
1188      }
1189    }
1190
1191    if ( type ) {
1192      if(cidersOrigin == 'domestic cider'){
1193        type = 'domestic cider'
1194      }
1195      if(cidersOrigin == 'import cider'){
1196        type = 'import cider'
1197      }
1198      SubCategory = type;
1199    }
1200    if ( maincategory ) {
1201      SubCategory = maincategory;
1202    }
1203
1204    if ( subtype ) {
1205      subsub_item_key = 'subtype';
1206      SubSubCategory = subtype;
1207    }
1208    if ( red ) {
1209      subsub_item_key = 'red';
1210      SubSubCategory = red;
1211    }
1212    if ( white ) {
1213      subsub_item_key = 'white';
1214      SubSubCategory = white;
1215    }
1216
1217    // overriding sub and subsub depends on group
1218    if ( group == 'country' || group == 'all countries' ) {
1219      SubCategory = ['country'];
1220      subsub_item_key = 'country';
1221      SubSubCategory = countryName;
1222    }
1223
1224    if (countryName) {
1225        SubSubCategory = countryName;
1226    }
1227
1228    if (maincategory) {
1229      type = maincategory;
1230    }
1231    if (subcategory) {
1232      subsub_item_key = 'subcategory';
1233      SubSubCategory = subcategory;
1234    }
1235
1236    if (style) {
1237      Style = style;
1238    }
1239
1240    if (group == 'promotions') {
1241      SubCategory = ['promotions'];
1242      if ( special != null ) {
1243        subsub_item_key = 'special';
1244        SubSubCategory = special;
1245      }
1246    }
1247
1248    if (group == 'sale') {
1249      SubCategory = ['sale'];
1250      if (category_description != null) {
1251        subsub_item_key = 'categoryclass';
1252        SubSubCategory = category_description;
1253      } else {
1254        subsub_item_key = '';
1255        SubSubCategory = '';
1256      }
1257      Style = '';
1258    }
1259    if (group == 'featured') {
1260      SubCategory = ['promotions'];
1261      SubSubCategory = ['featured'];
1262    }
1263
1264    if ( group == 'other wine' ) {
1265      SubCategory = ['other wine'];
1266      if(type === 'rose') {
1267        type = 'rose wine'
1268      }
1269      SubSubCategory = type;
1270      subsub_item_key = 'type';
1271      if(type !== null) {
1272        if(type[0] === 'Other Wine') {
1273          SubSubCategory = ['all other wine'];
1274        }
1275      }
1276      // key for attributes (All VQA, BC VQA, VQA Ontario, Kosher, Organic, De-Alcoholized Wine) is cert
1277      if(type == null && cert != ''){
1278        SubSubCategory = cert;
1279        subsub_item_key = 'cert';
1280      }
1281    }
1282
1283    // BC VQA overrides the other type as Sub Category because there is another nested Other Wine
1284    if (special) {
1285      if (special == 'bc vqa' || (special.length == 1 && special[0].toLowerCase() == 'bc vqa')) {
1286        SubCategory = ['bc vqa'];
1287      }
1288    }
1289
1290    if ( Array.isArray(SubCategory) ) {
1291      SubCategory = SubCategory.join(',');
1292    }
1293
1294    if ( Array.isArray(SubSubCategory) ) {
1295      SubSubCategory = SubSubCategory.join(',');
1296    }
1297
1298    if ( Array.isArray(Style) ) {
1299      Style = Style.join(',');
1300    }
1301
1302    if ( SubCategory !== null && SubCategory !== undefined ) {
1303      SubCategory = SubCategory.replace('null,', '').toLowerCase();
1304    }
1305
1306    if ( SubSubCategory !== null && SubSubCategory !== undefined ) {
1307      SubSubCategory = SubSubCategory.replace('null,', '').toLowerCase();
1308    }
1309
1310    if ( Style !== null && Style !== undefined ) {
1311      Style = Style.replace('null,', '').toLowerCase();
1312    }
1313
1314    if ( SubSubCategory !== null && SubSubCategory !== undefined && SubSubCategory.indexOf(',') >= 0 ) {
1315      SubSubCategory = null;
1316    }
1317
1318    if ( SubCategory !== null && SubCategory !== undefined && SubCategory.indexOf(',') >= 0 ) {
1319      SubCategory = null;
1320      SubSubCategory = null;
1321    }
1322
1323    if ( Style !== null && Style !== undefined && Style.indexOf(',') >= 0 ) {
1324      Style = null;
1325      // SubSubCategory = null;
1326    }
1327
1328    if ( subsub_item_key !== null && SubSubCategory !== undefined && SubSubCategory !== null ) {
1329      subsub_item = {
1330        key: subsub_item_key,
1331        term: SubSubCategory
1332      };
1333    }
1334
1335    // override special breadcrumb names
1336    if ( SubSubCategory == 'exclusive' ) {
1337      SubSubCategory = 'BCL Select';
1338    }
1339    if ( SubSubCategory == 'bcl select' ) {
1340      SubSubCategory = 'BCL Select';
1341    }
1342    if ( SubSubCategory == 'new product' ) {
1343      SubSubCategory = "what's new";
1344    }
1345
1346    $this.Category(getParameterByName('category'));
1347    $this.SubCategory(SubCategory);
1348    $this.SubSubCategory(SubSubCategory);
1349    $this.Style(Style);
1350    $this.updateSubCategoryUrl();
1351    $this.updateSubSubCategoryUrl(subsub_item);
1352    $this.updateStyleUrl();
1353
1354  };
1355
1356  (function Init() {
1357
1358    // We create a case insensitive function for finding menu elements for highlighting.
1359    // modified from: http://stackoverflow.com/a/40475075
1360    jQuery.expr[':'].ContainsInsensitive = jQuery.expr.createPseudo(function (arg) {
1361      return function (elem) {
1362        return jQuery(elem).text().toLowerCase().indexOf(arg.toLowerCase()) >= 0;
1363      };
1364    });
1365
1366
1367
1368    $this.getCategories(null);
1369    var promoEl = jQuery('#promotionData');
1370    if (promoEl !== null && promoEl !== undefined && promoEl.val() !== null && promoEl.val() !== undefined) {
1371      $this.PromotionData(JSON.parse(promoEl.val()));
1372    } else {
1373      $this.PromotionData(null)
1374    }
1375
1376    $this.Category(getParameterByName('category'));
1377
1378    $this.SearchQuery(getParameterByName('search'));
1379
1380
1381    if ($this.SearchQuery()) {
1382      // $this.SearchQuery($this.SearchQuery().replace('\"', '').replace(/"/g, ''));
1383      $this.SearchTerms($this.SearchQuery().split(' '));
1384      $this.SearchQuery($this.SearchQuery());
1385      jQuery('#header-search').val($this.SearchQuery());
1386      jQuery('#mobile-header-search').val($this.SearchQuery());
1387    }
1388
1389    if (window.localStorage && window.localStorage.getItem($this.LS_FILTER_KEY)) {
1390      if (getParameterByName('group') !== 'sale' && getParameterByName('group') !== 'promotions' ) {
1391        var filterData = JSON.parse(window.localStorage.getItem($this.LS_KEY));
1392        _.each(filterData, function (item) {
1393          item.expanded = ko.observable(item.expanded);
1394          item.expandMoreItems = ko.observable(item.expandMoreItems);
1395          _.each(item.Items, function (item) { item.isSelected = ko.observable(item.isSelected); item.isSelected.subscribe($this.GrabProducts.bind(null, 1, true)); });
1396        });
1397        $this.FilterAggregationsSummary(filterData);
1398        $this.BackButtonRestore = true;
1399      }
1400    }
1401
1402    $this.GrabProducts($this.Page(), true);
1403
1404    jQuery('body').addClass('bcls-product-list-page');
1405
1406    setTimeout(function () {
1407      jQuery('#superfish-main-toggle').click(function () {
1408        $this.SlideoutProducts(false);
1409      });
1410    }, 200);
1411
1412    var superfish = jQuery('#superfish-main');
1413
1414    if ($this.Category() != null && $this.Category() !== '') {
1415      // toUpperCase works fine for the main menu. Consider using the Case Insensitive version for consistency.
1416      var main_level_link = superfish.find("li > a:contains('" + $this.Category().toUpperCase() + "')");
1417      main_level_link.addClass('active');
1418
1419      var main_level = main_level_link.parent();
1420      main_level.addClass('active');
1421
1422      if ($this.SubCategory() != null && $this.SubCategory() !== '' ) {
1423        sub_level_link = main_level.find("ul > li > .sf-depth-2:ContainsInsensitive('" + $this.SubCategory() + "')");
1424        sub_level_link.addClass('active');
1425        sub_level_link.parent().addClass('active'); // TODO: do we need to do this?
1426      }
1427
1428      if ($this.SubSubCategory() != null && $this.SubSubCategory() !== '' ) {
1429        subsub_level_link = main_level.find("ul > li > .sf-depth-3:ContainsInsensitive('" + $this.SubSubCategory() + "')");
1430        subsub_level_link.addClass('active');
1431        subsub_level_link.parent().addClass('active'); // TODO: do we need to do this?
1432      }
1433    }
1434
1435    // Sale page filters uses SubCategory for the first breadcrumb and SubSubCategory for the children (ie. Home / Sale / Wine)
1436    if ( $this.SubCategory() == 'sale') {
1437      let main_level_link = superfish.find("li > a:contains('" + $this.SubCategory().toUpperCase() + "')");
1438      // let main_level_link = superfish.find("li > a:contains('SALE')");
1439      main_level_link.addClass('active');
1440      let main_level = main_level_link.parent();
1441      if ($this.SubSubCategory() != null && $this.SubSubCategory() !== '' ) {
1442        sub_level_link = main_level.find("ul > li > .sf-depth-2:ContainsInsensitive('" + $this.SubSubCategory() + "')");
1443        sub_level_link.addClass('active');
1444        sub_level_link.parent().addClass('active'); // TODO: do we need to do this?
1445      }
1446    }
1447
1448  })();
1449};
1450
1451function toCapitalized(string)
1452{
1453  return string.charAt(0).toUpperCase() + string.slice(1);
1454}
1455
1456jQuery(document).ready( function($) {
1457
1458  if ($('.path-promotion li.featured li.Exclusive').length ||
1459    $('.path-promotion li.featured li.On.Sale').length ||
1460    $('.path-promotion li.featured li.BCL.Select').length ||
1461    $('.path-promotion li.featured li.New.Product').length )
1462    {
1463      $('.path-promotion').addClass('show-featured');
1464    }
1465});

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.