PageSourceSearch

https://nacrasailing.com/dist/js/bundle.js?134309965877330550

js nacrasailing.com collected 2026-10-02 12:28:11 UTC 53,587 bytes, 1,596 lines download raw bytes

1var cookies = (function() {
2  var get = function(key) {
3    if (!key || !hasCookie(key)) {
4      return null;
5    }
6    return decodeURIComponent(
7      document.cookie.replace(
8        new RegExp(
9          '(?:^|.*;\\s*)' +
10            encodeURIComponent(key).replace(/[-.+*]/g, '\\$&') +
11            '\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*'
12        ),
13        '$1'
14      )
15    );
16  };
17
18  var hasCookie = function(key) {
19    return new RegExp(
20      '(?:^|;\\s*)' + encodeURIComponent(key).replace(/[-.+*]/g, '\\$&') + '\\s*\\='
21    ).test(document.cookie);
22  };
23
24  var set = function(key, value, end, path, domain, secure) {
25    if (!key || /^(?:expires|max-age|path|domain|secure)$/.test(key)) {
26      return;
27    }
28    var expires = '';
29    if (end) {
30      switch (typeof end) {
31        case 'number':
32          expires = '; max-age=' + end;
33          break;
34        case 'string':
35          expires = '; expires=' + end;
36          break;
37        case 'object':
38          if (end.hasOwnProperty('toGMTString')) {
39            expires = '; expires=' + end.toUTCString();
40          }
41          break;
42      }
43    }
44    document.cookie =
45      encodeURIComponent(key) +
46      '=' +
47      encodeURIComponent(value) +
48      expires +
49      (domain ? '; domain=' + domain : '') +
50      (path ? '; path=' + path : '') +
51      (secure ? '; secure' : '');
52  };
53
54  var remove = function(key) {
55    if (!key || !hasCookie(key)) {
56      return;
57    }
58    var expDate = new Date();
59    expDate.setDate(expDate.getDate() - 1);
60    document.cookie = encodeURIComponent(key) + '=; expires=' + expDate.toUTCString() + '; path=/';
61  };
62
63  return {
64    get: get,
65    hasCookie: hasCookie,
66    set: set,
67    remove: remove
68  };
69})();
70function supportIntersectionObserver() {
71  return 'IntersectionObserver' in window;
72}
73/**
74 * Prevent submitting form before JS is fully loaded
75 * Otherwise users can accidentally submit the form
76 * Which causes an unnecessary page reload
77 * @param form
78 */
79var enableFormSubmit = function(form) {
80  form.querySelector('[type="submit"]').removeAttribute('disabled');
81};
82var createGUID = function() {
83  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
84    var r = (Math.random() * 16) | 0,
85      v = c === 'x' ? r : (r & 0x3) | 0x8;
86    return v.toString(16);
87  });
88};
89function findParentByClass(element, cls) {
90  while ((element = element.parentElement) && !element.classList.contains(cls));
91  return element;
92}
93
94function serializeArray(form) {
95  var field,
96    l,
97    s = [];
98  if (typeof form == 'object' && form.nodeName == 'FORM') {
99    var len = form.elements.length;
100    for (var i = 0; i < len; i++) {
101      field = form.elements[i];
102      if (
103        field.name &&
104        !field.disabled &&
105        field.type != 'file' &&
106        field.type != 'reset' &&
107        field.type != 'submit' &&
108        field.type != 'button'
109      ) {
110        if (field.type == 'select-multiple') {
111          l = form.elements[i].options.length;
112          for (var j = 0; j < l; j++) {
113            if (field.options[j].selected)
114              s[s.length] = { name: field.name, value: field.options[j].value };
115          }
116        } else if ((field.type != 'checkbox' && field.type != 'radio') || field.checked) {
117          s[s.length] = { name: field.name, value: field.value };
118        }
119      }
120    }
121  }
122  return s;
123}
124
125var preparePatchArray = function(formgroups) {
126  var array = [];
127  for (var i = 0; i < formgroups.length; i++) {
128    var input = formgroups[i].querySelector('input[name]');
129    array.push({
130      op: 'replace',
131      path: '/' + input.getAttribute('name'),
132      value: input.value
133    });
134  }
135  return array;
136};
137/**
138 * Emit custom event for triggering toaster
139 * @param type
140 * @param text
141 */
142var sendToastEvent = function(type, text) {
143  window.dispatchEvent(
144    new CustomEvent('toast', {
145      detail: {
146        type: type,
147        text: text
148      }
149    })
150  );
151};
152
153/**
154 * Emit custom success event for triggering toaster
155 * @param text
156 */
157var sendSuccessToast = function(text) {
158  sendToastEvent('success', text);
159};
160
161/**
162 * Emit custom error event for triggering toaster
163 * @param text
164 */
165var sendErrorToast = function(text) {
166  sendToastEvent('error', text);
167};
168function getUrlParameters(url) {
169  var vars = [];
170  var hash;
171  var urlParameters = url ? '?' + url.split('?')[1] : window.location.search;
172
173  if (urlParameters) {
174    var hashes = urlParameters.slice(1).split('&');
175    for (var i = 0; i < hashes.length; i++) {
176      hash = hashes[i].split('=');
177      vars[hash[0]] = decodeURIComponent(hash[1]);
178    }
179    return vars;
180  }
181  return false;
182}
183
184function openUrl(url) {
185  window.location = url;
186}
187
188function getCurrentUrl() {
189  return [window.location.protocol, '//', window.location.host, window.location.pathname].join('');
190}
191
192function resetUrlPagination(url) {
193  var pathname = url.split('?')[0];
194  var pathhash = url.split('?')[1];
195  var patharray = pathname.split('/');
196  var page = false;
197
198  // set pagination back to 1
199  pathname = '';
200  for (var i = 0; i < patharray.length; i++) {
201    if (page) {
202      patharray[i] = '1';
203    }
204
205    page = patharray[i] === 'page';
206
207    pathname += patharray[i];
208
209    if (i < patharray.length - 1) {
210      pathname += '/';
211    } else if (pathhash) {
212      pathname += '?';
213    }
214  }
215
216  return (url = pathname + (pathhash || ''));
217}
218(function(root, factory) {
219  if (typeof define === 'function' && define.amd) {
220    define(factory);
221  } else if (typeof exports === 'object') {
222    module.exports = factory(require, exports, module);
223  } else {
224    root.CountUp = factory();
225  }
226})(this, function(require, exports, module) {
227  /*
228
229     countUp.js
230     by @inorganik
231
232     */
233
234  // target = id of html element or var of previously selected html element where counting occurs
235  // startVal = the value you want to begin at
236  // endVal = the value you want to arrive at
237  // decimals = number of decimal places, default 0
238  // duration = duration of animation in seconds, default 2
239  // options = optional object of options (see below)
240
241  var CountUp = function(target, startVal, endVal, decimals, duration, options) {
242    // make sure requestAnimationFrame and cancelAnimationFrame are defined
243    // polyfill for browsers without native support
244    // by Opera engineer Erik M�ller
245    var lastTime = 0;
246    var vendors = ['webkit', 'moz', 'ms', 'o'];
247    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
248      window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
249      window.cancelAnimationFrame =
250        window[vendors[x] + 'CancelAnimationFrame'] ||
251        window[vendors[x] + 'CancelRequestAnimationFrame'];
252    }
253    if (!window.requestAnimationFrame) {
254      window.requestAnimationFrame = function(callback, element) {
255        var currTime = new Date().getTime();
256        var timeToCall = Math.max(0, 16 - (currTime - lastTime));
257        var id = window.setTimeout(function() {
258          callback(currTime + timeToCall);
259        }, timeToCall);
260        lastTime = currTime + timeToCall;
261        return id;
262      };
263    }
264    if (!window.cancelAnimationFrame) {
265      window.cancelAnimationFrame = function(id) {
266        clearTimeout(id);
267      };
268    }
269
270    var self = this;
271    self.version = function() {
272      return '1.8.5';
273    };
274
275    function formatNumber(num) {
276      num = num.toFixed(self.decimals);
277      num += '';
278      var x, x1, x2, rgx;
279      x = num.split('.');
280      x1 = x[0];
281      x2 = x.length > 1 ? self.options.decimal + x[1] : '';
282      rgx = /(\d+)(\d{3})/;
283      if (self.options.useGrouping) {
284        while (rgx.test(x1)) {
285          x1 = x1.replace(rgx, '$1' + self.options.separator + '$2');
286        }
287      }
288      return self.options.prefix + x1 + x2 + self.options.suffix;
289    }
290    // Robert Penner's easeOutExpo
291    function easeOutExpo(t, b, c, d) {
292      return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b;
293    }
294    function ensureNumber(n) {
295      return typeof n === 'number' && !isNaN(n);
296    }
297
298    // default options
299    self.options = {
300      useEasing: true, // toggle easing
301      useGrouping: true, // 1,000,000 vs 1000000
302      separator: ',', // character to use as a separator
303      decimal: '.', // character to use as a decimal
304      easingFn: easeOutExpo, // optional custom easing function, default is Robert Penner's easeOutExpo
305      formattingFn: formatNumber, // optional custom formatting function, default is formatNumber above
306      prefix: '', // optional text before the result
307      suffix: '' // optional text after the result
308    };
309
310    // extend default options with passed options object
311    if (options && typeof options === 'object') {
312      for (var key in self.options) {
313        if (options.hasOwnProperty(key) && options[key] !== null) {
314          self.options[key] = options[key];
315        }
316      }
317    }
318
319    if (self.options.separator === '') self.options.useGrouping = false;
320
321    self.initialize = function() {
322      if (self.initialized) return true;
323      self.d = typeof target === 'string' ? document.getElementById(target) : target;
324      if (!self.d) {
325        return false;
326      }
327      self.startVal = Number(startVal);
328      self.endVal = Number(endVal);
329      // error checks
330      if (ensureNumber(self.startVal) && ensureNumber(self.endVal)) {
331        self.decimals = Math.max(0, decimals || 0);
332        self.dec = Math.pow(10, self.decimals);
333        self.duration = Number(duration) * 1000 || 2000;
334        self.countDown = self.startVal > self.endVal;
335        self.frameVal = self.startVal;
336        self.initialized = true;
337        return true;
338      } else {
339        return false;
340      }
341    };
342
343    // Print value to target
344    self.printValue = function(value) {
345      var result = self.options.formattingFn(value);
346
347      if (self.d.tagName === 'INPUT') {
348        this.d.value = result;
349      } else if (self.d.tagName === 'text' || self.d.tagName === 'tspan') {
350        this.d.textContent = result;
351      } else {
352        this.d.innerHTML = result;
353      }
354    };
355
356    self.count = function(timestamp) {
357      if (!self.startTime) {
358        self.startTime = timestamp;
359      }
360
361      self.timestamp = timestamp;
362      var progress = timestamp - self.startTime;
363      self.remaining = self.duration - progress;
364
365      // to ease or not to ease
366      if (self.options.useEasing) {
367        if (self.countDown) {
368          self.frameVal =
369            self.startVal -
370            self.options.easingFn(progress, 0, self.startVal - self.endVal, self.duration);
371        } else {
372          self.frameVal = self.options.easingFn(
373            progress,
374            self.startVal,
375            self.endVal - self.startVal,
376            self.duration
377          );
378        }
379      } else {
380        if (self.countDown) {
381          self.frameVal =
382            self.startVal - (self.startVal - self.endVal) * (progress / self.duration);
383        } else {
384          self.frameVal =
385            self.startVal + (self.endVal - self.startVal) * (progress / self.duration);
386        }
387      }
388
389      // don't go past endVal since progress can exceed duration in the last frame
390      if (self.countDown) {
391        self.frameVal = self.frameVal < self.endVal ? self.endVal : self.frameVal;
392      } else {
393        self.frameVal = self.frameVal > self.endVal ? self.endVal : self.frameVal;
394      }
395
396      // decimal
397      self.frameVal = Math.round(self.frameVal * self.dec) / self.dec;
398
399      // format and print value
400      self.printValue(self.frameVal);
401
402      // whether to continue
403      if (progress < self.duration) {
404        self.rAF = requestAnimationFrame(self.count);
405      } else {
406        if (self.callback) self.callback();
407      }
408    };
409    // start your animation
410    self.start = function(callback) {
411      if (!self.initialize()) return;
412      self.callback = callback;
413      self.rAF = requestAnimationFrame(self.count);
414    };
415    // toggles pause/resume animation
416    self.pauseResume = function() {
417      if (!self.paused) {
418        self.paused = true;
419        cancelAnimationFrame(self.rAF);
420      } else {
421        self.paused = false;
422        delete self.startTime;
423        self.duration = self.remaining;
424        self.startVal = self.frameVal;
425        requestAnimationFrame(self.count);
426      }
427    };
428    // reset to startVal so animation can be run again
429    self.reset = function() {
430      self.paused = false;
431      delete self.startTime;
432      self.initialized = false;
433      if (self.initialize()) {
434        cancelAnimationFrame(self.rAF);
435        self.printValue(self.startVal);
436      }
437    };
438    // pass a new endVal and start animation
439    self.update = function(newEndVal) {
440      if (!self.initialize()) return;
441      newEndVal = Number(newEndVal);
442      if (!ensureNumber(newEndVal)) {
443        return;
444      }
445      if (newEndVal === self.frameVal) return;
446      cancelAnimationFrame(self.rAF);
447      self.paused = false;
448      delete self.startTime;
449      self.startVal = self.frameVal;
450      self.endVal = newEndVal;
451      self.countDown = self.startVal > self.endVal;
452      self.rAF = requestAnimationFrame(self.count);
453    };
454
455    // format startVal on initialization
456    if (self.initialize()) self.printValue(self.startVal);
457  };
458
459  return CountUp;
460});
461var crossSellProducts = (function() {
462  var _config = {
463    moduleList: document.querySelectorAll('[data-module="CrossSellProducts"]')
464  };
465
466  var init = function() {
467    if (!_config.moduleList) return;
468
469    _config.moduleList.forEach(function(module) {
470      var itemcodes = module.dataset.productIds;
471
472      apiManager.getProducts(itemcodes, 'CrossSellProducts', addProductToGrid, module);
473
474      function addProductToGrid(data, location) {
475        if (data.readyState === 4) {
476          if (data.status === 200) {
477            var productGrid = location.querySelector("[data-child-module='ProductGrid']");
478            productGrid.innerHTML += data.response;
479            // convertToSlider(location);
480          }
481        }
482      }
483
484      // function convertToSlider(location) {
485      //   $(location).slick({
486      //     infinite: false,
487      //     speed: 200,
488      //     slidesToShow: 4,
489      //     pauseOnHover: true,
490      //     autoplay: false,
491      //     centerMode: false,
492      //     swipteToSlide: true,
493      //     dots: false,
494      //     arrows: true,
495      //     touchThreshold: 10
496      //   });
497      // }
498    });
499  };
500
501  return {
502    init: init
503  };
504})();document.addEventListener('DOMContentLoaded', function() {
505
506  var categoryDropdown = document.querySelectorAll('.js-category-dropdown');
507  for (i = 0; i < categoryDropdown.length; ++i) {
508    categoryDropdown[i].addEventListener('click', function(event) {
509      var events = $._data(document, 'events') || {};
510      events = events.click || [];
511      for(var i = 0; i < events.length; i++) {
512        if(events[i].selector) {
513          //Check if the clicked element matches the event selector
514          if($(event.target).is(events[i].selector)) {
515              events[i].handler.call(event.target, event);
516          }
517          // Check if any of the clicked element parents matches the
518          // delegated event selector (Emulating propagation)
519          $(event.target).parents(events[i].selector).each(function(){
520              events[i].handler.call(this, event);
521          });
522        }
523      }
524      event.stopPropagation(); //Always stop propagation
525    });
526  };
527
528
529  if (getUrlParameters()['Sort']) {
530    var orderval = getUrlParameters()['Sort'] + ':' + getUrlParameters()['Dir'];
531    $('.js-sorting option').removeAttr('selected');
532    $('.js-sorting option[value="' + orderval + '"]').attr('selected', 'selected');
533  }
534});
535
536$('.js-sorting').change(function(e) {
537  var selected = e.target;
538  setSortOrder(e.target);
539});
540
541$('.js-selectpicker').selectpicker({
542  width: 'fit',
543  style: 'btn-default btn-sm'
544});
545
546$('.js-apply-filters').on('click', function(e) {
547  e.preventDefault();
548  addFilters();
549});
550
551$('.js-filters-reset').on('click', function(e) {
552  e.preventDefault();
553  openUrl(getCurrentUrl());
554});
555
556
557$('.js-filteritem input[type=checkbox]').change(function() {
558  $(this)
559    .closest('.js-filteritem')
560    .toggleClass('js-filteritem-checked', this.checked);
561
562  var currentCategory = document.querySelector('[data-category]').getAttribute('data-category');
563  getTotalProducts(currentCategory);
564
565  countActiveFilterItems(this);
566});
567
568
569
570function addFilters(from) {
571  from = from ? '.mobileFilterItem' : '.item ';
572  var url = getCurrentUrl();
573  var selectedFilters = document.querySelectorAll('.js-filteritem-checked');
574  var filterObjects = [];
575  var urlParams = getUrlParameters();
576  var url = resetUrlPagination(url);
577  for (param in urlParams) {
578    if (param === 'Sort') {
579      filterObjects.push({ filtername: param, filtervalue: urlParams[param] });
580    }
581
582    if (param === 'Dir') {
583      filterObjects.push({ filtername: param, filtervalue: urlParams[param] });
584    }
585  }
586  for (var i = 0; i < selectedFilters.length; i++) {
587    var key = selectedFilters[i].getAttribute('data-kind');
588    var value = selectedFilters[i].getAttribute('data-id');
589    filterObjects.push({ filtername: key, filtervalue: value });
590  }
591
592  url = addFiltersToUrl(filterObjects, url);
593
594  // Trigger datalayer Measuring Filter data
595  var amountOfProducts = document.querySelector('.js-filter').getAttribute('data-amountofproducts');
596  datalayerFilterButtonClick(filterObjects, amountOfProducts);
597  openUrl(url);
598}
599
600function getTotalProducts(category) {
601  var selectedFilters = document.querySelectorAll('.js-filteritem-checked:not(.mobileFilterItem)');
602  var filterObjects = [];
603  filterObjects.push({ filtername: 'category', filtervalue: category });
604  for (var i = 0; i < selectedFilters.length; i++) {
605    var key = selectedFilters[i].getAttribute('data-kind');
606    var value = selectedFilters[i].getAttribute('data-id');
607    filterObjects.push({ filtername: key, filtervalue: value });
608  }
609  var sliderFilters = document.querySelectorAll('.slider-filter');
610  for (var y = 0; y < sliderFilters.length; y++) {
611    var slideRangeName = sliderFilters[y]
612      .querySelector('.cat-title')
613      .getAttribute('data-filtertitle');
614    var slideRangeValueMin = sliderFilters[y]
615      .querySelector('[data-lower-value]')
616      .getAttribute('data-lower-value');
617    var slideRangeValueMax = sliderFilters[y]
618      .querySelector('[data-upper-value]')
619      .getAttribute('data-upper-value');
620    if (
621      sliderFilters[y].querySelector('[data-minvalue]').getAttribute('data-minvalue') !==
622        slideRangeValueMin ||
623      sliderFilters[y].querySelector('[data-maxvalue]').getAttribute('data-maxvalue') !==
624        slideRangeValueMax
625    ) {
626      var tempFilter = {
627        filtername: slideRangeName,
628        filtervalue: slideRangeValueMin + ',' + slideRangeValueMax
629      };
630      if (
631        filterObjects.filter(function(e) {
632          return (
633            e.filtername === tempFilter['filtername'] && e.filtervalue === tempFilter['filtervalue']
634          );
635        }).length > 0
636      ) {
637        continue;
638      }
639      filterObjects.push({
640        filtername: slideRangeName,
641        filtervalue: slideRangeValueMin + ',' + slideRangeValueMax
642      });
643    }
644  }
645  filterObjects.push({ filtername: 'select', filtervalue: 'sortOrder' });
646  var url = addFiltersToUrl(filterObjects, '/api/v2/catalog/product');
647  apiManager.callApi(url, renderTotalProducts, null);
648}
649
650function setSortOrder(initiator) {
651  var urlParams = getUrlParameters();
652  var filterObjects = [];
653  var value = $(initiator).val();
654  var type = value.slice(0, value.indexOf(':'));
655  var sort = value.slice(value.lastIndexOf(':') + 1);
656
657  for (param in urlParams) {
658    if (param !== 'Sort' && param !== 'Dir') {
659      filterObjects.push({ filtername: param, filtervalue: urlParams[param] });
660    }
661  }
662
663  filterObjects.push(
664    { filtername: 'Sort', filtervalue: type },
665    { filtername: 'Dir', filtervalue: sort }
666  );
667
668  url = addFiltersToUrl(filterObjects, getCurrentUrl());
669  openUrl(url);
670}
671
672function addFiltersToUrl(filterObjects, url) {
673  for (var filters in filterObjects) {
674    var urlParams = getUrlParameters(url);
675
676    if (Object.keys(urlParams).indexOf(filterObjects[filters]['filtername']) === -1) {
677      var params =
678        url.indexOf('?') === -1
679          ? '?' +
680            filterObjects[filters]['filtername'] +
681            '=' +
682            encodeURIComponent(filterObjects[filters]['filtervalue'])
683          : '&' +
684            filterObjects[filters]['filtername'] +
685            '=' +
686            encodeURIComponent(filterObjects[filters]['filtervalue']);
687      url += params;
688    } else {
689      url =
690        url.slice(
691          0,
692          url.indexOf(filterObjects[filters]['filtername']) +
693            filterObjects[filters]['filtername'].length +
694            1
695        ) +
696          encodeURIComponent(filterObjects[filters]['filtervalue']) +
697        ',' +
698        url.slice(
699          url.indexOf(filterObjects[filters]['filtername']) +
700            filterObjects[filters]['filtername'].length +
701            1
702        );
703    }
704  }
705  return url;
706}
707
708function countActiveFilterItems(e) {
709  // count active filter items per filter
710  var jsFilter = $(e).closest('.js-filter');
711  var filterCounter = $(jsFilter).find('.js-count-activeitems');
712  var activeItems = $(jsFilter).find('.js-filteritem-checked').length;
713  $(filterCounter).text(activeItems);
714
715  // count all active filter items
716  var totalCount = $('.js-count-allactiveitems');
717  var allActiveItems = $('.js-filters').find('.js-filteritem-checked').length;
718  $(totalCount).text(allActiveItems);
719
720  // show/hide counters
721  if (activeItems === 0 && allActiveItems != 0) {
722    $(filterCounter).hide();
723    $(totalCount).show();
724  } else if (allActiveItems === 0) {
725    $(filterCounter).hide();
726    $(totalCount).hide();
727  } else {
728    $(filterCounter).show();
729    $(totalCount).show();
730  }
731}
732
733function renderTotalProducts(response) {
734  if (response.readyState === 4) {
735    if (response.status === 200) {
736      var data = JSON.parse(response.responseText);
737      var amountOfProducts = document.querySelectorAll('.js-amountOfProducts');
738      var jsFilter = document.querySelector('.js-filter');
739      if (jsFilter) {
740        jsFilter.setAttribute('data-amountofproducts', data.totalResults);
741      }
742      for (var i = 0; i < amountOfProducts.length; i++) {
743        var previousAmount = parseInt(amountOfProducts[i].innerText.replace(',', ''));
744        var resultAmount = data.totalResults;
745        var animationOptions = {
746          useEasing: true,
747          easingFn: function(t, b, c, d) {
748            var ts = (t /= d) * t;
749            var tc = ts * t;
750            return b + c * (tc * ts + -5 * ts * ts + 10 * tc + -10 * ts + 5 * t);
751          },
752          useGrouping: false,
753          separator: '',
754          decimal: '.'
755        };
756
757        var animateNumber = new CountUp(
758          amountOfProducts[i],
759          previousAmount,
760          data.totalResults,
761          0,
762          1,
763          animationOptions
764        );
765        animateNumber.start();
766
767        var applyButton = document.querySelectorAll('.js-apply-filters');
768        for (var x = 0; x < applyButton.length; x++) {
769          if (resultAmount > 0) {
770            $('.js-apply-filters').prop('disabled', false);
771          } else {
772            $('.js-apply-filters').prop('disabled', true);
773          }
774        }
775      }
776    }
777  }
778}
779Hyphenator.config({
780  // hyphenchar: "•",
781  classname : 'js-hyphen',
782  minwordlength : 14,
783  leftmin : 6,
784  rightmin : 6
785});
786
787Hyphenator.run();
788var InfiniteScroll = (function() {
789  var _config = {
790    listView: document.querySelector('[data-module="infinite-scroll"]'),
791    threshold: 1.0,
792    rootMargin: '0px',
793    template: 'Product',
794    loadHTML: '<div class="infinite-loader"><h1>Loading</h1></div>'
795  };
796
797  var _lazyPage;
798  var _sentinel = {
799    el: null,
800    set: function set(el) {
801      this.el = el;
802      this.el.classList.add('infinite-sentinel');
803      _sentinelObserver.observe(this.el);
804    },
805    unset: function unset() {
806      if (!this.el) return;
807      _sentinelObserver.unobserve(this.el);
808      this.el.classList.remove('infinite-sentinel');
809      this.el = null;
810    }
811  };
812
813  var init = function(options) {
814    for (var prop in options) {
815      if (options.hasOwnProperty(prop)) {
816        if (prop === 'loadHTML') {
817          _config[prop] = '<div class="infinite-loader">' + options[prop] + '</div>';
818        } else {
819          _config[prop] = options[prop];
820        }
821      }
822    }
823
824    if (_config.listView) {
825      window.addEventListener(
826        'load',
827        function() {
828          _updateSentinel();
829        },
830        false
831      );
832    }
833  };
834
835  var _updateSentinel = function() {
836    _sentinel.set(_config.listView.children[_config.listView.children.length - 1]);
837  };
838
839  var _sentinelListener = function(entries) {
840    if (entries[0].intersectionRatio > 0) {
841      _sentinel.unset();
842      if (_lazyPage > parseInt(_config.listView.getAttribute('data-totalPages'))) return;
843      _config.listView.classList.add('infinite-loading');
844      var nextPage = typeof _lazyPage !== 'undefined' ? _lazyPage : 2;
845      var category = _config.listView.getAttribute('data-category');
846      var urlParameters = getUrlParameters();
847      var template = _config.template;
848      var filters = '';
849      for (var filter in urlParameters) {
850        if (filter !== 'page') {
851          filters += '&' + encodeURI(filter) + '=' + encodeURI(urlParameters[filter]);
852        }
853      }
854      var url =
855        '/api/v2/catalog/product?category=' +
856        category +
857        '&page=' +
858        nextPage +
859        filters +
860        '&template=' +
861        template +
862        '&omitfilterdata=true&nocount=1';
863      apiManager.callTemplate(url, _lazyLoadProducts, this);
864      _config.listView.insertAdjacentHTML('beforeend', _config.loadHTML);
865    }
866  };
867
868  var _sentinelObserver = new IntersectionObserver(_sentinelListener, {
869    threshold: _config.threshold,
870    rootMargin: _config.rootMargin
871  });
872
873  var _lazyLoadProducts = function(data) {
874    if (apiManager.isValidResponse(data)) {
875      if (typeof _lazyPage !== 'undefined') {
876        _lazyPage += 1;
877      } else {
878        _lazyPage = 3;
879      }
880      data = data.response;
881      var loader = _config.listView.querySelector('.infinite-loader');
882      loader.parentNode.removeChild(loader);
883      _config.listView.insertAdjacentHTML('beforeend', data);
884      _updateSentinel();
885      _config.listView.classList.remove('infinite-loading');
886    }
887  };
888
889  return {
890    init: init
891  };
892})();
893var QueryCleanup = (function() {
894  var _config = {
895    module: document.querySelectorAll('[data-module="QueryCleanup"]')
896  };
897
898  var init = function() {
899    _config.module.forEach(function(module) {
900      module.addEventListener('click', function() {
901        window.history.replaceState(null, null, window.location.pathname);
902      });
903    });
904  };
905
906  return {
907    init: init
908  };
909})();
910document.addEventListener('DOMContentLoaded', function() {
911  // Scroll to links with hashes on load
912  $('a[href*="#"]')
913    // Remove links that don't actually link to anything
914    .not('[href="#"]')
915    .not('[href^="#modal-"]')
916    .not('[href="#0"]')
917    .not('[data-toggle]')
918    .click(function(event) {
919      // On-page links
920      if (
921        location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') &&
922        location.hostname == this.hostname
923      ) {
924        // Figure out element to scroll to
925        var target = $(this.hash.replace(/\+/g, '\\+'));
926        target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
927        // Does a scroll target exist?
928        if (target.length) {
929          // Only prevent default if animation is actually gonna happen
930          event.preventDefault();
931
932          // exception for rows
933          if (this.hash.match('^#row-')) {
934            var target = $(this.hash).closest('.png-section');
935          }
936
937          $('html, body').animate(
938            {
939              scrollTop: target.offset().top - $('header').outerHeight() - 40 + 'px'
940            },
941            500,
942            function() {
943              // Callback after animation
944              // Must change focus!
945              // var $target = $(target);
946              // $target.focus();
947              // if ($target.is(":focus")) { // Checking if the target was focused
948              //   return false;
949              // } else {
950              //   $target.attr('tabindex','-1'); // Adding tabindex for elements not focusable
951              //   $target.focus(); // Set focus again
952              // };
953            }
954          );
955        }
956      }
957    });
958
959  // Scroll to links with hashes on load
960  if (window.location.hash) {
961    var target = window.location.hash;
962
963    if (target === '#403') return;
964
965    // Needed to fix the syntax error, unrecognized expression: #/ when redirectUrl from checkout is filled
966    if (target.match('#/')) return;
967
968    var $target = $(target);
969
970    // exception for rows
971    if (target.match('^#row-')) {
972      var $target = $(target).closest('.png-section');
973    }
974
975    $('html, body').animate(
976      {
977        scrollTop: $target.offset().top - $('header').outerHeight() - 40 + 'px'
978      },
979      500,
980      function() {
981        // Callback after animation
982        // Must change focus!
983        // var $target = $(target);
984        // $target.focus();
985        // if ($target.is(":focus")) { // Checking if the target was focused
986        //   return false;
987        // } else {
988        //   $target.attr('tabindex','-1'); // Adding tabindex for elements not focusable
989        //   $target.focus(); // Set focus again
990        // };
991      }
992    );
993  }
994});
995var createEventListeners = function() {
996  document.addEventListener(
997    'DOMContentLoaded',
998    function(event) {
999      crossSellProducts.init();
1000      InfiniteScroll.init();
1001      QueryCleanup.init();
1002    },
1003    false
1004  );
1005};
1006window.addEventListener('resize', function(e) {});
1007var apiManager = (function() {
1008  var callTemplate = function(url, callback, initiator) {
1009    _callAsync('GET', url, null, callback, 'text/html', initiator);
1010  };
1011
1012  var callApi = function(url, callback, initiator) {
1013    _callAsync('GET', url, null, callback, null, initiator);
1014  };
1015
1016  var patch = function(url, data, callback, initiator) {
1017    _callAsync('PATCH', url, JSON.stringify(data), callback, null, initiator);
1018  };
1019
1020  var post = function(url, data, callback, initiator) {
1021    _callAsync('POST', url, JSON.stringify(data), callback, null, initiator);
1022  };
1023
1024  var deleteApi = function(url, callback, initiator) {
1025    _callAsync('DELETE', url, null, callback, null, initiator);
1026  };
1027
1028  var remove = function(cartId, cartitemId, callback) {
1029    var url = '/api/v1/catalog/cart/' + cartId + '/remove/' + cartitemId;
1030    _callAsync('POST', url, null, callback, null, null);
1031  };
1032
1033  var getApi = function(id, discount, callback) {
1034    var timestamp = Date.now();
1035    var url =
1036      discount !== null
1037        ? '/api/v1/catalog/cart/' + id + '/discount'
1038        : '/api/v1/catalog/cart/' + id + '?' + timestamp;
1039    var requestMethod = discount !== null ? 'POST' : 'GET';
1040    var params = discount !== null ? discount : null;
1041    _callAsync(requestMethod, url, params, callback, null, null);
1042  };
1043
1044  var autocomplete = function(searchstring, callback, initiator) {
1045    _callAsync(
1046      'GET',
1047      '/api/v2/catalog/search/autocomplete?q=' + searchstring + '&template=SearchProductsResults',
1048      null,
1049      callback,
1050      'text/html',
1051      initiator
1052    );
1053  };
1054
1055  var getProducts = function(itemCode, template, callback, initiator) {
1056    _callAsync(
1057      'GET',
1058      '/api/v2/catalog/product?itemcode=' +
1059        itemCode +
1060        '&all=true&sort=unsorted&omitfilterdata=1&template=' +
1061        template,
1062      null,
1063      callback,
1064      'text/html',
1065      initiator
1066    );
1067  };
1068
1069  var isValidResponse = function(response) {
1070    return response.readyState === 4 && response.status === 200;
1071  };
1072
1073  var isBadRequest = function(response) {
1074    return response.readyState === 4 && response.status === 400;
1075  };
1076
1077  var _callAsync = function(method, url, params, callback, accept, initiator) {
1078    var lang = LANGUAGE !== undefined ? LANGUAGE : 'nl';
1079    var request = new XMLHttpRequest();
1080    request.onreadystatechange = function() {
1081      callback(request, initiator);
1082    };
1083    request.open(method, url, true);
1084    request.setRequestHeader('Content-type', 'application/json');
1085    request.setRequestHeader('Accept-language', lang);
1086    request.setRequestHeader('Authorization', 'bearer ' + cookies.get('token'));
1087    request.setRequestHeader('Cache-control', 'no-cache');
1088    if (accept) {
1089      request.setRequestHeader('Accept', accept);
1090    }
1091    request.send(params);
1092  };
1093
1094  return {
1095    callTemplate: callTemplate,
1096    callApi: callApi,
1097    patch: patch,
1098    post: post,
1099    deleteApi: deleteApi,
1100    getApi: getApi,
1101    autocomplete: autocomplete,
1102    getProducts: getProducts,
1103    isValidResponse: isValidResponse,
1104    isBadRequest: isBadRequest
1105  };
1106})();
1107var main = function() {
1108    createEventListeners();
1109};
1110
1111main();
1112
1113function paginationSmall() {
1114    var totalPages = document.querySelector('.js-pagination-small li:nth-last-child(2) a');
1115    var smallActivePagination = document.querySelector('.js-pagination-small .active a');
1116
1117    if (totalPages && smallActivePagination) {
1118        smallActivePagination.append('/' + totalPages.innerText);
1119    }
1120}
1121
1122
1123// MAKE ROWS STICKY TO FLEXIBLE HEIGHT HEADER
1124$('.js-headroom-sticky').each(function() {
1125
1126    var header = $('.c-header');
1127    var stickyElement = $('.js-headroom-sticky');
1128
1129    // Function to check if the sticky element is aligned with the header
1130    function updateStickyPosition() {
1131        var headerHeight = header.outerHeight(true);
1132        stickyElement.css('top', headerHeight);
1133
1134        var stickyRect = stickyElement[0].getBoundingClientRect().top;
1135
1136        // Check if the top of the sticky element matches the header height
1137        if (Math.round(stickyRect) === Math.round(headerHeight)) {
1138            header.css('box-shadow', 'none');
1139            stickyElement.addClass('is-sticky');
1140        } else {
1141            header.css('box-shadow', '');
1142            stickyElement.removeClass('is-sticky');
1143        }
1144    }
1145
1146    // Call the function to update sticky state immediately on page load
1147    updateStickyPosition();
1148
1149    $(window).scroll(function() {
1150        // Recalculate sticky state during scroll
1151        updateStickyPosition();
1152
1153        // In case transitions are slower, recalculate after 150ms
1154        setTimeout(updateStickyPosition, 150);
1155    });
1156});
1157
1158
1159// HEADROOM.JS
1160(function() {
1161    var header = new Headroom(document.querySelector('.c-header'), {
1162        tolerance: 70,
1163        offset: 35, // testing: same as header-top-row?
1164    });
1165    header.init();
1166})();
1167
1168
1169// document.load
1170document.addEventListener('DOMContentLoaded', function() {
1171
1172
1173    // create small pagination
1174    paginationSmall();
1175
1176
1177    // PARSLEY.JS
1178    $('.js-parsley-form').parsley({
1179        // append the error message to the form group
1180        errorsContainer: function(field) {
1181            return $(field.element).closest('.form-group');
1182        },
1183    });
1184
1185    // move form-help after parsley-errors
1186    window.Parsley.on('field:error', function() {
1187        $(".parsley-errors-list").prev('.form-help').appendTo(this.$element.closest('.form-group'));
1188    });
1189
1190
1191    if (window.innerWidth < 992) {
1192        $('.js-modalsearch')
1193            .keyup(function() {
1194                $('#modal-search').modal(
1195                    {
1196                        backdrop: false,
1197                    },
1198                    'show'
1199                );
1200            })
1201            .focus(function() {
1202                if ($(this).val()) {
1203                    $('#modal-search').modal(
1204                        {
1205                            backdrop: false,
1206                        },
1207                        'show'
1208                    );
1209                }
1210            });
1211    }
1212
1213
1214    // BENEFITS-PANEL: keep this script in case a customer wants the panel to open/close by default
1215    // open panel after timeout after document load
1216    // if (document.getElementById("js-benefitspanel") && (window.innerWidth >= 768) ) {
1217    //   setTimeout(function() {
1218    //     $('#js-benefitspanel').collapse('show');
1219    //     // panel close after timeout
1220    //     setTimeout(function() {
1221    //       $('#js-benefitspanel').collapse('hide');
1222    //     }, 2500);
1223    //   }, 200);
1224    // };
1225
1226
1227    // create href for 'terug-knop' from second to last breadcrumb-path
1228    var breadcrumbBackButton = document.querySelector('.js-backlink-button');
1229    var breadcrumbBackOrigin = document.querySelector('.js-backlink-item:nth-last-child(2) .js-backlink-origin');
1230
1231    if (breadcrumbBackButton !== null && breadcrumbBackOrigin !== null) {
1232        breadcrumbBackButton.setAttribute('href', breadcrumbBackOrigin.getAttribute('href'));
1233    }
1234
1235
1236    //remove ActiveCampaign styling and reset to our styling
1237    if ($('form[action*="activehosted"]').length) {
1238        $('form[action*="activehosted"]').siblings('style').remove();
1239        $('._form_element').addClass('form-group');
1240        $('._form_element').find('label').text($(this).find('label').text().replace('*', ''));
1241        $('._form_element').find('input').addClass('form-control');
1242        $('._button-wrapper').find('button').addClass('btn btn-primary btn-block');
1243        $('._form-thank-you').addClass('alert alert--info');
1244    }
1245
1246
1247    //remove Mailchimp styling and reset to our styling
1248    if ($('#mc_embed_signup').length) {
1249        $('.mc-field-group').addClass('form-group');
1250        $('.mc-field-group').find('label').text($(this).find('.mc-field-group').find('label').text().replace('*', ''));
1251        $('.mc-field-group').find('input').addClass('form-control');
1252        $('.foot').find('input').addClass('btn btn-primary btn-block');
1253    }
1254
1255
1256    //remove heading margins if heading follows heading
1257    $('.text-container h4, .text-container h5, .text-container h6').prev('h1,h2,h3').css('margin-bottom', '0');
1258
1259    var ignoreHeadings = ['/winkelwagen', '/shopping-cart', '/my-account', '/mijn-account'];
1260    //wrong headings detection
1261    if (!ignoreHeadings.some(function (x) { return window.location.pathname.includes(x); })) {
1262        if ($("body").hasClass("js-heading-errors-on")) {
1263            // multiple h1 detection
1264            var lengthH1 = $('h1:not([class*="hidden"])');
1265            // break used detection
1266            var doubleH1 = $('.text-container h1').next('h1');
1267            var doubleH2 = $('.text-container h2').next('h2');
1268            var doubleH3 = $('.text-container h3').next('h3');
1269
1270            if (lengthH1.length == 0 || lengthH1.length > 1 || doubleH1.length > 0 || doubleH2.length > 0 || doubleH3.length > 0) {
1271                // error on body
1272                $('body').append('<div class="js-heading-errors-detected"><p>Heading errors detected:</p><ul></ul></div>');
1273
1274                // error on each h1
1275                if (lengthH1.length == 0) {
1276                    $('.js-heading-errors-detected ul').append('<li>No H1 detected. <span>&nbsp; &nbsp; &nbsp; &#10551; Use at least one H1 on the page</span></li>');
1277                }
1278                if (lengthH1.length > 1) {
1279                    $('.js-heading-errors-detected ul').append('<li>Multiple H1\'s (' + lengthH1.length + 'x). <span>&nbsp; &nbsp; &nbsp; &#10551; Use only one H1 on a page.</span></li>');
1280                    $('h1').each(function(index) {
1281                        $(this).append("<div class='js-error-multiple-h1-on-page'>Multiple H1 (" + (index + 1) + ' of ' + lengthH1.length + ').</div>');
1282                    });
1283                }
1284                if (doubleH1.length > 0 || doubleH2.length > 0 || doubleH3.length > 0) {
1285                    $('.js-heading-errors-detected ul').append('<li>Heading followed by the same heading (' + (doubleH1.length + doubleH2.length + doubleH3.length) + 'x). <span>&nbsp; &nbsp; &nbsp; &#10551; Instead of <code>enter</code>, use <code>\\</code> to soft-break heading. Or replace by different <code>h2/h3/p</code>.</span></li>');
1286                    $(doubleH1).append('<div class="js-error-double-heading">H1 + H1 detected');
1287                    $(doubleH2).append('<div class="js-error-double-heading">H2 + H2 detected');
1288                    $(doubleH3).append('<div class="js-error-double-heading">H3 + H3 detected');
1289                }
1290            }
1291        }
1292    }
1293
1294
1295    // nested dropdown functionality
1296    $('[data-toggle=dropdown]').on('click', function(e) {
1297
1298        // prevent follow link if NOT opened by hover
1299        if (!$(this).parent().hasClass('is-opened-on-hover')) {
1300            e.preventDefault(); // do not follow link
1301        }
1302
1303        // prevent bootstrap functionality, enables dropdown inside dropdown
1304        e.stopPropagation();
1305
1306        // closes all open dropdowns that are not a parent
1307        $('.c-dropdown').not($(this).parents('.open')).removeClass('open');
1308
1309        // open dropdown of clicked item
1310        $(this).parent().toggleClass('open active').parents('.active').removeClass('active');
1311
1312        // modal no scroll
1313        if (window.innerWidth < 960) {
1314            $(this).closest('.c-modal__body').css("overflow", "hidden");
1315        };
1316
1317    });
1318
1319
1320    // PREVENT DROPDOWN FROM CLOSING WHEN CLICKED INSIDE (if not <a>, stop dropdowntoggle from closing)
1321    $('.c-dropdown__menu').on('click', function(e) {
1322        if (!$(e.target).is('a')) {
1323            e.stopPropagation();
1324        }
1325    });
1326
1327
1328    // close all open / active dropdowns
1329    $('#modal-menus').on('hide.bs.modal', function(e) {
1330        $(this).find('.c-dropdown').removeClass('open active');
1331    });
1332
1333
1334    // close submenu by button
1335    $('.js-dropdown-close').on('click', function(e) {
1336        $(this).closest('.c-dropdown').removeClass('open active').closest('.open').addClass('active');
1337
1338    });
1339
1340
1341    // modal activate scroll
1342    $('.js-reactivate-modal').on('click', function(e) {
1343        $(this).closest('.c-modal__body').css("overflow", "");
1344    });
1345
1346
1347    // CLOSE MEGAMENU ON MOBILE
1348    $('.js-close-megamenu').click(function(e) {
1349        $(this).closest('.c-dropdown').find('[data-toggle="dropdown"]').dropdown('toggle');
1350    });
1351
1352
1353    // OPEN DROPDOWN ON HOVER (main menu)
1354    // because touch devices execute touchstart AND mouseenter on tap, it must be added to be stopped
1355    $('.js-open-dropdown-on-hover').on('touchstart mouseenter mouseleave', function(e) {
1356
1357        // for desktop-layout
1358        if (window.innerWidth >= 960) {
1359
1360            // on touch device
1361            if (e.type == 'touchstart') {
1362                $(this).off('mouseenter mouseleave');
1363            }
1364
1365            // on mouse device
1366            if (e.type == 'mouseenter') {
1367                $(this).addClass('open is-opened-on-hover');
1368            }
1369            else if (e.type == 'mouseleave') {
1370                $(this).removeClass('open is-opened-on-hover');
1371            }
1372
1373        };
1374    });
1375
1376
1377    // CATEGORY PANELS
1378    // catch clicks and mouseenter evens (for desktop)
1379    $('.js-category-link').on('click mouseenter', function(e) {
1380
1381        // for all clicks and mouseenters on desktop
1382        if (e.type == 'click' || (e.type == 'mouseenter' && window.innerWidth > 960)) {
1383
1384            // if link has href (always) AND target (sometimes), prevent follow link if NOT opened by hover (only follow link if opened by hover)
1385            if (!$(this).hasClass('is-opened-on-hover') && $(this).attr('data-target') !== undefined && $(this).data('target').startsWith("#cat-")) {
1386                e.preventDefault();
1387            }
1388
1389            // close all levels of next panels
1390            $(this).closest('.js-category-panel').nextAll().find('.js-category-level').removeClass('open').children().hide();
1391
1392            // only for subcategories
1393            if ($(this).attr('data-target') !== undefined && $(this).data('target').startsWith("#cat-")) {
1394
1395                // remove active from this panel, open and active next panel, close and deactive all next panels
1396                $(this).closest('.js-category-panel').removeClass('active').next().addClass('open active').nextAll().removeClass('open active');
1397
1398                // open referenced level
1399                $($(this).data('target')).addClass('open').children().show();
1400            };
1401
1402            // for desktop-layout show clicked state
1403            if (window.innerWidth >= 960) {
1404                // remove active (clicked) state of all links in this panel
1405                $(this).closest('.js-category-panel').find('.js-category-link').removeClass('active');
1406                // remove active (clicked) state of all links in deeper panels
1407                $(this).closest('.js-category-panel').nextAll().find('.js-category-link').removeClass('active');
1408                // // set link to active
1409                $(this).addClass('active');
1410            };
1411
1412        }
1413
1414    });
1415
1416
1417    // for mobile, back-function has to close/deactivate various things
1418    $('.js-category-level-back').click(function(e) {
1419        // close & deactivate panel, activate provious panel
1420        $(this).closest('.js-category-panel').removeClass('open active').prev().addClass('active');
1421        // remove active state from links in this panel
1422        $(this).closest('.js-category-panel').find('.js-category-link').removeClass('active');
1423    });
1424
1425
1426    // reset open panels/levels/links on start
1427    $('.js-reset-panels').on('touchstart mouseenter', function(e) {
1428        // close all panels
1429        $('.js-category-panel').removeClass('open active');
1430        // open first panel
1431        $('.js-category-panel:first-child').addClass('open active');
1432        // close all levels
1433        $('.js-category-level').removeClass('open').children().hide();
1434        // close all levels
1435        $('.js-category-link').removeClass('active');
1436    });
1437
1438    // END CATEGORY PANELS
1439
1440
1441    // remove imagedetails text when item is opened
1442    $('[data-child-module="imagedetails__link"').on('click', function(e) {
1443        $(this).closest('[data-module="imagedetails"]').find('[data-child-module="imagedetails__text"]').remove();
1444    });
1445
1446
1447    // set radiobutton to false when category is closed
1448    $('.js-category-check').on('click', function(event) {
1449        var input = $(this)
1450
1451        setTimeout(function() {
1452            if (input.hasClass("collapsed")) {
1453                input.prop("checked", false);
1454            }
1455        }, 50);
1456    });
1457
1458
1459    // open active categories on load (only category page and only > 992px)
1460    if ($('.row-catalogcategory .c-categorylist__item.is-active').length && window.innerWidth >= 960) {
1461        $('.row-catalogcategory .c-categorylist__item.is-active > .form-check').children('.js-category-check').trigger('click');
1462    };
1463
1464
1465    // open modal when starting with modal prefix (resengo/bookingmask/etc)
1466    $("[href^='#modal-']").on("click", function(e) {
1467        e.preventDefault();
1468        $($(this).attr('href')).modal('show');
1469    });
1470
1471
1472    // when submit is clicked, deactivate submit button
1473    $('button[data-module="recaptcha"]').click(function() {
1474        $(this).attr('disabled', 'disabled');
1475    });
1476    // when input is changed, activate submit button
1477    $('form').find('input, select, textarea').on('keyup change', function() {
1478        $(this).closest('form').find('button[data-module="recaptcha"]').removeAttr('disabled');
1479    });
1480
1481
1482    // if image is used as background, remove smaller source files, so high res is used
1483    $(".image-cover").find(".image-container").addClass('js-sources-removed').children("source").remove();
1484
1485
1486
1487    $(".js-select-productchild").click(function() {
1488        $(".js-select-productchild").removeClass('is-selected');
1489        $(this).addClass('is-selected').closest('.c-dropdown').removeClass('open active');
1490    });
1491
1492
1493    // animation demo page
1494    $(".js-animation-demo .btn-primary").click(function(e) {
1495        e.preventDefault();
1496        var classes = $(this).closest('.o-macro__item').attr("class");
1497        $(this).closest('.o-macro__item').attr('class', 'o-macro__item');
1498        setTimeout(() => {
1499            $(this).closest('.o-macro__item').attr('class', classes);
1500        }, "10");
1501
1502    });
1503
1504    // Create table structure
1505    const tableSpecs = document.querySelectorAll('.c-table-specs .text-container p');
1506    tableSpecs.forEach((p) => {
1507        let parentContainer = document.createElement('div');
1508        parentContainer.classList.add('c-table');
1509
1510        let nodes = Array.from(p.childNodes);
1511        let currentRow = null;
1512        let firstTextHandled = false;
1513
1514        nodes.forEach((node) => {
1515            if (node.nodeType === 1 && node.tagName === 'STRONG') {
1516            // Nieuwe rij starten bij een <strong>
1517            currentRow = document.createElement('div');
1518            currentRow.classList.add('c-table-row');
1519
1520            let strongElement = document.createElement('div');
1521            strongElement.classList.add('c-table-cell', 'c-table-header');
1522            strongElement.appendChild(node.cloneNode(true));
1523
1524            currentRow.appendChild(strongElement);
1525            parentContainer.appendChild(currentRow);
1526            } else if (currentRow && node.nodeType === 3) {
1527            // Verwijder ALLE bullet-symbolen en voeg tekst toe in de tweede kolom
1528            let textContent = node.textContent.replace(/[\u2B24\u25CF\u2022]/g, '').trim();
1529            if (textContent) {
1530                let textCell = document.createElement('div');
1531                textCell.classList.add('c-table-cell');
1532                textCell.textContent = textContent;
1533                currentRow.appendChild(textCell);
1534            }
1535            } else if (!firstTextHandled && node.nodeType === 3) {
1536            // Zorg dat de eerste tekst buiten strong behouden blijft en verwijder bullets
1537            let textContent = node.textContent.replace(/[\u2B24\u25CF\u2022]/g, '').trim();
1538            if (textContent) {
1539                let fullWidthRow = document.createElement('div');
1540                fullWidthRow.classList.add('c-table-row', 'c-table-full-width');
1541
1542                let fullWidthCell = document.createElement('div');
1543                fullWidthCell.classList.add('c-table-cell');
1544                fullWidthCell.textContent = textContent;
1545
1546                fullWidthRow.appendChild(fullWidthCell);
1547                parentContainer.appendChild(fullWidthRow);
1548                firstTextHandled = true;
1549            }
1550            }
1551        });
1552
1553        // Vervang de originele <p> met de nieuwe tabel
1554        p.replaceWith(parentContainer);
1555    });
1556
1557
1558    // Create table structure with headers
1559    const tables = document.querySelectorAll('.c-table-specs-headers table');
1560    tables.forEach((table) => {
1561        const headers = table.querySelectorAll('th');
1562
1563        // Voeg klik-events toe aan de koppen van elke tabel
1564        headers.forEach((header, index) => {
1565            header.addEventListener('click', () => {
1566            sortTable(table, index);
1567            });
1568        });
1569    });
1570
1571     // Functie om de tabel te sorteren
1572    function sortTable(table, index) {
1573        const rows = Array.from(table.querySelectorAll('tr:nth-child(n+2)'));
1574        const sortedRows = rows.sort((rowA, rowB) => {
1575            const cellA = rowA.cells[index].innerText;
1576            const cellB = rowB.cells[index].innerText;
1577            return cellA.localeCompare(cellB);
1578        });
1579
1580        // Voeg de gesorteerde rijen opnieuw toe aan de tabel
1581        sortedRows.forEach((row) => {
1582            table.appendChild(row);
1583        });
1584    }
1585
1586    // Language selector with landcode
1587    var input = document.querySelector('#CharterPhoneNumber');
1588    var iti = window.intlTelInput(input, {
1589      initialCountry: 'nl', // Standaard Nederland
1590      separateDialCode: true, // Zet de landcode los van het nummer
1591      preferredCountries: ['nl', 'be', 'de'], // Voorkeurslanden
1592      utilsScript: 'https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js',
1593    });
1594
1595
1596});

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.