PageSourceSearch

https://med-info24shop.top/design_16/js/main.9507b401.js?v=1776174268

js med-info24shop.top collected 2026-10-09 21:42:35 UTC 63,916 bytes, 2,025 lines download raw bytes

vendor: 111 bytes, lines 1-5
1/******/ (() => { // webpackBootstrap
2/******/ 	"use strict";
3/******/ 	var __webpack_modules__ = ({
4
5/***/ "./
5js/components/Accordion.js":
6/*!****************************************!*\
7  !*** ./js/components/Accordion.js ***!
8  \****************************************/
9/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
10
11__webpack_require__.r(__webpack_exports__);
12/* harmony export */ __webpack_require__.d(__webpack_exports__, {
13/* harmony export */   "default": () => (/* binding */ initAccordion)
14/* harmony export */ });
15/* harmony import */ var _BaseComponent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BaseComponent */ "./js/components/BaseComponent.js");
16
17
18const itemSelector = '[data-accordion-item]';
19
20class Accordion extends _BaseComponent__WEBPACK_IMPORTED_MODULE_0__["default"] {
21  selectors = {
22    parent: '[data-accordion]',
23    button: '[data-accordion-button]',
24    panel: '[data-accordion-panel]',
25  };
26
27  stateClasses = {
28    isOpen: 'is-open',
29    isAnimating: 'is-animating',
30  };
31
32  stateAttributes = {
33    dataCollapsible: 'data-collapsible',
34  };
35
36  cssVariables = {
37    height: '--accordion-height',
38  };
39
40  constructor(rootElement) {
41    super();
42    this.rootElement = rootElement;
43    this.parent = this.rootElement.closest(this.selectors.parent);
44    this.button = this.rootElement.querySelector(this.selectors.button);
45    this.panel = this.rootElement.querySelector(this.selectors.panel);
46    this.isCollapsible = this.parent?.hasAttribute(this.stateAttributes.dataCollapsible);
47    this.isAnimating = false;
48    this.state = this.getProxyState({
49      isOpen: this.rootElement.classList.contains(this.stateClasses.isOpen),
50    });
51    rootElement._instance = this;
52
53    this.bindEvents();
54  }
55
56  updateUI() {
57    const { isOpen } = this.state;
58
59    this.rootElement.classList.toggle(this.stateClasses.isOpen, isOpen);
60
61    if (this.isCollapsible && isOpen) {
62      this.closeOtherInstances();
63    }
64  }
65
66  toggle() {
67    this.state.isOpen = !this.state.isOpen;
68  }
69
70  close() {
71    this.state.isOpen = false;
72  }
73
74  closeOtherInstances() {
75    const siblings = this.parent.querySelectorAll(`:scope > ${itemSelector}.${this.stateClasses.isOpen}`);
76    siblings.forEach((sibling) => sibling !== this.rootElement && sibling._instance.handleAnimation());
77  }
78
79  onButtonClick = (e) => {
80    this.state.isOpen && e.preventDefault();
81
82    const isSafari = document.documentElement.classList.contains('ua-safari');
83    isSafari ? this.setSafariHeight() : this.setHeight();
84
85    if (!this.isAnimating) {
86      this.isAnimating = true;
87    } else {
88      e.preventDefault();
89      this.rootElement.classList.remove(this.stateClasses.isAnimating);
90      this.rootElement.open = false;
91      this.isAnimating = false;
92      this.close();
93      return;
94    }
95
96    this.handleAnimation();
97  };
98
99  handleAnimation() {
100    this.rootElement.classList.add(this.stateClasses.isAnimating);
101    this.toggle();
102    this.rootElement.addEventListener('animationend', this.animationEndHandler, { once: true });
103  }
104
105  animationEndHandler = () => {
106    this.rootElement.classList.remove(this.stateClasses.isAnimating);
107    this.isAnimating = false;
108    this.rootElement.open = this.state.isOpen;
109  };
110
111  setHeight() {
112    this.panel.style.setProperty(this.cssVariables.height, `${this.panel.scrollHeight}px`);
113  }
114
115  setSafariHeight() {
116    if (!this.rootElement.open) {
117      this.rootElement.open = true;
118      this.setHeight();
119      this.rootElement.open = false;
120    } else {
121      this.setHeight();
122    }
123  }
124
125  bindEvents() {
126    this.button.addEventListener('click', this.onButtonClick);
127  }
128}
129
130class initAccordion {
131  constructor() {
132    this.init();
133  }
134
135  init() {
136    const items = document.querySelectorAll(itemSelector);
137    items.forEach((item) => new Accordion(item));
138  }
139}
140
141
142/***/ }),
143
144/***/ "./js/components/BaseComponent.js":
145/*!********************************************!*\
146  !*** ./js/components/BaseComponent.js ***!
147  \********************************************/
148/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
149
150__webpack_require__.r(__webpack_exports__);
151/* harmony export */ __webpack_require__.d(__webpack_exports__, {
152/* harmony export */   "default": () => (/* binding */ BaseComponent)
153/* harmony export */ });
154class BaseComponent {
155  constructor() {
156    if (this.constructor === BaseComponent) {
157      throw new Error('Cannot create an instance of an abstract class.');
158    }
159  }
160
161  getProxyState(initialState) {
162    return new Proxy(initialState, {
163      get: (target, prop) => {
164        return target[prop];
165      },
166      set: (target, prop, newValue) => {
167        const oldValue = target[prop];
168
169        target[prop] = newValue;
170
171        if (newValue !== oldValue) {
172          this.updateUI();
173        }
174
175        return true;
176      },
177    });
178  }
179
180  updateUI() {
181    throw new Error('updateUI() method must be implemented in the child class.');
182  }
183}
184
185
186/***/ }),
187
188/***/ "./js/components/Dialog.js":
189/*!*************************************!*\
190  !*** ./js/components/Dialog.js ***!
191  \*************************************/
192/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
193
194__webpack_require__.r(__webpack_exports__);
195/* harmony export */ __webpack_require__.d(__webpack_exports__, {
196/* harmony export */   "default": () => (/* binding */ initDialog)
197/* harmony export */ });
198/* harmony import */ var _BaseComponent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BaseComponent */ "./js/components/BaseComponent.js");
199/* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/utils */ "./js/utils/utils.js");
200
201
202
203const dialogSelector = '[data-dialog]';
204
205class Dialog extends _BaseComponent__WEBPACK_IMPORTED_MODULE_0__["default"] {
206  stateClasses = {
207    isVisible: 'is-visible',
208    isClosing: 'close-dialog-animation',
209  };
210
211  stateAttributes = {
212    dataModal: 'data-modal',
213    dataDialogStack: 'data-dialog-stack',
214  };
215
216  selectors = {
217    nativeSubmitForm: 'form.form--native-submit[method="dialog"]',
218  };
219
220  static openModals = [];
221  static stackable = false;
222  static overlay = null;
223  static immediateClose = false;
224
225  constructor(rootElement) {
226    super();
227    this.rootElement = rootElement;
228    this.dialogName = this.rootElement.dataset.dialog;
229    this.isModal = this.rootElement.hasAttribute(this.stateAttributes.dataModal);
230    this.openButtons = document.querySelectorAll(`[data-dialog-open="${this.dialogName}"]`);
231    this.closeButtons = document.querySelectorAll(`[data-dialog-close="${this.dialogName}"]`);
232    this.nativeSubmitForms = this.rootElement.querySelectorAll(this.selectors.nativeSubmitForm);
233    this.state = this.getProxyState({ isOpen: false });
234    rootElement._instance = this;
235
236    this.dialog = this.rootElement.querySelector('.dialog');
237    this.backdropFilterResizeObserver = null;
238
239    this.isModal && !Dialog.stackable && this.createOverlay();
240    this.bindEvents();
241  }
242
243  updateUI() {
244    const { isOpen } = this.state;
245    const { isVisible } = this.stateClasses;
246
247    (0,_utils_utils__WEBPACK_IMPORTED_MODULE_1__.lockScrolling)(isOpen, 'dialog');
248
249    if (isOpen) {
250      if (!this.isModal) return this.rootElement.show();
251
252      this.rootElement.showModal();
253      !Dialog.openModals.includes(this) && Dialog.openModals.push(this);
254
255      if (Dialog.stackable) {
256        this.rootElement.setAttribute(this.stateAttributes.dataDialogStack, Dialog.openModals.length);
257      } else {
258        const backdropFilter = Dialog.overlay.querySelector('.overlay__filter');
259        backdropFilter.style.setProperty('width', this.dialog.clientWidth + 'px');
260        backdropFilter.style.setProperty('height', this.dialog.clientHeight + 'px');
261        Dialog.overlay.classList.add(isVisible);
262        Dialog.openModals.length === 2 && Dialog.openModals[0].close();
263
264        // Resize observer on dialog to update filter size
265        this.backdropFilterResizeObserver = new ResizeObserver((entries) => {
266          backdropFilter.style.setProperty('width', entries[0].target.clientWidth + 'px');
267          backdropFilter.style.setProperty('height', entries[0].target.clientHeight + 'px');
268        });
269        this.backdropFilterResizeObserver.observe(this.dialog);
270      }
271
272      // Remove initial focus from the first interactive element inside the dialog
273      this.rootElement.focus();
274    } else {
275      if (!this.isModal) return this.rootElement.close();
276
277      !Dialog.immediateClose && this.rootElement.close();
278      Dialog.stackable && this.rootElement.removeAttribute(this.stateAttributes.dataDialogStack);
279      Dialog.openModals.splice(Dialog.openModals.indexOf(this), 1);
280      this.backdropFilterResizeObserver.disconnect();
281    }
282  }
283
284  open() {
285    this.state.isOpen = true;
286  }
287
288  close() {
289    this.startClosingAnimation();
290  }
291
292  startClosingAnimation() {
293    this.rootElement.classList.add(this.stateClasses.isClosing);
294    Dialog.hideOverlay();
295    this.rootElement.addEventListener('animationend', this.animationEndHandler, { once: true });
296  }
297
298  animationEndHandler = () => {
299    this.completeClosingAnimation();
300  };
301
302  completeClosingAnimation() {
303    this.state.isOpen = false;
304    this.rootElement.classList.remove(this.stateClasses.isClosing);
305  }
306
307  handleImmediateClose() {
308    if (!this.isModal) return;
309    Dialog.immediateClose = true;
310    if (Dialog.stackable) {
311      Dialog.openModals[Dialog.openModals.length - 1].close();
312    } else {
313      this.rootElement.close();
314      Dialog.hideOverlay();
315    }
316    this.state.isOpen = false;
317    this.rootElement.classList.remove(this.stateClasses.isClosing);
318    this.rootElement.removeEventListener('animationend', this.animationEndHandler);
319    Dialog.immediateClose = false;
320  }
321
322  createOverlay() {
323    if (!Dialog.overlay) {
324      Dialog.overlay = (0,_utils_utils__WEBPACK_IMPORTED_MODULE_1__.createOverlay)('dialog-overlay', document.body, true);
325    }
326  }
327
328  onOpenButtonClick = () => {
329    this.open();
330  };
331
332  onCloseButtonClick = () => {
333    this.close();
334  };
335
336  static closeAll() {
337    Dialog.openModals.forEach((dialog) => dialog.close());
338  }
339
340  static hideOverlay() {
341    if (!Dialog.stackable && Dialog.openModals.length === 1) {
342      Dialog.overlay.classList.remove('is-visible');
343    }
344  }
345
346  static handleEscapeKey(e) {
347    if (e.key === 'Escape' && Dialog.openModals.length > 0) {
348      if (Dialog.stackable) {
349        return Dialog.openModals[Dialog.openModals.length - 1].handleImmediateClose();
350      }
351      // Force close all dialogs despite current animation state
352      while (Dialog.openModals.length > 0) {
353        Dialog.openModals[Dialog.openModals.length - 1].handleImmediateClose();
354      }
355    }
356  }
357
358  bindEvents() {
359    this.openButtons.forEach((openButton) => {
360      openButton.addEventListener('click', this.onOpenButtonClick);
361    });
362    this.closeButtons.forEach((closeButton) => {
363      closeButton.addEventListener('click', this.onCloseButtonClick);
364    });
365    this.nativeSubmitForms[0] &&
366      this.nativeSubmitForms.forEach((form) => {
367        form.addEventListener('submit', (e) => {
368          e.preventDefault();
369          this.close();
370        });
371      });
372
373    // Overlay lays beneath transparent .dialog-container::backdrop
374    this.rootElement.addEventListener('click', (e) => {
375      e.target === this.rootElement && this.close();
376    });
377  }
378}
379
380class initDialog {
381  constructor() {
382    this.init();
383  }
384
385  init() {
386    const dialogs = document.querySelectorAll(dialogSelector);
387    dialogs.forEach((dialog) => new Dialog(dialog));
388
389    document.addEventListener('keydown', Dialog.handleEscapeKey);
390  }
391}
392
393
394/***/ }),
395
396/***/ "./js/components/Drawer.js":
397/*!*************************************!*\
398  !*** ./js/components/Drawer.js ***!
399  \*************************************/
400/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
401
402__webpack_require__.r(__webpack_exports__);
403/* harmony export */ __webpack_require__.d(__webpack_exports__, {
404/* harmony export */   "default": () => (/* binding */ initDrawer)
405/* harmony export */ });
406/* harmony import */ var _BaseComponent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BaseComponent */ "./js/components/BaseComponent.js");
407/* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/utils */ "./js/utils/utils.js");
408
409
410
411const drawerSelector = '[data-drawer]';
412
413class Drawer extends _BaseComponent__WEBPACK_IMPORTED_MODULE_0__["default"] {
414  stateClasses = {
415    isActive: 'is-active',
416    isVisible: 'is-visible',
417  };
418
419  stateAttributes = {
420    ariaExpanded: 'aria-expanded',
421  };
422
423  static openDrawers = [];
424  static resizeListener = false;
425  static overlay = null;
426  static isAnimating = false;
427  static animationDelay = 300;
428
429  constructor(rootElement) {
430    super();
431    this.rootElement = rootElement;
432    this.drawerName = this.rootElement.dataset.drawer;
433    this.toggleButtons = document.querySelectorAll(`[data-drawer-toggle="${this.drawerName}"]`);
434    this.closeButtons = document.querySelectorAll(`[data-drawer-close="${this.drawerName}"]`);
435    this.state = this.getProxyState({ isOpen: false });
436
437    this.createOverlay();
438    this.bindEvents();
439  }
440
441  updateUI() {
442    const { isOpen } = this.state;
443    const { isActive, isVisible } = this.stateClasses;
444    const { ariaExpanded } = this.stateAttributes;
445
446    this.toggleButtons.forEach((toggleButton) => {
447      toggleButton.setAttribute(ariaExpanded, isOpen);
448    });
449
450    if (isOpen) {
451      this.rootElement.classList.add(isActive);
452      !Drawer.openDrawers.includes(this) && Drawer.openDrawers.push(this);
453    } else {
454      this.rootElement.classList.remove(isActive);
455      Drawer.openDrawers = Drawer.openDrawers.filter((drawer) => drawer !== this);
456    }
457
458    (0,_utils_utils__WEBPACK_IMPORTED_MODULE_1__.lockScrolling)(Drawer.openDrawers.length === 1, 'drawer', Drawer.animationDelay);
459
460    if (Drawer.openDrawers.length === 0) {
461      Drawer.overlay.classList.remove(isVisible);
462      this.removeResizeListener();
463    } else {
464      Drawer.overlay.classList.add(isVisible);
465      this.addResizeListener();
466    }
467  }
468
469  toggle() {
470    this.state.isOpen = !this.state.isOpen;
471  }
472
473  close() {
474    this.state.isOpen = false;
475  }
476
477  createOverlay() {
478    if (!Drawer.overlay) {
479      Drawer.overlay = (0,_utils_utils__WEBPACK_IMPORTED_MODULE_1__.createOverlay)('drawer-overlay');
480    }
481  }
482
483  addResizeListener() {
484    if (!Drawer.resizeListener) {
485      window.addEventListener('resize', Drawer.closeAll);
486      Drawer.resizeListener = true;
487    }
488  }
489
490  removeResizeListener() {
491    if (Drawer.resizeListener) {
492      window.removeEventListener('resize', Drawer.closeAll);
493      Drawer.resizeListener = false;
494    }
495  }
496
497  onToggleButtonClick = () => {
498    if (Drawer.isAnimating) return;
499
500    if (!this.state.isOpen) {
501      this.toggle();
502    } else {
503      Drawer.isAnimating = true;
504      this.toggle();
505      setTimeout(() => {
506        Drawer.isAnimating = false;
507      }, Drawer.animationDelay);
508    }
509  };
510
511  onCloseButtonClick = () => {
512    this.close();
513  };
514
515  static closeAll() {
516    Drawer.openDrawers.forEach((drawer) => drawer.close());
517  }
518
519  bindEvents() {
520    this.toggleButtons.forEach((toggleButton) => {
521      toggleButton.addEventListener('click', this.onToggleButtonClick);
522    });
523    this.closeButtons.forEach((closeButton) => {
524      closeButton.addEventListener('click', this.onCloseButtonClick);
525    });
526    Drawer.overlay.addEventListener('click', Drawer.closeAll);
527  }
528}
529
530class initDrawer {
531  constructor() {
532    this.init();
533  }
534
535  init() {
536    const drawers = document.querySelectorAll(drawerSelector);
537    drawers.forEach((drawer) => new Drawer(drawer));
538
539    // Close all drawers when clicking on an anchor link
540    document.addEventListener('click', (e) => {
541      if (e.target.matches(`${drawerSelector} a[href*="#"]:not([href="#!"]`)) {
542        Drawer.closeAll();
543      }
544    });
545  }
546}
547
548
549/***/ }),
550
551/***/ "./js/components/Dropdown.js":
552/*!***************************************!*\
553  !*** ./js/components/Dropdown.js ***!
554  \***************************************/
555/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
556
557__webpack_require__.r(__webpack_exports__);
558/* harmony export */ __webpack_require__.d(__webpack_exports__, {
559/* harmony export */   "default": () => (/* binding */ initDropdown)
560/* harmony export */ });
561/* harmony import */ var _BaseComponent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BaseComponent */ "./js/components/BaseComponent.js");
562/* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/utils */ "./js/utils/utils.js");
563
564
565const { computePosition, offset, flip, shift } = window.FloatingUIDOM;
566
567const dropdownSelector = '[data-dropdown]';
568
569class Dropdown extends _BaseComponent__WEBPACK_IMPORTED_MODULE_0__["default"] {
570  selectors = {
571    button: '[data-dropdown-button]',
572    container: '[data-dropdown-container]',
573  };
574
575  stateClasses = {
576    isVisible: 'is-visible',
577  };
578
579  stateAttributes = {
580    ariaExpanded: 'aria-expanded',
581    dropdownHover: 'data-dropdown-hover',
582  };
583
584  featureAttributes = {
585    fixedDropdown: 'data-fixed-dropdown',
586  };
587
588  static openDropdowns = [];
589  static globalClickListener = false;
590  static hoverableMQ = window.matchMedia('(min-width: 830px)');
591  static hoverSupport = Dropdown.evaluateHoverSupport();
592
593  constructor(rootElement) {
594    super();
595    this.rootElement = rootElement;
596    this.button = this.rootElement.querySelector(this.selectors.button);
597    this.container = this.rootElement.querySelector(this.selectors.container);
598    this.offset = parseInt((0,_utils_utils__WEBPACK_IMPORTED_MODULE_1__.getCssValue)(this.rootElement, '--dropdown-offset'), 10) || 0;
599    this.isHoverable = Dropdown.hoverSupport && this.rootElement.hasAttribute(this.stateAttributes.dropdownHover);
600    this.isToggler = this.rootElement.dataset.dropdownHover === 'toggler';
601    this.hoverListeners = null;
602    this.containerClone = null;
603    this.isFixedDropdown = this.rootElement.hasAttribute(this.featureAttributes.fixedDropdown);
604    this.state = this.getProxyState({ isOpen: false });
605    rootElement._instance = this;
606
607    this.bindEvents();
608  }
609
610  updateUI() {
611    const { isOpen } = this.state;
612    const { isVisible } = this.stateClasses;
613    const { ariaExpanded } = this.stateAttributes;
614    const isSubDropdown = this.rootElement.parentElement.closest(dropdownSelector);
615
616    if (Dropdown.openDropdowns.length && !isSubDropdown) {
617      Dropdown.closeAll();
618    }
619
620    this.button.setAttribute(ariaExpanded, isOpen);
621
622    if (isOpen) {
623      if (this.isFixedDropdown) {
624        this.createContainerClone();
625      } else {
626        this.positionContainer(this.container);
627        this.container.classList.add(isVisible);
628      }
629      Dropdown.openDropdowns.push(this);
630    } else {
631      if (this.isFixedDropdown && this.containerClone) {
632        document.body.removeChild(this.containerClone);
633        this.containerClone = null;
634      }
635      this.container.classList.remove(isVisible);
636      Dropdown.openDropdowns.splice(Dropdown.openDropdowns.indexOf(this), 1);
637    }
638  }
639
640  createContainerClone() {
641    this.containerClone = this.container.cloneNode(true);
642    this.containerClone.style.position = 'fixed';
643    document.body.appendChild(this.containerClone);
644    this.positionContainer(this.containerClone);
645    this.containerClone.classList.add(this.stateClasses.isVisible);
646  }
647
648  positionContainer(element) {
649    const isSubDropdown = this.rootElement.parentElement.closest(dropdownSelector);
650    // Floating UI
651    computePosition(this.button, element, {
652      middleware: [flip(), offset(this.offset), shift({ padding: 10 })],
653      placement: isSubDropdown ? 'right' : 'bottom',
654    }).then(({ x, y }) => {
655      element.style.left = `${x}px`;
656      element.style.top = `${y}px`;
657    });
658  }
659
660  toggle() {
661    this.state.isOpen = !this.state.isOpen;
662  }
663
664  open() {
665    this.state.isOpen = true;
666  }
667
668  close() {
669    this.state.isOpen = false;
670    if (this.containerClone) {
671      document.body.removeChild(this.containerClone);
672      this.containerClone = null;
673    }
674  }
675
676  static closeAll() {
677    Dropdown.openDropdowns.forEach((dropdown) => {
678      dropdown.close();
679    });
680  }
681
682  addHoverListeners() {
683    this.rootElement.addEventListener('mouseenter', () => {
684      Dropdown.hoverSupport && this.open();
685    });
686    this.rootElement.addEventListener('mouseleave', () => {
687      Dropdown.hoverSupport && this.close();
688    });
689    this.hoverListeners = true;
690  }
691
692  static evaluateHoverSupport() {
693    return (
694      Dropdown.hoverableMQ.matches &&
695      (window.matchMedia('(any-hover: hover)').matches || !('ontouchstart' in window || navigator.maxTouchPoints > 0))
696    );
697  }
698
699  bindEvents() {
700    this.isHoverable && this.addHoverListeners();
701
702    if (Dropdown.globalClickListener) return;
703
704    document.addEventListener('click', (e) => {
705      if (e.target.closest(this.selectors.button)) {
706        const dropdown = e.target.closest(dropdownSelector)._instance;
707        if (dropdown.isHoverable && !dropdown.isToggler) return;
708        e.preventDefault();
709        dropdown.toggle();
710        return;
711      }
712      if (Dropdown.openDropdowns.length && !e.target.closest(this.selectors.container)) {
713        Dropdown.closeAll();
714      }
715    });
716
717    Dropdown.globalClickListener = true;
718  }
719}
720
721class initDropdown {
722  constructor() {
723    this.init();
724  }
725
726  init() {
727    const dropdowns = document.querySelectorAll(dropdownSelector);
728    dropdowns.forEach((dropdown) => new Dropdown(dropdown));
729
730    const handleResize = (0,_utils_utils__WEBPACK_IMPORTED_MODULE_1__.debounce)(() => {
731      const currentHoverSupport = Dropdown.evaluateHoverSupport();
732
733      if (Dropdown.hoverSupport !== currentHoverSupport) {
734        Dropdown.hoverSupport = currentHoverSupport;
735
736        dropdowns.forEach((dropdown) => {
737          const instance = dropdown._instance;
738          if (instance.isHoverable && !instance.hoverListeners) {
739            instance.addHoverListeners();
740          }
741        });
742      }
743    }, 300);
744
745    window.addEventListener('resize', () => {
746      handleResize();
747      Dropdown.openDropdowns.length && Dropdown.closeAll();
748    });
749  }
750}
751
752
753/***/ }),
754
755/***/ "./js/components/Sticky.js":
756/*!*************************************!*\
757  !*** ./js/components/Sticky.js ***!
758  \*************************************/
759/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
760
761__webpack_require__.r(__webpack_exports__);
762/* harmony export */ __webpack_require__.d(__webpack_exports__, {
763/* harmony export */   "default": () => (/* binding */ initSticky)
764/* harmony export */ });
765/* harmony import */ var _BaseComponent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BaseComponent */ "./js/components/BaseComponent.js");
766/* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/utils */ "./js/utils/utils.js");
767
768
769
770const stickySelector = '[data-sticky]';
771
772class Sticky extends _BaseComponent__WEBPACK_IMPORTED_MODULE_0__["default"] {
773  selectors = {
774    containerElement: 'data-sticky-container',
775    offsetElement: '[data-sticky-offset]',
776    stickyHeaderElement: 'header',
777  };
778
779  stateClasses = {
780    isSticky: 'is-sticky',
781    isLocked: 'is-locked',
782  };
783
784  stateAttributes = {
785    isOnTop: 'data-sticky-on-top',
786  };
787
788  constructor(rootElement) {
789    super();
790    this.rootElement = rootElement;
791    this.rootElement.sticky = this;
792    this.isHeader = this.rootElement.classList.contains(this.selectors.stickyHeaderElement);
793    this.isOnTop = this.rootElement.hasAttribute(this.stateAttributes.isOnTop);
794    this.stickyElementName = this.rootElement.dataset.sticky;
795    this.containerElement = this.getContainerElement();
796    this.rootElementOffset = this.rootElement.offsetTop;
797    this.offsetElements = this.rootElement.querySelectorAll(this.selectors.offsetElement);
798    this.innerOffset = null;
799    this.state = this.getProxyState({ isSticky: false });
800
801    this.applyInitialSettings();
802    this.bindEvents();
803  }
804
805  updateUI() {
806    const { isSticky } = this.state;
807    const container = this.containerElement;
808    const stickyHeight = `${this.rootElement.offsetHeight - this.innerOffset}px`;
809    const stickyHeightVar = `--sticky-${this.stickyElementName}-height`;
810    const stickyOffsetVar = `--sticky-${this.stickyElementName}-offset`;
811
812    if (isSticky) {
813      this.rootElement.classList.add(this.stateClasses.isSticky);
814      if (!this.innerOffset) return;
815      container.style.setProperty(stickyHeightVar, stickyHeight);
816      container.style.setProperty(stickyOffsetVar, `${this.innerOffset}px`);
817    } else {
818      if (this.isHeader && document.body.classList.contains(this.stateClasses.isLocked)) return;
819
820      this.rootElement.classList.remove(this.stateClasses.isSticky);
821      if (!this.innerOffset) return;
822      container.style.removeProperty(stickyHeightVar);
823      container.style.removeProperty(stickyOffsetVar);
824    }
825  }
826
827  setInnerOffset() {
828    this.innerOffset = 0;
829    this.offsetElements.forEach((offsetElement) => {
830      this.innerOffset += offsetElement.offsetHeight;
831    });
832  }
833
834  setOuterOffset(boolean) {
835    if (!boolean) return;
836    this.rootElementOffset > 0 &&
837      this.rootElement.style.setProperty(`--${this.stickyElementName}-offset`, `${this.rootElementOffset}px`);
838  }
839
840  setHeightVariable(boolean) {
841    boolean &&
842      this.containerElement.style.setProperty(
843        `--${this.stickyElementName}-height`,
844        `${this.rootElement.offsetHeight}px`,
845      );
846  }
847
848  applyOuterOffset() {
849    this.setOuterOffset(this.isOnTop);
850    this.setHeightVariable(this.isOnTop);
851  }
852
853  recalculateOffset() {
854    this.rootElementOffset = this.rootElement.offsetTop;
855    this.applyOuterOffset();
856    this.setInnerOffset();
857    this.updateUI();
858  }
859
860  getContainerElement() {
861    return this.isHeader
862      ? document.body
863      : this.rootElement.closest(`[${this.selectors.containerElement}=${this.stickyElementName}]`);
864  }
865
866  toggleStickState() {
867    const mqMedium = window.matchMedia('(min-width: 829.98px)');
868    if (mqMedium.matches) return;
869
870    window.scrollY > this.rootElementOffset + this.innerOffset
871      ? (this.state.isSticky = true)
872      : (this.state.isSticky = false);
873  }
874
875  applyInitialSettings() {
876    this.applyOuterOffset();
877    this.setInnerOffset();
878    this.toggleStickState();
879  }
880
881  handleScroll() {
882    requestAnimationFrame(() => {
883      this.toggleStickState();
884    });
885  }
886
887  bindEvents() {
888    window.addEventListener('scroll', this.handleScroll.bind(this));
889    window.addEventListener(
890      'resize',
891      (0,_utils_utils__WEBPACK_IMPORTED_MODULE_1__.debounce)(() => {
892        this.recalculateOffset();
893      }, 300),
894    );
895  }
896}
897
898class initSticky {
899  constructor() {
900    this.init();
901  }
902
903  init() {
904    const stickyElements = document.querySelectorAll(stickySelector);
905    stickyElements.forEach((element) => new Sticky(element));
906  }
907}
908
909
910/***/ }),
911
912/***/ "./js/components/categories-nav.js":
913/*!*********************************************!*\
914  !*** ./js/components/categories-nav.js ***!
915  \*********************************************/
916/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
917
918__webpack_require__.r(__webpack_exports__);
919/* harmony export */ __webpack_require__.d(__webpack_exports__, {
920/* harmony export */   initCategoriesNav: () => (/* binding */ initCategoriesNav)
921/* harmony export */ });
922function initCategoriesNav() {
923  const catNavOpeners = document.querySelectorAll('[data-cat-nav-opener]');
924  const catNav = document.querySelector('.cat-nav');
925  const catNavLinks = catNav.querySelectorAll('.sublist-toggler');
926  const catSubLists = catNav.querySelectorAll('.nav__sublist');
927  const catCloseButtons = catNav.querySelectorAll('[data-cat-nav-close]');
928  const catOverlay = document.querySelector('.cat-overlay');
929  const mqSmall = window.matchMedia('(max-width: 829.98px)');
930
931  // Open categories menu
932  catNavOpeners.forEach((button) => {
933    button.addEventListener('click', (e) => {
934      e.preventDefault();
935      catNav.classList.toggle('is-visible');
936      catOverlay.classList.toggle('is-visible');
937      catNavOpeners.forEach((button) => {
938        button.classList.toggle('is-active');
939      });
940      document.body.classList.toggle('is-fixed', catNav.classList.contains('is-visible'));
941      document.body.classList.toggle(
942        'has-scroll',
943        document.body.scrollHeight > window.innerHeight && catNav.classList.contains('is-visible'),
944      );
945    });
946  });
947
948  // Toggle the categories menu state
949  function toggleCatMenu() {
950    if (mqSmall.matches) {
951      catNavLinks.forEach((link) => {
952        link.removeEventListener('mouseover', mouseoverCatlinksHandler);
953        link.addEventListener('click', clickCatLinksHandler);
954      });
955      catSubLists.forEach((sublist) => sublist.classList.remove('is-visible'));
956      return;
957    }
958    catNavLinks.forEach((link) => {
959      link.removeEventListener('click', clickCatLinksHandler);
960      link.addEventListener('mouseover', mouseoverCatlinksHandler);
961    });
962    catSubLists[0].classList.add('is-visible');
963  }
964
965  // Mobile categories menu
966  function clickCatLinksHandler(e) {
967    e.preventDefault();
968    const link = e.currentTarget;
969    catSubLists.forEach((sublist) => {
970      if (sublist.dataset.sublistIndex === link.dataset.sublistIndex) {
971        return sublist.classList.add('is-visible');
972      }
973      sublist.classList.remove('is-visible');
974    });
975  }
976
977  // Desktop categories menu
978  function mouseoverCatlinksHandler() {
979    const link = this;
980    link.classList.add('is-active');
981    catNavLinks.forEach((otherLink) => {
982      if (otherLink !== link) {
983        otherLink.classList.remove('is-active');
984      }
985    });
986    catSubLists.forEach((sublist) => {
987      if (sublist.dataset.sublistIndex === link.dataset.sublistIndex) {
988        return sublist.classList.add('is-visible');
989      }
990      sublist.classList.remove('is-visible');
991    });
992  }
993
994  mqSmall.addEventListener('change', toggleCatMenu);
995
996  toggleCatMenu();
997
998  // Mobile categories menu return buttons
999  const mobileNavReturnButtons = document.querySelectorAll('.nav__mobile-return');
1000  mobileNavReturnButtons.forEach((button) => {
1001    button.addEventListener('click', () => {
1002      const submenu = button.closest('.nav__sublist');
1003      submenu.classList.remove('is-visible');
1004    });
1005  });
1006
1007  catOverlay.addEventListener('click', () => {
1008    closeCatNav();
1009  });
1010
1011  catCloseButtons.forEach((button) => {
1012    button.addEventListener('click', () => {
1013      closeCatNav();
1014    });
1015  });
1016
1017  window.addEventListener('click', (e) => {
1018    if (!catNav.contains(e.target) && e.target.closest('[data-cat-nav-opener]') === null) {
1019      closeCatNav();
1020    }
1021  });
1022
1023  function closeCatNav() {
1024    catNav.classList.remove('is-visible');
1025    catOverlay.classList.remove('is-visible');
1026    catNavOpeners.forEach((button) => {
1027      button.classList.remove('is-active');
1028    });
1029    document.body.classList.remove('is-fixed');
1030    document.body.classList.remove('has-scroll');
1031  }
1032}
1033
1034
1035/***/ }),
1036
1037/***/ "./js/components/drag-nav.js":
1038/*!***************************************!*\
1039  !*** ./js/components/drag-nav.js ***!
1040  \***************************************/
1041/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1042
1043__webpack_require__.r(__webpack_exports__);
1044/* harmony export */ __webpack_require__.d(__webpack_exports__, {
1045/* harmony export */   "default": () => (/* binding */ DragNav)
1046/* harmony export */ });
1047/* Draggable navigation component */
1048class DragNav {
1049  constructor(selector, options) {
1050    if (typeof selector === 'string') {
1051      const elements = document.querySelectorAll(selector);
1052      if (elements.length > 1) {
1053        elements.forEach((element) => new DragNav(element, options));
1054        return;
1055      }
1056      selector = elements[0];
1057    }
1058
1059    if (!selector) {
1060      return console.error('Drag Nav: Selector not found.');
1061    }
1062
1063    this.container = selector.querySelector('.drag-nav-container');
1064    this.items = selector.querySelectorAll('a, div');
1065
1066    this.startX = null;
1067    this.scrollLeft = null;
1068
1069    this.mouseMoveHandler = this.mouseMoveHandler.bind(this);
1070    this.mouseUpHandler = this.mouseUpHandler.bind(this);
1071
1072    this.events();
1073  }
1074
1075  events() {
1076    this.container.addEventListener('mousedown', (e) => {
1077      this.startX = e.pageX - this.container.offsetLeft;
1078      this.scrollLeft = this.container.scrollLeft;
1079
1080      document.addEventListener('mousemove', this.mouseMoveHandler);
1081      document.addEventListener('mouseup', this.mouseUpHandler);
1082    });
1083  }
1084
1085  mouseMoveHandler(e) {
1086    // Disable default browser drag & drop behavior
1087    this.items.forEach((link) => {
1088      link.addEventListener('dragstart', (e) => {
1089        e.preventDefault();
1090      });
1091    });
1092    const x = e.pageX - this.container.offsetLeft;
1093    const distance = (x - this.startX) * 1;
1094    // Disable pointer events on links while dragging
1095    if (Math.abs(distance) > 10) {
1096      this.container.classList.add('is-dragging');
1097    }
1098    this.container.scrollLeft = this.scrollLeft - distance;
1099  }
1100
1101  mouseUpHandler() {
1102    this.container.classList.remove('is-dragging');
1103    document.removeEventListener('mousemove', this.mouseMoveHandler);
1104    document.removeEventListener('mouseup', this.mouseUpHandler);
1105  }
1106}
1107
1108
1109/***/ }),
1110
1111/***/ "./js/components/greedy-nav.js":
1112/*!*****************************************!*\
1113  !*** ./js/components/greedy-nav.js ***!
1114  \*****************************************/
1115/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1116
1117__webpack_require__.r(__webpack_exports__);
1118/* harmony export */ __webpack_require__.d(__webpack_exports__, {
1119/* harmony export */   "default": () => (/* binding */ GreedyNav)
1120/* harmony export */ });
1121/* Greedy navigation component */
1122/* Dinamically calculates total width of items and shows/hides them when needed */
1123class GreedyNav {
1124  constructor(selector, options) {
1125    if (typeof selector === 'string') {
1126      const elements = document.querySelectorAll(selector);
1127      if (elements.length > 1) {
1128        elements.forEach((element) => new GreedyNav(element, options));
1129        return;
1130      }
1131      selector = elements[0];
1132    }
1133
1134    if (!selector) {
1135      return console.error('Greedy Nav: Selector not found.');
1136    }
1137
1138    const defaultOptions = {
1139      visibleItemsContainer: '.greedy-items',
1140      item: '.greedy-item',
1141      button: '.greedy-button',
1142      buttonPlaceholder: 18,
1143      hiddenItemsContainer: '.greedy-hidden-items',
1144      minWidth: 830,
1145    };
1146
1147    this.options = Object.assign(defaultOptions, options);
1148    this.container = selector;
1149
1150    this.visibleItemsContainer = this.container.querySelector(this.options.visibleItemsContainer);
1151    this.items = this.container.querySelectorAll(this.options.item);
1152    this.button = this.container.querySelector(this.options.button);
1153    this.hiddenItemsContainer = this.container.querySelector(this.options.hiddenItemsContainer);
1154
1155    this.availableSpace = 0;
1156    this.totalItems = 0;
1157    this.totalOccupiedSpace = 0;
1158    this.itemBreakpoints = [];
1159    this.placeholderNeeded = false;
1160
1161    this.init();
1162    this.events();
1163  }
1164
1165  init() {
1166    this.items.forEach((item) => {
1167      this.totalItems += 1;
1168      this.totalOccupiedSpace += item.offsetWidth;
1169      this.itemBreakpoints.push(this.totalOccupiedSpace);
1170    });
1171
1172    this.checkAvailableSpace();
1173  }
1174
1175  checkAvailableSpace() {
1176    const viewportWidth = window.innerWidth;
1177
1178    if (viewportWidth < this.options.minWidth) {
1179      // Restore all hidden items to the visible container
1180      while (this.hiddenItemsContainer.children.length > 0) {
1181        this.visibleItemsContainer.appendChild(this.hiddenItemsContainer.firstElementChild);
1182      }
1183      this.placeholderNeeded = false;
1184      this.updateButtonState();
1185      return;
1186    }
1187
1188    // Proceed with greedy logic
1189    while (true) {
1190      this.availableSpace = this.container.offsetWidth - (this.placeholderNeeded ? this.options.buttonPlaceholder : 0);
1191      this.sumOfVisibleItems = this.visibleItemsContainer.children.length;
1192      this.requiredSpace = this.itemBreakpoints[this.sumOfVisibleItems - 1];
1193
1194      if (this.requiredSpace > this.availableSpace && this.sumOfVisibleItems > 0) {
1195        this.hiddenItemsContainer.prepend(this.visibleItemsContainer.lastElementChild);
1196        this.sumOfVisibleItems -= 1;
1197        this.placeholderNeeded = true;
1198      } else if (
1199        this.itemBreakpoints[this.totalItems - 1] <= this.container.offsetWidth &&
1200        this.hiddenItemsContainer.children.length > 0
1201      ) {
1202        this.visibleItemsContainer.appendChild(this.hiddenItemsContainer.firstElementChild);
1203        this.sumOfVisibleItems += 1;
1204        this.placeholderNeeded = false;
1205      } else if (
1206        this.availableSpace >= this.itemBreakpoints[this.sumOfVisibleItems] &&
1207        this.hiddenItemsContainer.children.length > 0
1208      ) {
1209        this.visibleItemsContainer.appendChild(this.hiddenItemsContainer.firstElementChild);
1210        this.sumOfVisibleItems += 1;
1211      } else {
1212        break;
1213      }
1214    }
1215
1216    this.updateButtonState();
1217  }
1218
1219  updateButtonState() {
1220    this.button.setAttribute('data-counter', this.totalItems - this.visibleItemsContainer.children.length);
1221    if (this.visibleItemsContainer.children.length === this.totalItems) {
1222      this.button.classList.remove('is-visible');
1223    } else {
1224      this.button.classList.add('is-visible');
1225    }
1226  }
1227
1228  events() {
1229    window.addEventListener('resize', this.debounce(this.checkAvailableSpace.bind(this), 500));
1230  }
1231
1232  debounce(fn, time) {
1233    let timeout;
1234    return function () {
1235      clearTimeout(timeout);
1236      const context = this;
1237      const args = arguments;
1238      timeout = setTimeout(() =>
1238 fn.apply(context, args), time);
1239    };
1240  }
1241}
1242
1243
1244/***/ }),
1245
1246/***/ "./js/libs/custom-select-settings.js":
1247/*!***********************************************!*\
1248  !*** ./js/libs/custom-select-settings.js ***!
1249  \***********************************************/
1250/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1251
1252__webpack_require__.r(__webpack_exports__);
1253/* harmony export */ __webpack_require__.d(__webpack_exports__, {
1254/* harmony export */   initCustomSelect: () => (/* binding */ initCustomSelect)
1255/* harmony export */ });
1256/* Custom select settings */
1257function initCustomSelect() {
1258  if (typeof customSelect === 'undefined') return;
1259
1260  const headerSelects = customSelect('.header-select');
1261  const selects = customSelect('.select');
1262
1263  // Improve custom select aria
1264  const selectOpeners = document.querySelectorAll('.custom-select-opener');
1265
1266  selectOpeners.forEach((opener) => {
1267    opener.setAttribute('aria-label', 'Select category');
1268  });
1269
1270  // Inject data-flag into custom options
1271  document.querySelectorAll('.header-lang').forEach((customSelect) => {
1272    const instance = customSelect.querySelector('.header-select').customSelect;
1273    const select = instance.select;
1274    const options = customSelect.querySelectorAll('option');
1275    const customItems = customSelect.parentNode.querySelectorAll('.custom-select-option');
1276
1277    options.forEach((option, index) => {
1278      const flag = option.dataset.flag;
1279      if (flag && customItems[index]) {
1280        customItems[index].setAttribute('data-flag', flag);
1281      }
1282    });
1283
1284    // Set initial flag on opener
1285    const selectedOption = select.options[select.selectedIndex];
1286    const initialFlag = selectedOption.dataset.flag;
1287    if (initialFlag) {
1288      instance.opener.setAttribute('data-flag', initialFlag);
1289    }
1290
1291    select.addEventListener('change', () => {
1292      const selectedOption = select.options[select.selectedIndex];
1293      const flag = selectedOption.dataset.flag;
1294
1295      if (flag) {
1296        instance.opener.setAttribute('data-flag', flag);
1297      }
1298    });
1299  });
1300}
1301
1302
1303/***/ }),
1304
1305/***/ "./js/libs/intl-tel-settings.js":
1306/*!******************************************!*\
1307  !*** ./js/libs/intl-tel-settings.js ***!
1308  \******************************************/
1309/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1310
1311__webpack_require__.r(__webpack_exports__);
1312/* harmony export */ __webpack_require__.d(__webpack_exports__, {
1313/* harmony export */   initIntlTel: () => (/* binding */ initIntlTel)
1314/* harmony export */ });
1315/* International Telephone Input settings */
1316function initIntlTel() {
1317  if (typeof intlTelInput === 'undefined') return;
1318
1319  const callbackBtn = document.querySelector('.link[data-dialog-open="call"]');
1320  const callbackDialog = document.querySelector('.dialog-container[data-dialog="call"]');
1321
1322  callbackBtn &&
1323    callbackBtn.addEventListener('click', initIntlTelInput, {
1324      once: true,
1325    });
1326
1327  function initIntlTelInput() {
1328    const callbackIntlTelInput = callbackDialog.querySelector('.intl-phone');
1329    intlTelInput(callbackIntlTelInput, {
1330      utilsScript: './vendor/intl-tel/js/utils.js',
1331      useFullscreenPopup: false,
1332      showSelectedDialCode: true,
1333      initialCountry: $('#initial_country').val(),
1334      onlyCountries: JSON.parse($('#country_iso').val()),
1335    });
1336  }
1337
1338  const intlInputs = document.querySelectorAll('form:not(.callback-form) .intl-phone');
1339
1340  intlInputs.forEach((input) => {
1341    intlTelInput(input, {
1342      utilsScript: './vendor/intl-tel/js/utils.js',
1343      useFullscreenPopup: false,
1344      showSelectedDialCode: true,
1345      initialCountry: $('#initial_country').val(),
1346      onlyCountries: JSON.parse($('#country_iso').val()),
1347    });
1348  });
1349}
1350
1351
1352/***/ }),
1353
1354/***/ "./js/libs/just-validate-settings.js":
1355/*!***********************************************!*\
1356  !*** ./js/libs/just-validate-settings.js ***!
1357  \***********************************************/
1358/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1359
1360__webpack_require__.r(__webpack_exports__);
1361/* harmony export */ __webpack_require__.d(__webpack_exports__, {
1362/* harmony export */   initJustValidate: () => (/* binding */ initJustValidate)
1363/* harmony export */ });
1364/* Just validate settings */
1365function initJustValidate() {
1366  if (typeof JustValidate === 'undefined') return;
1367
1368  const forms = document.querySelectorAll('.form:not(.form--native-submit)');
1369
1370  forms.forEach((form) => {
1371    const validator = new JustValidate(form, {
1372      errorLabelStyle: {
1373        // Remove default inline styling
1374        color: false,
1375      },
1376      errorFieldCssClass: 'error-field',
1377      errorLabelCssClass: 'error-label',
1378    });
1379
1380    /* Text fields */
1381    const textFields = form.querySelectorAll('.input-text[required]');
1382    const strictTextFieldValidation = true;
1383    const strictTextFieldValidationRuleset = {
1384      rule: 'customRegexp',
1385      errorMessage: 'Incorrect input format',
1386      // Latin & russian letters, numbers, space, hyphens
1387      value: /^[A-Za-z0-9А-Яа-яЁё\s\-–—]+$/gi,
1388    };
1389
1390    textFields.forEach((field) => {
1391      validator.addField(field, [
1392        {
1393          rule: 'required',
1394          errorMessage: 'Required field',
1395        },
1396        ...(strictTextFieldValidation ? [strictTextFieldValidationRuleset] : []),
1397        {
1398          rule: 'minLength',
1399          errorMessage: 'Minimum 2 characters',
1400          value: 2,
1401        },
1402        {
1403          rule: 'maxLength',
1404          errorMessage: 'Maximum 30 characters',
1405          value: 30,
1406        },
1407      ]);
1408    });
1409
1410    /* Textarea fields */
1411    const textareaFields = form.querySelectorAll('.input-textarea[required]');
1412    const strictTextareaValidation = false;
1413    const strictTextareaValidationRuleset = {
1414      rule: 'customRegexp',
1415      errorMessage: 'Incorrect input format',
1416      // Latin & russian letters, numbers, space,
1417      // general punctuation marks, quotes
1418      value: /^[A-Za-z0-9А-Яа-яЁё\s\-_.,!?;:'"«»“”‘’()]+$/gi,
1419    };
1420
1421    textareaFields.forEach((field) => {
1422      validator.addField(field, [
1423        {
1424          rule: 'required',
1425          errorMessage: 'Required field',
1426        },
1427        ...(strictTextareaValidation ? [strictTextareaValidationRuleset] : []),
1428        {
1429          rule: 'minLength',
1430          errorMessage: 'Minimum 5 characters',
1431          value: 5,
1432        },
1433        {
1434          rule: 'maxLength',
1435          errorMessage: 'Maximum 2000 characters',
1436          value: 2000,
1437        },
1438      ]);
1439    });
1440
1441    /* Email fields */
1442    const emailFields = form.querySelectorAll('.input-email[required]');
1443
1444    emailFields.forEach((field) => {
1445      validator.addField(field, [
1446        {
1447          rule: 'required',
1448          errorMessage: 'Required field',
1449        },
1450        {
1451          rule: 'email',
1452          errorMessage: 'Invalid email format',
1453        },
1454      ]);
1455    });
1456
1457    /* Phone number fields */
1458    const phoneFields = form.querySelectorAll('.input-tel[required]');
1459    // 11 digit + iMask symbols format
1460    const iMaskPhoneRegex = /^(?:\+7|(?:\D*\d){11}\D*)$/gi;
1461    // Russian phone number formats + simple 7 digit format
1462    const russianPhoneRegex =
1463      /^(?:\+?7|8)?[\s-]?(?:\(?(?:9\d{2}|4[6-9]\d|5\d{2}|3[0-8]\d|82\d|8[1-9][0-9])\)?[\s-]?\d{3}[\s-]?\d{2}[\s-]?\d{2}|\d{3}[\s-]?\d{2}[\s-]?\d{2})$/gi;
1464    // Simplified phone number format
1465    const simplifiedPhoneRegex = /^(?:\D*\d){7,10}\D*$/gi;
1466
1467    phoneFields.forEach((field) => {
1468      validator.addField(field, [
1469        {
1470          rule: 'required',
1471          errorMessage: 'Required field',
1472        },
1473        {
1474          rule: 'customRegexp',
1475          errorMessage: 'Invalid phone number',
1476          value: simplifiedPhoneRegex,
1477        },
1478      ]);
1479    });
1480
1481    /* Password fields */
1482    const passwordFields = form.querySelectorAll('.input-password[required]');
1483
1484    passwordFields.forEach((field) => {
1485      validator.addField(field, [
1486        {
1487          rule: 'required',
1488          errorMessage: 'Required field',
1489        },
1490        {
1491          rule: 'minLength',
1492          errorMessage: 'Minimum 8 characters',
1493          value: 8,
1494        },
1495      ]);
1496    });
1497
1498    /* Checkboxes */
1499    const checkboxes = form.querySelectorAll('.input-checkbox[required]');
1500
1501    checkboxes.forEach((checkbox) => {
1502      validator.addField(checkbox, [
1503        {
1504          rule: 'required',
1505          errorMessage: 'Required field',
1506        },
1507      ]);
1508    });
1509
1510    /* Radio groups */
1511    const radioGroups = form.querySelectorAll('.radio-fieldset--required');
1512
1513    radioGroups.forEach((radioGroup) => {
1514      validator.addRequiredGroup(radioGroup, 'Select an option');
1515    });
1516
1517    /* Selects */
1518    const selects = form.querySelectorAll('select[required]');
1519
1520    selects.forEach((select) => {
1521      validator.addField(select, [
1522        {
1523          rule: 'required',
1524          errorMessage: 'Select an option',
1525        },
1526      ]);
1527    });
1528
1529    validator.onFail((e) => {
1530      // Error logic goes here
1531    });
1532
1533    validator.onSuccess((e) => {
1534      closeDialog(form);
1535      // Success logic goes here
1536
1537      /*
1538        Example: redirect to success page upon form submission
1539      */
1540      // const rootLocation = 'https://domen.name';
1541      // const successPage = 'success.html';
1542      // window.location.href = rootLocation + successPage;
1543      /*
1544        Example: show status dialog upon form submission
1545      */
1546      // const xhr = new XMLHttpRequest();
1547      // const formData = new FormData(form);
1548      // xhr.open('POST', form.getAttribute('action'));
1549      // xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1550      // xhr.send(formData);
1551      // xhr.onreadystatechange = function () {
1552      //   const statusDialogSuccess = document.querySelector('dialog[data-dialog="success"]');
1553      //   // Form send successfully
1554      //   if (this.readyState === 4 && this.status === 200) {
1555      //     statusDialogSuccess.showModal();
1556      //   }
1557      // };
1558      // xhr.onerror = function () {
1559      //   const statusDialogError = document.querySelector('dialog[data-dialog="error"]');
1560      //   statusDialogError.showModal();
1561      // };
1562    });
1563  });
1564}
1565
1566function closeDialog(form) {
1567  if (form.method !== 'dialog') return;
1568  const dialog = form.closest('dialog')._instance;
1569  dialog.close();
1570}
1571
1572
1573/***/ }),
1574
1575/***/ "./js/utils/utils.js":
1576/*!*******************************!*\
1577  !*** ./js/utils/utils.js ***!
1578  \*******************************/
1579/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1580
1581__webpack_require__.r(__webpack_exports__);
1582/* harmony export */ __webpack_require__.d(__webpack_exports__, {
1583/* harmony export */   applyInitialSettings: () => (/* binding */ applyInitialSettings),
1584/* harmony export */   checkDialog: () => (/* binding */ checkDialog),
1585/* harmony export */   createOverlay: () => (/* binding */ createOverlay),
1586/* harmony export */   debounce: () => (/* binding */ debounce),
1587/* harmony export */   getCssValue: () => (/* binding */ getCssValue),
1588/* harmony export */   initBrowserChecks: () => (/* binding */ initBrowserChecks),
1589/* harmony export */   lockScrolling: () => (/* binding */ lockScrolling)
1590/* harmony export */ });
1591/**
1592  Browser utilities
1593================= **/
1594
1595/* Check if JavaScript is enabled */
1596function checkJS() {
1597  document.documentElement.classList.remove('no-js');
1598}
1599
1600/* Detect browser */
1601function detectBrowser() {
1602  const test = (regexp) => regexp.test(navigator.userAgent);
1603  const browser = (() => {
1604    switch (true) {
1605      case test(/edg/i):
1606        return 'edge';
1607      case test(/trident/i):
1608        return 'ie';
1609      case test(/firefox|fxios/i):
1610        return 'firefox';
1611      case test(/opr\//i):
1612        return 'opera';
1613      case test(/chrome|chromium|crios/i):
1614        return 'chrome';
1615      case test(/safari|AppleWebKit/i):
1616        return 'safari';
1617      default:
1618        return 'unknown';
1619    }
1620  })();
1621
1622  document.documentElement.classList.add(`ua-${browser}`);
1623}
1624
1625/* Check if browser supports .webp-images */
1626function checkWebp() {
1627  const webp = new Image();
1628  webp.src =
1629    'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
1630
1631  webp.onload = webp.onerror = () => {
1632    const isWebpSupported = webp.height === 2;
1633    if (!isWebpSupported) document.documentElement.classList.remove('webp');
1634  };
1635}
1636
1637/* Check if browser supports dialog element */
1638function checkDialog() {
1639  document.addEventListener('DOMContentLoaded', function () {
1640    const dialog = document.querySelector('dialog');
1641    try {
1642      dialog && dialog.close();
1643    } catch (e) {
1644      const head = document.getElementsByTagName('HEAD')[0];
1645      const link = document.createElement('link');
1646      const script = document.createElement('script');
1647      const dialogs = document.querySelectorAll('dialog');
1648      link.rel = 'stylesheet';
1649      link.type = 'text/css';
1650      link.href = 'vendor/dialog-polyfill/dialog-polyfill.min.css';
1651      script.src = 'vendor/dialog-polyfill/dialog-polyfill.min.js';
1652      head.append(link, script);
1653      script.addEventListener('load', () => {
1654        dialogs.forEach((dialog) => {
1655          dialogPolyfill.registerDialog(dialog);
1656        });
1657      });
1658    }
1659  });
1660}
1661
1662function initBrowserChecks() {
1663  checkJS();
1664  detectBrowser();
1665  checkWebp();
1666  checkDialog();
1667}
1668
1669/**
1670  DOM utilities
1671============= **/
1672
1673/* Disable a[href="#!"] links */
1674function disableEmptyLinks() {
1675  document.addEventListener('click', (e) => {
1676    if (e.target.matches('a[href="#!"]')) {
1677      e.preventDefault();
1678    }
1679  });
1680}
1681
1682/* Disable CSS transitions during window resize */
1683function disableTransitionsOnResize(className = 'no-transitions', delay = 300) {
1684  const handleResize = debounce(() => {
1685    document.body.classList.remove(className);
1686  }, delay);
1687
1688  window.addEventListener('resize', () => {
1689    document.body.classList.add(className);
1690    handleResize();
1691  });
1692}
1693
1694function applyInitialSettings() {
1695  disableEmptyLinks();
1696  disableTransitionsOnResize();
1697}
1698
1699/**
1700  General utilities
1701================= **/
1702
1703/* Debounce function to limit its execution rate */
1704function debounce(func, delay) {
1705  let timeout;
1706  return function (...args) {
1707    clearTimeout(timeout);
1708    timeout = setTimeout(() => func.apply(this, args), delay);
1709  };
1710}
1711
1712/* Get CSS property value */
1713function getCssValue(element, property) {
1714  return window.getComputedStyle(element).getPropertyValue(property);
1715}
1716
1717/**
1718  UI utilities
1719============ **/
1720
1721/* Create overlay element */
1722function createOverlay(className, parent = document.body, filter = false) {
1723  const overlay = document.createElement('div');
1724  if (filter) {
1725    const filter = document.createElement('div');
1726    filter.classList.add('overlay__filter');
1727    overlay.appendChild(filter);
1728  }
1729  overlay.classList.add(className, 'overlay');
1730  parent.appendChild(overlay);
1731  return overlay;
1732}
1733
1734/* Lock scrolling */
1735function lockScrolling(enableLock, source, delay = 0) {
1736  const { documentElement: html, body } = document;
1737  const currentSource = body.dataset.lockSource;
1738  const hasSameSource = currentSource === source;
1739  const scrollY = window.scrollY;
1740
1741  // Toggle lock state and document scrollbar
1742  if (!currentSource || hasSameSource) {
1743    body.classList.toggle('is-locked', enableLock);
1744    html.classList.toggle('has-scrollbar', body.scrollHeight > window.innerHeight && enableLock);
1745  }
1746
1747  // Toggle lock source
1748  if (enableLock && !currentSource) {
1749    body.dataset.lockSource = source;
1750  } else if (!enableLock && hasSameSource) {
1751    body.removeAttribute('data-lock-source');
1752  }
1753
1754  // Manage scroll offset
1755  if (enableLock && scrollY > 0) {
1756    body.style.setProperty('--top-body-offset', `-${scrollY}px`);
1757  } else if (hasSameSource) {
1758    const offset = Math.abs(parseInt(getCssValue(body, '--top-body-offset') || '0', 10));
1759    setTimeout(() => {
1760      body.style.removeProperty('--top-body-offset');
1761    }, delay);
1762    requestAnimationFrame(() => {
1763      window.scrollTo({ top: offset, left: 0, behavior: 'instant' });
1764    });
1765  }
1766}
1767
1768
1769/***/ })
1769
1770
1771/******/ 	});
1772/************************************************************************/
1773/******/ 	// The module cache
1774/******/ 	var __webpack_module_cache__ = {};
1775/******/
1776/******/ 	// The require function
1777/******/ 	function __webpack_require__(moduleId) {
1778/******/ 		// Check if module is in cache
1779/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
1780/******/ 		if (cachedModule !== undefined) {
1781/******/ 			return cachedModule.exports;
1782/******/ 		}
1783/******/ 		// Create a new module (and put it into the cache)
1784/******/ 		var module = __webpack_module_cache__[moduleId] = {
1785/******/ 			// no module.id needed
1786/******/ 			// no module.loaded needed
1787/******/ 			exports: {}
1788/******/ 		};
1789/******/
1790/******/ 		// Execute the module function
1791/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
1792/******/
1793/******/ 		// Return the exports of the module
1794/******/ 		return module.exports;
1795/******/ 	}
1796/******/
1797/************************************************************************/
1798/******/ 	/* webpack/runtime/define property getters */
1799/******/ 	(() => {
1800/******/ 		// define getter functions for harmony exports
1801/******/ 		__webpack_require__.d = (exports, definition) => {
1802/******/ 			for(var key in definition) {
1803/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
1804/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
1805/******/ 				}
1806/******/ 			}
1807/******/ 		};
1808/******/ 	})();
1809/******/
1810/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
1811/******/ 	(() => {
1812/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
1813/******/ 	})();
1814/******/
1815/******/ 	/* webpack/runtime/make namespace object */
1816/******/ 	(() => {
1817/******/ 		// define __esModule on exports
1818/******/ 		__webpack_require__.r = (exports) => {
1819/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
1820/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1821/******/ 			}
1822/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
1823/******/ 		};
1824/******/ 	})();
1825/******/
1826/************************************************************************/
1827var __webpack_exports__ = {};
1828// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
1829(() => {
1830/*!************************!*\
1831  !*** ./js/main.js ***!
1832  \************************/
1833__webpack_require__.r(__webpack_exports__);
1834/* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/utils */ "./js/utils/utils.js");
1835/* harmony import */ var _components_Sticky__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/Sticky */ "./js/components/Sticky.js");
1836/* harmony import */ var _components_Accordion__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/Accordion */ "./js/components/Accordion.js");
1837/* harmony import */ var _components_Dialog__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/Dialog */ "./js/components/Dialog.js");
1838/* harmony import */ var _components_Drawer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components/Drawer */ "./js/components/Drawer.js");
1839/* harmony import */ var _components_Dropdown__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/Dropdown */ "./js/components/Dropdown.js");
1840/* harmony import */ var _components_greedy_nav__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/greedy-nav */ "./js/components/greedy-nav.js");
1841/* harmony import */ var _components_drag_nav__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./components/drag-nav */ "./js/components/drag-nav.js");
1842/* harmony import */ var _libs_just_validate_settings__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./libs/just-validate-settings */ "./js/libs/just-validate-settings.js");
1843/* harmony import */ var _libs_custom_select_settings__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./libs/custom-select-settings */ "./js/libs/custom-select-settings.js");
1844/* harmony import */ var _libs_intl_tel_settings__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./libs/intl-tel-settings */ "./js/libs/intl-tel-settings.js");
1845/* harmony import */ var _components_categories_nav__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./components/categories-nav */ "./js/components/categories-nav.js");
1846/**
1847  Inintial checks & settings
1848========================== **/
1849
1850
1851(0,_utils_utils__WEBPACK_IMPORTED_MODULE_0__.initBrowserChecks)();
1852(0,_utils_utils__WEBPACK_IMPORTED_MODULE_0__.applyInitialSettings)();
1853
1854/**
1855  Components
1856========== **/
1857
1858
1859
1860
1861
1862
1863
1864
1865new _components_Sticky__WEBPACK_IMPORTED_MODULE_1__["default"]();
1866new _components_Accordion__WEBPACK_IMPORTED_MODULE_2__["default"]();
1867new _components_Dialog__WEBPACK_IMPORTED_MODULE_3__["default"]();
1868new _components_Drawer__WEBPACK_IMPORTED_MODULE_4__["default"]();
1869new _components_Dropdown__WEBPACK_IMPORTED_MODULE_5__["default"]();
1870const greedyNav = new _components_greedy_nav__WEBPACK_IMPORTED_MODULE_6__["default"]('.greedy-nav');
1871const dragNav = new _components_drag_nav__WEBPACK_IMPORTED_MODULE_7__["default"]('.drag-nav');
1872
1873/**
1874  Form elements UX
1875================ **/
1876
1877/* Autoresizible textarea */
1878
1879const textareaFields = document.querySelectorAll('.textarea-field');
1880
1881textareaFields.forEach((field) => {
1882  const textarea = field.querySelector('.input-textarea');
1883  const initialHeight = textarea.offsetHeight;
1884  const initialOffset = initialHeight - textarea.clientHeight;
1885
1886  textarea.addEventListener('input', () => {
1887    textarea.style.height = initialHeight + 'px';
1888    textarea.style.height = textarea.closest('.dialog')
1889      ? textarea.scrollHeight + initialOffset + 2 + 'px'
1890      : textarea.scrollHeight + initialOffset + 'px';
1891    // Fix clumsy textarea scroll
1892    textarea.scrollTo(0, textarea.scrollHeight);
1893  });
1894});
1895
1896/* Quantity inputs */
1897
1898document.querySelectorAll('.qty-input__plus').forEach((button) => {
1899  button.addEventListener('click', () => {
1900    const input = button.parentNode.querySelector('.qty-input__qty-field');
1901    let val = parseInt(input.value);
1902    isNaN(val) && (val = 0);
1903    input.value = val + 1;
1904  });
1905});
1906
1907document.querySelectorAll('.qty-input__minus').forEach((button) => {
1908  button.addEventListener('click', () => {
1909    const input = button.parentNode.querySelector('.qty-input__qty-field');
1910    const val = parseInt(input.value);
1911    if (val > 1) {
1912      input.value = val - 1;
1913    }
1914  });
1915});
1916
1917/* Show uploaded file name */
1918
1919const fileUploadFields = document.querySelectorAll('.file-field');
1920
1921fileUploadFields.forEach((field) => {
1922  const input = field.querySelector('.input-file');
1923  const label = field.querySelector('.label-file');
1924  const labelText = label.textContent;
1925
1926  input.addEventListener('change', (e) => {
1927    label.textContent = e.target.files.length > 0 ? e.target.files[0].name : labelText;
1928  });
1929});
1930
1931/* Password visibility toggler */
1932
1933const passwordTogglers = document.querySelectorAll('.password-toggler');
1934
1935passwordTogglers.forEach((toggler) => {
1936  toggler.addEventListener('click', () => {
1937    const input = toggler.nextSibling;
1938    toggler.classList.toggle('is-active');
1939    input.type = input.type === 'password' ? 'text' : 'password';
1940  });
1941});
1942
1943/**
1944  Vendor libs settings
1945==================== **/
1946
1947
1948
1949
1950(0,_libs_just_validate_settings__WEBPACK_IMPORTED_MODULE_8__.initJustValidate)();
1951(0,_libs_custom_select_settings__WEBPACK_IMPORTED_MODULE_9__.initCustomSelect)();
1952(0,_libs_intl_tel_settings__WEBPACK_IMPORTED_MODULE_10__.initIntlTel)();
1953
1954/**
1955  Categories nav
1956=============- **/
1957
1958
1959(0,_components_categories_nav__WEBPACK_IMPORTED_MODULE_11__.initCategoriesNav)();
1960
1961/**
1962  Payment method's switcher
1963======================= **/
1964
1965const paymentMethod = document.querySelector('.payment-select')?.customSelect;
1966
1967paymentMethod &&
1968  paymentMethod.select.addEventListener('change', (e) => {
1969    if (e.target.value === 'crypto')
1970      return swithPaymentMethod(
1971        '.payment-information__card-field',
1972        '.payment-information__crypto-field',
1973        'I have paid',
1974      );
1975    if (e.target.value === 'card')
1976      return swithPaymentMethod(
1977        '.payment-information__crypto-field',
1978        '.payment-information__card-field',
1979        'Place the order',
1980      );
1981  });
1982
1983// Set crypto method first
1984paymentMethod &&
1985  swithPaymentMethod('.payment-information__card-field', '.payment-information__crypto-field', 'I have paid');
1986
1987function swithPaymentMethod(hiddenClasses, shownClasses, submitText) {
1988  const parent = paymentMethod.select.closest('.payment-information');
1989  parent.querySelectorAll(hiddenClasses).forEach((field) => {
1990    field.classList.add('hidden-field');
1991    field.querySelectorAll('input').forEach((input) => input.setAttribute('disabled', ''));
1992  });
1993  parent.querySelectorAll(shownClasses).forEach((field) => {
1994    field.classList.remove('hidden-field');
1995    field.querySelectorAll('input').forEach((input) => input.removeAttribute('disabled'));
1996  });
1997  parent.closest('.order-form').querySelector('.submit-button').textContent = submitText;
1998  parent.closest('.order-form').querySelector('.submit-button').value = submitText;
1999}
2000
2001/**
2002  Copy text from copy fields
2003========================-= **/
2004
2005const copyFields = document.querySelectorAll('.copy-field');
2006
2007copyFields.forEach((field) => {
2008  const text = field.querySelector('.copy-text').textContent;
2009  const button = field.querySelector('.copy-button');
2010
2011  button.addEventListener('click', () => {
2012    if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
2013      button.querySelector('.button-text').classList.add('is-visible');
2014      setTimeout(() => {
2015        button.querySelector('.button-text').classList.remove('is-visible');
2016      }, 1500);
2017      return navigator.clipboard.writeText(text);
2018    }
2019  });
2020});
2021
2022})();
2023
2024/******/ })()
2025;

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.