PageSourceSearch

https://portaprima.ru/bitrix/cache/js/s1/portaprima-main/template_…9689cdbfe22d37902db6_v1.js?1790620776223684

js portaprima.ru collected 2026-10-06 07:28:07 UTC 223,684 bytes, 6,277 lines download raw bytes

1
2; /* Start:"a:4:{s:4:"full";s:62:"/bitrix/templates/portaprima-main/js/script.js?178817727080091";s:6:"source";s:46:"/bitrix/templates/portaprima-main/js/script.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
3// Мини-хелперы вместо jQuery. Цель - убрать зависимость от библиотеки (~30 КБ gzip)
4// на страницах, где её больше никто не использует (каталог, главная).
5//
6//   ready(fn)             - вместо jQuery(function(){})
7//   qs(sel, root)         - вместо $(sel).get(0)
8//   qsa(sel, root)        - вместо $(sel), всегда массив (можно forEach/map/filter)
9//   on(root, ev, sel, fn) - делегирование: подписка на родителя, как $(root).on(ev, sel, fn).
10//                           В обработчике this - элемент, совпавший с sel (как в jQuery).
11//                           sel можно опустить - тогда это обычная подписка.
12function ready(fn) {
13	if (document.readyState === 'loading') {
14		document.addEventListener('DOMContentLoaded', fn);
15	} else {
16		fn();
17	}
18}
19
20function qs(sel, root) {
21	return (root || document).querySelector(sel);
22}
23
24function qsa(sel, root) {
25	return Array.prototype.slice.call((root || document).querySelectorAll(sel));
26}
27
28// Вместо $(el).trigger('open'). Всплывающее CustomEvent ловится и делегированием через on().
29// ВАЖНО: jQuery-события ('open'/'close' из .trigger) и DOM-события не пересекаются,
30// поэтому вся система попапов переведена на fire() разом.
31function fire(el, name, detail) {
32	if (!el) {
33		return;
34	}
35	el.dispatchEvent(new CustomEvent(name, {bubbles: true, detail: detail}));
36}
37
38function on(root, event, selector, handler) {
39	if (typeof selector === 'function') {
40		handler = selector;
41		selector = null;
42	}
43	if (!root) {
44		return;
45	}
46	root.addEventListener(event, function(e) {
47		if (!selector) {
48			handler.call(root, e);
49			return;
50		}
51		var target = e.target.closest(selector);
52		// closest мог выйти за пределы root - такие события не наши
53		if (target && root.contains(target)) {
54			handler.call(target, e);
55		}
56	});
57}
58
59ready(function() {
60	var queryString = window.location.search; // Получаем часть URL после знака ?
61	var urlParams = new URLSearchParams(queryString); // Используем URLSearchParams для разбора параметров
62	if (urlParams.getAll('show-gray-panel').length) {
63		BX.setCookie('show-gray-panel', 'Y', {expires: 60*60*24*7, path: '/', domain: '.portaprima.ru'});
64		// Планшет с серой панелью выводим из композитного кэша: BITRIX_SM_NCC - штатный флаг
65		// Bitrix "не отдавать и не сохранять композит", его уважают и PHP, и nginx.
66		// Срок тот же, что у show-gray-panel: иначе кука отвалится раньше, nginx отдаст планшету
67		// общий кэш мимо PHP - и панели не будет, и NCC поставить будет уже некому.
68		BX.setCookie('BITRIX_SM_NCC', 'Y', {expires: 60*60*24*7, path: '/', domain: '.portaprima.ru'});
69		var returlUrl = urlParams.getAll('return-url');
70		// returlUrl = returlUrl && returlUrl.length && returlUrl[0];
71		// if (returlUrl) {
72		// 	BX.setCookie('panel-return-url', returlUrl, {expires: 60*60*24*7, path: '/', domain: '.portaprima.ru'});
73		// }
74	}
75});
76ready(function() {
77    const intro = document.querySelector('.intro'),
78          bgIntro = intro && intro.querySelector('.bg'),
79          bgIntroImgs = bgIntro && bgIntro.querySelectorAll('.bg-img'),
80          body  = document.querySelector('body'),
81          navigationSlides = document.querySelectorAll('.navigation_slide'),
82          intro_inners = document.querySelectorAll('.intro_inner');
83    
84    if (navigationSlides && navigationSlides.length) {
85        let introStartClick = false;
86        let introImg = false;
87        if (bgIntroImgs.length) {
88            bgIntroImgs.forEach(el => {
89                if (el.classList.contains('active')) {
90                    introImg = el;
91                    if (introImg.classList.contains('hide-gradient')) {
92                        bgIntro.classList.add('hide-gradient');
93                    }
94                    else {
95                        bgIntro.classList.remove('hide-gradient');
96                    }
97                    if (introImg.classList.contains('cursor-pointer')) {
98                        bgIntro.classList.add('cursor-pointer');
99                    }
100                    else {
101                        bgIntro.classList.remove('cursor-pointer');
102                    }
103                }
104            });
105        }
106
107        function newSlide(i) {
108            navigationSlides.forEach(el => el.classList.remove('active'));
109            if (!i) {
110                index++;
111            } else {
112                index = i;
113            }
114            if (index > navigationSlides.length) {
115                index = 1;
116            }
117            let bg = intro_inners[index-1].dataset.bg;
118            let bgClass = intro_inners[index-1].dataset.bgClass;
119            if (bg) {
120                bgIntro.style.opacity = `0`;
121                bgIntro.style = `
122                    background-image: url('${bg}');
123                `;
124                bgIntro.style.opacity = `1`;
125            }
126            if (bgClass) {
127                bgIntro.style.opacity = `0`;
128                intro.classList.forEach(function (value, key) {
129                    if (value.startsWith('slide-')) {
130                        intro.classList.remove(value);
131                    }
132                });
133                intro.classList.add(`slide-${index}`);
134                bgIntro.style.opacity = `1`;
135            }
136            introImg = false;
137            if (bgIntroImgs.length) {
138                bgIntroImgs.forEach(el => el.classList.remove('active'));
139                bgIntroImgs[index-1].classList.add('active');
140                introImg = bgIntroImgs[index-1];
141                if (introImg.classList.contains('hide-gradient')) {
142                    bgIntro.classList.add('hide-gradient');
143                }
144                else {
145                    bgIntro.classList.remove('hide-gradient');
146                }
147                if (introImg.classList.contains('cursor-pointer')) {
148                    bgIntro.classList.add('cursor-pointer');
149                }
150                else {
151                    bgIntro.classList.remove('cursor-pointer');
152                }
153            }
154            intro_inners.forEach(el => el.classList.remove('visible'));
155            intro_inners[index-1].classList.add('visible');
156            navigationSlides[index-1].classList.add('active');
157        }
158        
159        let id = setInterval(() => {
160            newSlide();
161        }, 5000);
162
163        let index = 1;
164        navigationSlides.forEach((navigationSlide, i) => {
165            navigationSlide.addEventListener('click', (event) => {
166                newSlide(i+1);
167                clearInterval(id);
168                introStartClick = false;
169            });
170        });
171
172        let intro_x;
173        intro.addEventListener('mousedown', (e) => {
174            intro_x = e.pageX;
175            introStartClick = true;
176        }, { passive: true });
177        intro.addEventListener('mouseup', (e) => {
178            if (e.pageX < (intro_x-100)) {
179                newSlide(index+1);
180                introStartClick = false;
181            } else if (e.pageX > (intro_x+100)) {
182                newSlide(index-1);
183                introStartClick = false;
184            }
185            clearInterval(id);
186        });
187        intro.querySelectorAll('.nav_hide, .intro_plus .nav, .navigation_slides, .navigation_slide').forEach((el) => {
188            el.addEventListener('click', (e) => {
189                introStartClick = false;
190            });
191        });
192        intro.querySelectorAll('.intro_plus .intro_inner').forEach((el) => {
193            el.addEventListener('click', (e) => {
194                introStartClick = false;
195            });
196        });
197        intro.addEventListener('click', (e) => {
198            if (introStartClick) {
199                const link = introImg.parentElement;
200                if (link && link.classList.contains('bg-img-wrap')) {
201                    link.click();
202                }
203            }
204        });
205        
206        intro.addEventListener('touchstart', (e) => {
207            intro_x = e.changedTouches[0].pageX;
208        }, { passive: true });
209        intro.addEventListener('touchend', (e) => {
210            if (e.changedTouches[0].pageX < (intro_x-100)) {
211                newSlide(index+1);
212                introStartClick = false;
213            } else if (e.changedTouches[0].pageX > (intro_x+100)) {
214                newSlide(index-1);
215                introStartClick = false;
216            }
217            clearInterval(id);
218        });
219    }
220
221    /* PICK UP */
222    
223    const pickupButtons = document.querySelectorAll('.pickup_button'),
224          pickupItemsContainer = document.querySelector('.pickup_items');
225    if (pickupButtons && pickupItemsContainer && pickupButtons.length) {
226        pickupItemsContainer.style.opacity = 1;
227        
228        pickupButtons.forEach((pickupButton, i) => {
229            pickupButton.addEventListener('click', () => {
230        
231                let id = pickupButton.dataset.id;
232            
233                pickupButtons.forEach((el, i) => {
234                    el.classList.remove('active');
235                })
236                pickupButton.classList.add('active');
237                pickupItemsContainer.style.opacity = 0;
238                setTimeout(() => {
239                    // Показываем только те элементы, у которых data-id содержит нужный id
240                    // (было: childs.hide() + childs.filter('[data-id*=id]').show()).
241                    qsa('[data-id]', pickupItemsContainer).forEach((el) => {
242                        const match = el.matches('[data-id*="' + id + '"]');
243                        el.style.display = match ? '' : 'none';
244                    });
245                }, 100)
246                
247                    
248                setTimeout(() => {
249                    pickupItemsContainer.style.opacity = 1;
250                }, 150) 
251            })
252        })
253    }
254    /* SCROLL PICKUP */
255    
256    let dragMove = false;
257    
258    function scrolling(scroll) {
259        let speed = 1; // Скорость скролла.
260        let left = 0; // отпустили мышку - сохраняем положение скролла
261        let drag = false;
262        let coorX = 0; // нажали мышку - сохраняем координаты.
263        
264        let timing = 0;
265        let intervalId;
266        scroll.addEventListener('mousedown', function(e) {
267            drag = true;
268            coorX = e.pageX - this.offsetLeft;
269            intervalId = setInterval(() => {
270                timing++;
271            }, 1)
272        }, { passive: true });
273        
274        document.addEventListener('mouseup', function(e) {
275            e.preventDefault();
276            drag = false;
277            left = scroll.scrollLeft;
278            clearInterval(intervalId);
279            setTimeout(() => {
280                dragMove = false;
281            }, 50);
282        //   let koef = (coorX-(e.pageX - scroll.offsetLeft))/timing;
283        //   let intervalId2 = setInterval(() => {
284        //     scroll.scrollLeft += 10*koef
285        //   }, 10)
286        
287        //   setTimeout(() => {
288        //     clearInterval(intervalId2);
289        //   }, koef*koef)
290            
291        });
292        scroll.addEventListener('mousemove', function(e) {
293          if (drag) {
294            // console.log('drag move on');
295            dragMove = true;
296            this.scrollLeft = left - (e.pageX - this.offsetLeft - coorX)*speed;
297          }
298        });
299    }
300
301    function scrollingLeftRight(scroll, arrowLeft, arrowRight, item) {
302        // помечаем стрелку классом disabled, когда сдвигаться в эту сторону уже некуда
303        // (в т.ч. когда контент влезает целиком — тогда обе стрелки неактивны)
304        function updateArrowsState() {
305            const max = scroll.scrollWidth - scroll.clientWidth;
306            const pos = scroll.scrollLeft;
307            // 1px запаса на дробные размеры при масштабировании
308            arrowLeft && arrowLeft.classList.toggle('disabled', pos <= 1);
309            arrowRight && arrowRight.classList.toggle('disabled', pos >= max - 1);
310        }
311
312        updateArrowsState();
313        scroll.addEventListener('scroll', updateArrowsState, {passive: true});
314        addEventListener('resize', updateArrowsState);
315        // картинки товаров догружаются и меняют scrollWidth
316        addEventListener('load', updateArrowsState);
317
318        arrowLeft && arrowLeft.addEventListener('click', () => {
319            if (arrowLeft.classList.contains('disabled')) {
320                return;
321            }
322            let width = item.getBoundingClientRect().width;
323            num = Math.round(scroll.scrollLeft/(width*10)*10)
324            scroll.scroll({
325                left: (num-1)*width,
326                top: 0,
327                behavior: 'smooth'
328            })
329            left = (num-1)*width;
330        });
331        arrowRight && arrowRight.addEventListener('click', () => {
332            if (arrowRight.classList.contains('disabled')) {
333                return;
334            }
335            let width = item.getBoundingClientRect().width;
336            num = Math.round(scroll.scrollLeft/(width*10)*10)
337            scroll.scroll({
338                left: (num+1)*width,
339                top: 0,
340                behavior: 'smooth'
341            })
342            left = (num+1)*width;
343        });
344    }
345    
346    const pickup_scroll = document.querySelector('.pickup_items_container');
347    if (pickup_scroll) {
348        scrolling(pickup_scroll);
349    }
350    const new_scroll = document.querySelector('.new_items');
351    if (new_scroll) {
352        scrolling(new_scroll);
353        scrollingLeftRight(
354            new_scroll,
355            new_scroll.parentElement.querySelector('.new_items_left_arrow'),
356            new_scroll.parentElement.querySelector('.new_items_right_arrow'),
357            new_scroll.querySelector('.new_item'),
358        );
359    }
360    const solution_examples_scroll = document.querySelector('.solution_small_examples');
361    if (solution_examples_scroll) {
362        scrolling(solution_examples_scroll);
363    }
364    
365    const newItems = document.querySelectorAll('.new_item');
366    newItems.forEach(newItem => {
367        newItem.addEventListener('click', (e) => {
368            if (dragMove) {
369                e.preventDefault();
370            }
371        })
372    })
373
374    const pickupItems = document.querySelectorAll('.pickup_item');
375    pickupItems.forEach(pickupItem => {
376        pickupItem.addEventListener('click', (e) => {
377            if (dragMove) {
378                e.preventDefault();
379            }
380        })
381    })
382
383    const solutionExamples = document.querySelectorAll('.solution_example');
384    solutionExamples.forEach(solutionExample => {
385        solutionExample.addEventListener('click', (e) => {
386            if (dragMove) {
387                e.preventDefault();
388            }
389        })
390    })
391    
392    /* ANIMATION ON SCROLL */
393    
394    const animItems = document.querySelectorAll('.anim-item');
395    
396    if (animItems.length > 0) {
397        window.addEventListener('scroll', animOnScroll, { passive: true });
398
399        let animTicking = false;
400        function animOnScroll() {
401            if (!animTicking) {
402                requestAnimationFrame(animOnScrollUpdating);
403                animTicking = true;
404            }
405        }
406
407        function animOnScrollUpdating() {
408            const scrollTop = window.scrollY || window.pageYOffset || document.documentElement.scrollTop;
409            for (let i = 0; i < animItems.length; i++) {
410                const animItem = animItems[i];
411                const animItemHeight = animItem.offsetHeight;
412                const animItemOffset = offset(animItem).top;
413                const animStart = 4;
414    
415                let animItemPoint = window.innerHeight - animItemHeight / animStart;
416                if (animItemHeight > window.innerHeight) {
417                    animItemPoint = window.innerHeight - window.innerHeight / animStart;
418                }
419    
420                if ((scrollTop > animItemOffset - animItemPoint) && scrollTop < (animItemOffset + animItemHeight)) {
421                    animItem.classList.remove('_active');
422                }
423            }
424            animTicking = false;
425        }
426        
427        function offset(el) {
428            var rect = el.getBoundingClientRect(),
429            scrollLeft = window.scrollX || window.pageXOffset || document.documentElement.scrollLeft,
430            scrollTop = window.scrollY || window.pageYOffset || document.documentElement.scrollTop;
431            return { top: rect.top + scrollTop, left: rect.left + scrollLeft }
432        }
433    
434        setTimeout(() => {
435            animOnScroll();
436        }, 300);
437        
438    }
439    
440    /* POPUP */
441    const popup_nav = document.querySelector('.popup_nav'),
442            popup_nav_button = document.querySelector('.nav-toggle_popup'),
443            nav_below = document.querySelector('.nav-with-below'),
444            nav_button = document.querySelector('.nav-toggle-wrap'),
445            popup_nav_back = document.querySelector('.popup_nav_back'),
446            lower_nav = document.querySelector('.lower_nav'),
447            popup_intro_gift = document.querySelector('.popup_intro-gift')
448            popup_intro_gift_button = document.querySelector('.intro-gift__btn'),
449            popup_intro_gift_back = document.querySelector('.popup_intro-gift_back');
450    
451    popup_nav_button && popup_nav_button.addEventListener('click', () => {
452        
453        popup_nav.classList.add('active');
454        document.body.style.overflow = 'hidden';
455        lower_nav.style.display = "none";
456    });
457
458    nav_button && nav_button.addEventListener('click', () => {
459        if (!nav_button.classList.contains('active')) {
460            nav_button.classList.add('active');
461            nav_below.classList.add('has-active');
462        }
463        else {
464            nav_button.classList.remove('active');
465            nav_below.classList.remove('has-active');
466        }
467    });
468    
469    popup_nav_back.addEventListener('click', () => {
470        
471        popup_nav.classList.remove('active');
472        document.body.style.overflow = 'visible';
473        lower_nav.style.display = "";
474    }); 
475    
476    popup_intro_gift_button && popup_intro_gift_button.addEventListener('click', () => {
477        
478        popup_intro_gift.classList.add('active');
479        document.body.style.overflow = 'hidden';
480        lower_nav.style.display = "none";
481    });
482
483    popup_intro_gift_back && popup_intro_gift_back.addEventListener('click', () => {
484        
485        popup_intro_gift.classList.remove('active');
486        document.body.style.overflow = 'visible';
487        lower_nav.style.display = "";
488    });
489    
490    /* INTERIOR_FILTER */
491    on(document, 'click', '.interior_button', function() {
492        const wasActive = this.classList.contains('active');
493
494        // Открыт может быть только один фильтр - гасим все, потом при необходимости включаем свой.
495        qsa('.interior_button').forEach((el) => {
496            el.classList.remove('active');
497        });
498
499        if (!wasActive) {
500            this.classList.add('active');
501        }
502    });
503
504    /*FILTER */
505    on(document, 'click', '.interior_filter_content_title', function() {
506        const content = this.closest('.interior_filter_content');
507        if (!content) {
508            return;
509        }
510
511        const text = qs('.interior_filter_content_text', content);
512        const svg = qs('.interior_filter_content_svg', content);
513        if (!text) {
514            return;
515        }
516
517        const opened = text.classList.toggle('hidden') === false;
518        if (svg) {
519            svg.classList.toggle('active', opened);
520        }
521    });
522
523    /* FAQ */
524    const faq_items = document.querySelectorAll('.faq_item');
525    if (faq_items && faq_items.length) {
526        faq_items.forEach(faq_item => {
527            faq_item.addEventListener('click', () => {
528    
529                if (faq_item.classList.contains('active')) {
530                    faq_item.classList.remove('active');
531                } else {
532                    faq_item.classList.add('active');
533                }
534                
535            })
536        })
537    }
538
539    let popup_filter_active = false;
540
541    on(document, 'click', '.catalog_cards_settings_under .filter_button_popup', function() {
542        const popup_filter = qs('.popup_filter');
543
544        popup_filter.classList.add('active');
545        document.body.style.overflow = 'hidden';
546        lower_nav.style.display = "none";
547        popup_filter_active = true;
548    });
549    function close_popup_filter () {
550        const popup_filter = document.querySelector('.popup_filter');
551
552        popup_filter.classList.remove('active');
553        document.body.style.overflow = 'visible';
554        lower_nav.style.display = "";
555        popup_filter_active = false;
556    }
557    on(document, 'click', '.catalog_vertical_filter .popup_filter_back', close_popup_filter);
558
559    // filter_applied шлёт commonCatalog_new.js нативным CustomEvent с bubbles: true,
560    // поэтому делегирование от document его ловит.
561    on(document, 'filter_applied', '.catalog_vertical_filter #b-filter', function() {
562        close_popup_filter();
563    });
564
565
566    window.addEventListener('resize', () => {
567        if (popup_filter_active) {
568            close_popup_filter();
569        }
570    })
571});
572
573ready(function() {
574    const comprehensiveSolutions_items_left_arrow = document.querySelector('.comprehensiveSolutions_items_left_arrow');
575    const comprehensiveSolutions_items_right_arrow = document.querySelector('.comprehensiveSolutions_items_right_arrow');
576    const comprehensiveSolutions_items = document.querySelector('.comprehensiveSolutions_items');
577    const comprehensiveSolutions_item = document.querySelector('.comprehensiveSolutions_item');
578    if (!comprehensiveSolutions_items) {
579        return;
580    }
581
582    let left = 0;
583    let last_left = false;
584    comprehensiveSolutions_items_right_arrow.addEventListener('click', () => {
585        // после перетаскивания мышью left не совпадает с реальной прокруткой
586        left = comprehensiveSolutions_items.scrollLeft;
587        let rect = comprehensiveSolutions_item.getBoundingClientRect();
588        let width = rect.width + 20;
589        // Ограничение на скролирование право
590        if (last_left === false) {
591            last_left = comprehensiveSolutions_items.scrollWidth - comprehensiveSolutions_items.getBoundingClientRect().width;
592        }
593        // Если впаво невозможно скролировать, то не надо этого делать
594        if (last_left !== false && (left >= last_left)) {
595            left = last_left;
596            return;
597        }
598        left += width;
599        
600        comprehensiveSolutions_items.scrollTo({
601            top: 0,
602            left: left,
603            behavior: 'smooth'
604        });
605    })
606
607    comprehensiveSolutions_items_left_arrow.addEventListener('click', () => {
608        left = comprehensiveSolutions_items.scrollLeft;
609        let rect = comprehensiveSolutions_item.getBoundingClientRect();
610        let width = rect.width + 20;
611        left -= width
612        left = left < 0 ? 0 : left;
613        comprehensiveSolutions_items.scrollTo({
614            top: 0,
615            left: left,
616            behavior: 'smooth'
617        });
618        last_left = false;
619    })
620
621    window.addEventListener('resize', () => {
622        last_left = false;
623    })
624});
625
626// Перетаскивание .comprehensiveSolutions_items мышью (тач и трекпад скроллят нативно).
627// Делегируем на document: слайдеров на странице может быть несколько.
628ready(function() {
629    var DRAG_THRESHOLD = 5; // пока не сдвинули на столько px - это ещё клик, а не перетаскивание
630    var drag = null;
631    var suppressClick = false;
632
633    function markDraggable() {
634        qsa('.comprehensiveSolutions_items').forEach(function(el) {
635            el.classList.toggle('comprehensiveSolutions_items--draggable', el.scrollWidth - el.clientWidth > 1);
636        });
637    }
638
639    document.addEventListener('mousedown', function(e) {
640        if (e.button !== 0 || !e.target.closest) {
641            return;
642        }
643        var el = e.target.closest('.comprehensiveSolutions_items');
644        if (!el || el.scrollWidth - el.clientWidth <= 1) {
645            return;
646        }
647        drag = {el: el, startX: e.pageX, startScroll: el.scrollLeft, moved: false};
648        // иначе браузер начнёт своё drag&drop картинки или ссылки
649        e.preventDefault();
650    });
651
652    document.addEventListener('mousemove', function(e) {
653        if (!drag) {
654            return;
655        }
656        var dx = e.pageX - drag.startX;
657        if (!drag.moved) {
658            if (Math.abs(dx) < DRAG_THRESHOLD) {
659                return;
660            }
661            drag.moved = true;
662            drag.el.classList.add('comprehensiveSolutions_items--dragging');
663        }
664        drag.el.scrollLeft = drag.startScroll - dx;
665    });
666
667    document.addEventListener('mouseup', function() {
668        if (!drag) {
669            return;
670        }
671        if (drag.moved) {
672            drag.el.classList.remove('comprehensiveSolutions_items--dragging');
673            // click прилетит сразу после mouseup - гасим его, чтобы не уйти по ссылке
674            suppressClick = true;
675        }
676        drag = null;
677    });
678
679    document.addEventListener('click', function(e) {
680        if (!suppressClick) {
681            return;
682        }
683        suppressClick = false;
684        e.preventDefault();
685        e.stopPropagation();
686    }, true);
687
688    markDraggable();
689    window.addEventListener('resize', markDraggable);
690    window.addEventListener('load', markDraggable);
691});
692
693ready(function() {
694    // Делегируем на document: подвал может перерисовываться (динамические области композита).
695    on(document, 'click', '.footer_title', function() {
696        const svg = qs('.footer_title_svg', this);
697        const next = this.nextElementSibling;
698        if (!svg) {
699            return;
700        }
701
702        const opened = svg.classList.toggle('active');
703        if (next && next.classList.contains('footer_item_text')) {
704            next.classList.toggle('hidden', !opened);
705        }
706    });
707});
708
709ready(function() {
710    // fixed
711    const nav = document.querySelector('.nav');
712    const leftMenu = document.querySelector('.left-menu_fixed');
713
714    function requestAnimationWrapper(callback) {
715        let ticking = false;
716
717        function nextTick() {
718            callback();
719            ticking = false;
720        }
721
722        function requestTick() {
723            if (!ticking) {
724                requestAnimationFrame(nextTick);
725                ticking = true;
726            }
727        }
728        
729        return requestTick;
730    }
731
732    function fixNav() {
733        const scrollTop = window.scrollY || window.pageYOffset || document.documentElement.scrollTop;
734        const innerHeight = window.innerHeight;
735        if (scrollTop > innerHeight) {
736            nav.classList.add('fixed');
737        } else {
738            nav.classList.remove('fixed');
739        }
740    }
741
742    function fixLeftMenu() {
743        const scrollTop = window.scrollY || window.pageYOffset || document.documentElement.scrollTop;
744        const innerHeight = window.innerHeight;
745        const parentTop = leftMenu.parentNode.offsetTop;
746        const maxTop = Math.max(innerHeight, parentTop);
747
748        if (scrollTop > maxTop) {
749            leftMenu.classList.add('fixed');
750        } else {
751            leftMenu && leftMenu.classList.remove('fixed');
752        }
753    }
754
755    function fixLeftMenuSize() {
756        const leftMenuWidth = leftMenu.offsetWidth;
757        leftMenu.style.setProperty('--left-menu-width', `${leftMenuWidth}px`);
758    }
759
760    const optimizedFixNav = requestAnimationWrapper(fixNav);
761    window.fixNav = optimizedFixNav;
762    window.addEventListener('scroll', optimizedFixNav, { passive: true });
763    optimizedFixNav();
764    if (leftMenu) {
765        const optimizedFixLeftMenu = requestAnimationWrapper(fixLeftMenu);
766        const optimizedFixLeftMenuSize = requestAnimationWrapper(fixLeftMenuSize);
767        window.addEventListener('scroll', optimizedFixLeftMenu, { passive: true });
768        window.addEventListener('resize', optimizedFixLeftMenuSize);
769        optimizedFixLeftMenu();
770        optimizedFixLeftMenuSize();
771    }
772
773    setTimeout(function () {
774        optimizedFixNav();
775        nav.classList.remove('_active');
776    }, 1500);
777});
778
779ready(function() {
780    function collapseAll() {
781        qsa('.expandable-btn[aria-expanded=true]').forEach(function(btn
781) {
782            btn.setAttribute('aria-expanded', 'false');
783        });
784    }
785
786    on(document, 'click', '.expandable-btn', function() {
787        const wasOpen = this.getAttribute('aria-expanded') === 'true';
788        if (wasOpen) {
789            this.setAttribute('aria-expanded', 'false');
790            return;
791        }
792        collapseAll();
793        this.setAttribute('aria-expanded', 'true');
794    });
795
796    on(document, 'click', '.expandable-btn-sibling', function() {
797        const btn = this.parentElement && qs(':scope > .expandable-btn', this.parentElement);
798        if (btn) {
799            btn.click();
800        }
801    });
802
803    on(document, 'click', '.close-expandable-btn', collapseAll);
804});
805
806ready(function() {
807    const popup_city = qs('.popup_city');
808    const lower_nav = qs('.lower_nav');
809
810    function showCityPopup() {
811        qsa('.popup.active').forEach(function(popup) {
812            popup.classList.remove('active');
813        });
814        popup_city.classList.add('active');
815        document.body.style.overflow = 'hidden';
816        if (lower_nav) {
817            lower_nav.style.display = 'none';
818        }
819    }
820
821    function hideCityPopup() {
822        popup_city.classList.remove('active');
823        document.body.style.overflow = 'visible';
824        if (lower_nav) {
825            lower_nav.style.display = '';
826        }
827    }
828
829    // Делегируем: кнопка города живёт в динамической области композита и перерисовывается,
830    // прямая подписка после подстановки динамики отвалилась бы.
831    on(document, 'click', '[data-popup="city"], .js-change-city', function(e) {
832        e.preventDefault();
833
834        const replacer = qs('.popup-city-replacer');
835        if (!replacer) {
836            showCityPopup();
837            return;
838        }
839
840        // $.get + $replacer.replaceWith(html)
841        fetch(this.dataset.href, {credentials: 'same-origin'})
842            .then(function(response) {
843                return response.text();
844            })
845            .then(function(html) {
846                replacer.outerHTML = html;
847                showCityPopup();
848            });
849    });
850
851    on(document, 'click', '.popup_city_back', function(e) {
852        e.preventDefault();
853        hideCityPopup();
854    });
855
856    on(document, 'click', '.popup_city .city-list-link', function() {
857        BX.setCookie('BITRIX_SM_SELECT_CITY', '1', {path: '/', domain: '.portaprima.ru', expires: 86400});
858    });
859
860    // Функция обратного геокодирования (координаты -> адрес)
861    function getAddressByCoords(lat, lon) {
862        const apiKey = window.yandexMapApiKey || '';
863        const url = `https://geocode-maps.yandex.ru/1.x/?apikey=${apiKey}&geocode=${lon},${lat}&format=json&results=1`;
864        
865        fetch(url)
866            .then(response => response.json())
867            .then(data => {
868                const geoObject = data.response.GeoObjectCollection.featureMember[0].GeoObject;
869                const address = geoObject.metaDataProperty.GeocoderMetaData.Address;
870                
871                // Извлекаем компоненты адреса
872                const components = address.Components;
873                let city = '';
874                let province = '';
875                let region = '';
876                let country = '';
877                
878                components.forEach(component => {
879                    switch(component.kind) {
880                    case 'locality': // Город
881                        city = component.name;
882                        break;
883                    case 'province': // Область/регион
884                        if (region) {
885                            province = region;
886                        }
887                        region = component.name;
888                        break;
889                    case 'country': // Страна
890                        country = component.name;
891                        break;
892                    }
893                });
894                
895                // Полный адрес
896                const fullAddress = geoObject.metaDataProperty.GeocoderMetaData.text;
897                
898                // Возвращаем результат
899                const locationData = {
900                    country: country,
901                    region: region,
902                    province: province,
903                    city: city,
904                    fullAddress: fullAddress,
905                    coordinates: {
906                        lat: lat,
907                        lon: lon
908                    }
909                };
910                
911                onLocationDetected(locationData);
912            })
913            .catch(error => {
914                // console.error('Ошибка геокодирования:', error);
915            });
916    }
917
918    function isUserInStPetersburg(locationData) {
919        const city = locationData.city ? locationData.city.toLowerCase() : '';
920        const region = locationData.region ? locationData.region.toLowerCase() : '';
921        const province = locationData.province ? locationData.province.toLowerCase() : '';
922        
923        const spbVariants = [
924            'санкт-петербург',
925            'saint petersburg',
926            'st petersburg',
927            'petersburg',
928            'петербург',
929            'спб',
930            'ленинград',
931            'leningrad',
932
933            'северо-западный федеральный округ',
934            'северо-западный',
935        ];
936        
937        const isCityMatch = spbVariants.some(variant => 
938            city.includes(variant)
939        );
940        
941        const isRegionMatch = spbVariants.some(variant => 
942            region.includes(variant)
943        );
944
945        const isProvinceMatch = spbVariants.some(variant => 
946            province.includes(variant)
947        );
948        
949        return isCityMatch || isRegionMatch || isProvinceMatch || !!window.siteNeedDetectRegionAsSbp;
950    }
951
952    // Сохранение результата в localStorage на 24 часа
953    function onLocationDetected(locationData, saveInStorage) {
954        if (saveInStorage === undefined) {
955            saveInStorage = true;
956        }
957
958        // Сохраняем с временной меткой
959        const cacheData = {
960            location: locationData,
961            timestamp: Date.now()
962        };
963        
964        if (saveInStorage) {
965            localStorage.setItem('userLocation', JSON.stringify(cacheData));
966        }
967        var detectSpb = BX.getCookie('BITRIX_SM_NAV_DETECT_SPB');
968        if (!detectSpb) {
969            const detectSpb = isUserInStPetersburg(locationData) && 'Y' || 'N';
970            if (detectSpb == 'Y') {
971            }
972            BX.setCookie('BITRIX_SM_NAV_DETECT_SPB', detectSpb, {path: '/', domain: '.portaprima.ru', expires: 86400});
973        }
974        markDetect();
975        if (detectSpb && (detectSpb == 'Y')) {
976            markDetect(true);
977        }
978        if (saveInStorage) {
979            location.reload();
980        }
981    }
982
983    // Определение местоположения пользователя
984    function detectUserLocation() {
985        // Проверка кеша
986        const cached = localStorage.getItem('userLocation');
987        if (cached) {
988            const cacheData = JSON.parse(cached);
989            const cacheAge = Date.now() - cacheData.timestamp;
990            const oneDayInMs = 7 * 24 * 60 * 60 * 1000;
991            
992            // Если кеш свежий (менее 24 часов)
993            if (cacheAge < oneDayInMs) {
994                onLocationDetected(cacheData.location, false);
995                return;
996            }
997        }
998        
999        // Проверяем поддержку геолокации
1000        if (!navigator.geolocation) {
1001            // console.error('Геолокация не поддерживается вашим браузером');
1002            return;
1003        }
1004
1005        // Получаем координаты пользователя
1006        navigator.geolocation.getCurrentPosition(
1007            function(position) {
1008                const latitude = position.coords.latitude;
1009                const longitude = position.coords.longitude;
1010                
1011                // Обратное геокодирование через API Яндекс.Карт
1012                getAddressByCoords(latitude, longitude);
1013            },
1014            function(error) {
1015                // console.error('Ошибка получения геолокации:', error.message);
1016                if (!!window.siteNeedDetectRegionAsSbp) {
1017                    BX.setCookie('BITRIX_SM_NAV_DETECT_SPB', 'Y', {path: '/', domain: '.portaprima.ru', expires: 86400});
1018                    markDetect(true);
1019                    location.reload();
1020                }
1021            }
1022        );
1023    }
1024
1025    function markDetect(active) {
1026        document.body.classList.add('mark-location');
1027        if (active) {
1028            document.body.classList.add('mark-location-active');
1029        }
1030    }
1031
1032    if (window['siteNeedDetectRegion']) {
1033        detectUserLocation();
1034    }
1035});
1036
1037(function(params) {
1038    let lastKnownScrollPosition = 0;
1039    let ticking = false;
1040    let fixedNav;
1041
1042    function onScroll(position) {
1043        if (position > 70) {
1044            if (fixedNav !== true) {
1045                qsa('.nav_hide').forEach(function(el) { el.classList.add('fixed'); });
1046                fixedNav = true;
1047            }
1048        }
1049        else {
1050            if (fixedNav !== false) {
1051                qsa('.nav_hide').forEach(function(el) { el.classList.remove('fixed'); });
1052                fixedNav = false;
1053            }
1054        }
1055    }
1056
1057    document.addEventListener("scroll", (event) => {
1058        lastKnownScrollPosition = window.scrollY;
1059      
1060        if (!ticking) {
1061          window.requestAnimationFrame(() => {
1062            onScroll(lastKnownScrollPosition);
1063            ticking = false;
1064          });
1065      
1066          ticking = true;
1067        }
1068    });
1069    onScroll(window.scrollY);
1070
1071    let links = [];
1072    document.querySelectorAll('.nav_link').forEach(link => {
1073        if (link.parentElement.classList.contains('ext')) {
1074            // links.push(link);
1075            links.push(link.parentElement);
1076        }
1077    });
1078    let linkTimeout;
1079    function clearLinkTimeout() {
1080        if (linkTimeout) {
1081            clearTimeout(linkTimeout);
1082            linkTimeout = null;
1083        }
1084    }
1085    links.forEach(link => {
1086        // const parent = link.parentElement;
1087        const parent = link;
1088        parent.addEventListener('mouseenter', (e) => {
1089            links.forEach(_link => {
1090                _link.classList.remove('hover');    
1091            })
1092            clearLinkTimeout();
1093            parent.classList.add('hover');
1094        });
1095        parent.addEventListener('mouseleave', (e) => {
1096            clearLinkTimeout();
1097            linkTimeout = setTimeout(() => {
1098                parent.classList.remove('hover');
1099                linkTimeout = null;
1100            }, 1000);
1101        });
1102    })
1103
1104    // Удаление отложенной загрузки - из смещения картинки она не загружется иногда
1105    document.querySelectorAll('.advantages_partitions_img_container').forEach(container => {
1106        container.querySelectorAll('img').forEach(img => {
1107            img.loading = 'auto';
1108        });
1109    })
1110})();
1111
1112ready(function() {
1113    var links = document.querySelectorAll('[data-messenger-replace-link]');
1114    var groupedData = {};
1115    links.forEach((node) => {
1116        const selector = node.getAttribute('data-messenger-replace-selector');
1117        const link = node.getAttribute('data-messenger-replace-link');
1118        if (!groupedData[selector]) {
1119            groupedData[selector] = {};
1120        }
1121        groupedData[selector][link] = true;
1122    })
1123
1124    const result = {};
1125    for (const selector in groupedData) {
1126        var links = [];
1127        for (const link in groupedData[selector]) {
1128            links.push(link);
1129        }
1130        result[selector] = links;
1131    }
1132
1133    function fixMessengerLinks(replaceLinks, targetSelector) {
1134        document.addEventListener('click', function(event) {
1135            var link = event.target;
1136            if (!link || !link.nodeName) {
1137				return;
1138			}
1139            var i = 20;
1140            var breakTags = ['a', 'A', 'body', 'BODY'];
1141            var linkTags = ['a', 'A'];
1142            while(link && i) {
1143                if (breakTags.indexOf(link.nodeName) !== -1) {
1144                    break;
1145                }
1146                link = link.parentNode;
1147                i += 1;
1148            }
1149            if (link && linkTags.indexOf(link.nodeName) !== -1) {
1150                if (replaceLinks && replaceLinks.length && (replaceLinks.indexOf(link.href) !== -1)) {
1151                    var target = document.querySelector(targetSelector);
1152                    if (target) {
1153                        event.preventDefault();
1154                        target.click();
1155                        return false;
1156                    }
1157                }
1158            }
1159        });
1160    }
1161
1162    for (const selector in result) {
1163        var links = result[selector];
1164        fixMessengerLinks(links, selector);
1165    }
1166});
1167
1168ready(function() {
1169	// go to anchor animation
1170	on(document, 'click', 'a.js-smooth-scroll', function(e) {
1171		if (window.location.pathname !== this.pathname) {
1172			return;
1173		}
1174
1175		const target = qs(this.getAttribute('href'));
1176		if (!target) {
1177			return;
1178		}
1179		e.preventDefault();
1180
1181		// $('html, body').animate({scrollTop: ...}, 500) -> нативная плавная прокрутка
1182		window.scrollTo({
1183			top: target.getBoundingClientRect().top + window.pageYOffset - 100,
1184			behavior: 'smooth'
1185		});
1186	});
1187});
1188
1189ready(function() {
1190    const upBtn = qs('.up-button');
1191    if (!upBtn) {
1192        return;
1193    }
1194
1195    on(upBtn, 'click', function(e) {
1196        e.preventDefault();
1197        window.scrollTo({top: 0, behavior: 'smooth'});
1198    });
1199
1200    function updateUpBtn() {
1201        const scrollTop = window.pageYOffset;
1202        const pageOffset = scrollTop + window.innerHeight;
1203        const footer = qs('footer') || qs('.footer');
1204        const footerOffset = footer
1205            ? footer.getBoundingClientRect().top + scrollTop
1206            : document.documentElement.scrollHeight;
1207
1208        upBtn.classList.toggle('hide', scrollTop < 200);
1209        upBtn.classList.toggle('sticky', pageOffset > footerOffset);
1210    }
1211
1212    // scroll срабатывает часто - слушаем пассивно, чтобы не блокировать прокрутку
1213    window.addEventListener('scroll', updateUpBtn, {passive: true});
1214    updateUpBtn();
1215});
1216
1217ready(function() {
1218	var scrolled = false;
1219	function scrollToH1() {
1220		if (scrolled) {
1221			return;
1222		}
1223		if (window.BX && BX.getCookie('scrollH1OnNextPage')) {
1224			scrolled = true;
1225			const h1 = qs('h1');
1226			if (h1 && (window.innerWidth < 1024)) {
1227				window.scrollTo({
1228					top: h1.getBoundingClientRect().top + window.pageYOffset - 200,
1229					behavior: 'smooth'
1230				});
1231			}
1232		}
1233	}
1234    scrollToH1();
1235	const times = [1000, 2000, 5000, 10000];
1236	for (let i = 0; i < times.length; i++) {
1237		setTimeout(() => {
1238			scrollToH1();
1239		}, times[i]);
1240	}
1241
1242    function rememberScroll() {
1243        BX.setCookie('scrollH1OnNextPage', 1, {expires: 10*1, path: '/'});
1244    }
1245    on(document, 'click', '.scroll-h1-on-next-page a', rememberScroll);
1246    on(document, 'mouseup', '.scroll-h1-on-next-page a', rememberScroll);
1247});
1248
1249function updateCatalogBasketIn() {
1250    // Пустой список - не повод выходить: тогда с карточек надо СНЯТЬ подсветку
1251    // (товар удалили из корзины; при композите ready отрабатывает на заглушке).
1252    var basketItems = window.currentBasketItems || [];
1253
1254    function checkItemExists(basketItems, id, xmlId) {
1255        for (let item of basketItems) {
1256            if (item.PRODUCT_ID === id || item.PRODUCT_XML_ID === xmlId) {
1257                return true;
1258            }
1259        }
1260        return false;
1261    }
1262    
1263    qsa('.catalog_card').forEach(function(card) {
1264        const id = card.dataset.layerOfferId;
1265        const xmlId = card.dataset.layerXmlid;
1266
1267        card.classList.toggle('in_basket', checkItemExists(basketItems, id, xmlId));
1268    });
1269}
1270ready(function() {
1271    updateCatalogBasketIn();
1272
1273    function setZoomContent(node, map) {
1274        // map: селектор внутри попапа -> значение. Пустое значение очищает блок.
1275        Object.keys(map).forEach(function(selector) {
1276            const el = qs('.popup_zoom ' + selector);
1277            if (el) {
1278                el.innerHTML = map[selector] || '';
1279            }
1280        });
1281    }
1282
1283    on(document, 'click', '.catalog_cards_container .zoom', function(e) {
1284        e.preventDefault();
1285
1286        const img = this.dataset.href;
1287        const title = this.dataset.title;
1288
1289        const imgEl = qs('.popup_zoom .popup_zoom_img img');
1290        if (img && imgEl) {
1291            imgEl.setAttribute('src', img);
1292        }
1293        if (title) {
1294            setZoomContent(this, {'.popup_zoom_ontitle': title});
1295        }
1296
1297        fire(qs('.popup_zoom'), 'open');
1298    });
1299
1300    on(document, 'click', '.js-fasad-zoom', function(e) {
1301        e.preventDefault();
1302
1303        const img = this.dataset.img;
1304        const textEl = qs('.js-text', this);
1305        const colorsEl = qs('.js-colors', this);
1306
1307        const imgEl = qs('.popup_zoom .popup_zoom_img img');
1308        if (img && imgEl) {
1309            imgEl.setAttribute('src', img);
1310        }
1311
1312        setZoomContent(this, {
1313            '.popup_zoom_ontitle': this.dataset.title,
1314            '.popup_zoom_text': textEl ? textEl.innerHTML : '',
1315            '.popup_zoom_colors': colorsEl ? colorsEl.innerHTML : '',
1316        });
1317
1318        // Было $('.popup_zoom').data('id', id) - jQuery клал это во внутреннее хранилище,
1319        // а не в DOM. Читалось только здесь же, поэтому переносим в data-атрибут.
1320        const popup = qs('.popup_zoom');
1321        if (popup) {
1322            popup.dataset.id = this.dataset.zoom;
1323        }
1324
1325        fire(popup, 'open');
1326    });
1327
1328    on(document, 'click', '.popup_zoom_back', function() {
1329        fire(qs('.popup_zoom'), 'close');
1330    });
1331
1332    on(document, 'open', '.popup_zoom', function() {
1333        const lower_nav = qs('.lower_nav');
1334
1335        this.classList.add('active');
1336        document.body.style.overflow = 'hidden';
1337        if (lower_nav) {
1338            lower_nav.style.display = 'none';
1339        }
1340    });
1341
1342    on(document, 'close', '.popup_zoom', function() {
1343        const lower_nav = qs('.lower_nav');
1344
1345        this.classList.remove('active');
1346        document.body.style.overflow = 'visible';
1347        if (lower_nav) {
1348            lower_nav.style.display = '';
1349        }
1350    });
1351
1352    // Стрелки листают фасады по кругу: с первого влево -> на последний, и наоборот.
1353    function stepFasad(arrow, dir) {
1354        const popup = arrow.closest('.popup_zoom');
1355        const current = popup && qs('.js-fasad-zoom[data-zoom="' + popup.dataset.id + '"]');
1356        if (!current) {
1357            return;
1358        }
1359
1360        let next = dir < 0 ? current.previousElementSibling : current.nextElementSibling;
1361        if (!next) {
1362            // Соседа в нужную сторону нет - уходим в противоположный конец списка.
1363            const all = qsa('.js-fasad-zoom', current.parentElement);
1364            next = dir < 0 ? all[all.length - 1] : all[0];
1365        }
1366        if (next && next !== current) {
1367            next.click();
1368        }
1369    }
1370
1371    on(document, 'click', '.popup_zoom_nav-arrow_left', function() {
1372        stepFasad(this, -1);
1373    });
1374    on(document, 'click', '.popup_zoom_nav-arrow_right', function() {
1375        stepFasad(this, 1);
1376    });
1377});
1378
1379ready(function() {
1380    const catalog_cards = document.querySelectorAll('.catalog_card');
1381
1382    if (!catalog_cards.length) {
1383        return;
1384    }
1385
1386    function whatSlide(kord, width, quant) {
1387        let part = width/quant
1388
1389        if (Math.floor(kord/part) >= 0 && Math.floor(kord/part) <= quant) {
1390            return Math.floor(kord/part)
1391        } else {
1392            return 0;
1393        }
1394        
1395    }
1396
1397    function removeLazy(card, slides) {
1398        if (card.dataset.skip_lazy) {
1399            return;
1400        }
1401        card.dataset.skip_lazy = true;
1402        slides.forEach(slide => {
1403            slide.removeAttribute('loading');
1404            // slide.loading = 'eager';
1405            const src = slide.src;
1406            slide.src = '';
1407            slide.src = src;
1408        })
1409        catalog_cards.forEach(catalog_card => {
1410            if (catalog_card.dataset.skip_lazy) {
1411                return;
1412            }
1413            catalog_card.dataset.skip_lazy = true;
1414            let catalog_slides = catalog_card.querySelectorAll('.catalog_card_slide')
1415            if (!catalog_slides.length) {
1416                return;
1417            }
1418            catalog_slides.forEach(slide => {
1419                slide.removeAttribute('loading');
1420                // slide.loading = 'eager';
1421                const src = slide.src;
1422                slide.src = '';
1423                slide.src = src;
1424            })
1425        })
1426    }
1427
1428    if (window.innerWidth > 650) {
1429
1430        catalog_cards.forEach(catalog_card => {
1431        
1432            let catalog_slides = catalog_card.querySelectorAll('.catalog_card_slide')
1433            let quant = catalog_slides.length
1434            if (!quant) {
1435                return;
1436            }
1437            let catalog_dots = catalog_card.querySelectorAll('.catalog_card_slider_dot')
1438            let width = catalog_card.getBoundingClientRect().width
1439        
1440            catalog_card.addEventListener('mousemove', (e) => {
1441                removeLazy(catalog_card, catalog_slides);
1442                let kord = e.clientX - catalog_card.getBoundingClientRect().left
1443        
1444                let index = whatSlide(kord, width, quant)
1445                if (index+1) {
1446                    catalog_slides.forEach(el => el.classList.remove('active'))
1447                    catalog_dots.forEach(el => el.classList.remove('active'))
1448                    
1449                    if (index < catalog_slides.length) {
1450                        catalog_slides[index].classList.add('active')
1451                        catalog_dots[index].classList.add('active')
1452                    }
1453                    else {
1454                        catalog_slides[catalog_slides.length-1].classList.add('active')
1455                        catalog_dots[catalog_slides.length-1].classList.add('active')
1456                    }
1457                }
1458            })
1459        
1460            catalog_card.addEventListener('mouseleave', (e) => {
1461                catalog_slides.forEach(el => el.classList.remove('active'))
1462                catalog_dots.forEach(el => el.classList.remove('active'))
1463        
1464                catalog_slides[0].classList.add('active')
1465                catalog_dots[0].classList.add('active')
1466            })
1467        })
1468        
1469    } else {
1470
1471        function getIndex(slides) {
1472            let index = 0
1473            slides.forEach((slide, i) => {
1474                if (slide.classList.contains('active')) {
1475                    index = i
1476                } 
1477            })
1478
1479            return index
1480        }
1481        
1482        catalog_cards.forEach(catalog_card => {
1483            
1484            let catalog_slides = catalog_card.querySelectorAll('.catalog_card_slide')
1485            let quant = catalog_slides.length
1486            if (!quant) {
1487                return;
1488            }
1489            let catalog_dots = catalog_card.querySelectorAll('.catalog_card_slider_dot')
1490            let startX, startY;
1491            let threshold = 50; // Минимальное расстояние для свайпа
1492
1493            catalog_card.addEventListener('touchstart', function(e) {
1494                startX = e.touches[0].clientX;
1495                startY = e.touches[0].clientY;
1496            });
1497
1498
1499            catalog_card.addEventListener('touchmove', function(e) {
1500                let endX = e.changedTouches[0].clientX;
1501                let endY = e.changedTouches[0].clientY;
1502
1503                let xDiff = startX - endX;
1504                let yDiff = startY - endY;
1505                if (Math.abs(xDiff) > Math.abs(yDiff)) { 
1506                    e.preventDefault();
1507                }
1508            });
1509            catalog_card.addEventListener('touchend', function(e) {
1510                
1511                let endX = e.changedTouches[0].clientX;
1512                let endY = e.changedTouches[0].clientY;
1513
1514                let xDiff = startX - endX;
1515                let yDiff = startY - endY;
1516
1517                if (Math.abs(xDiff) > Math.abs(yDiff)) { 
1518                    let index = getIndex(catalog_slides)
1519                    removeLazy(catalog_card, catalog_slides);
1520                
1521                    if (xDiff > threshold && index < quant-1) {
1522                        catalog_slides.forEach(el => el.classList.remove('active'))
1523                        catalog_dots.forEach(el => el.classList.remove('active'))
1524                        catalog_slides[index+1].classList.add('active')
1525                        catalog_dots[index+1].classList.add('active')
1526                    } else if (xDiff < -threshold && index > 0) {
1527                        catalog_slides.forEach(el => el.classList.remove('active'))
1528                        catalog_dots.forEach(el => el.classList.remove('active'))
1529                        catalog_slides[index-1].classList.add('active')
1530                        catalog_dots[index-1].classList.add('active')
1531                    }
1532                } 
1533            });
1534        })
1535    }
1536});
1537
1538// Ссылки, скрытые от ботов: <span class="hidden-link-class" data-link="..."> -> <a href="...">
1539function replaceHiddenLink () {
1540    qsa('.hidden-link-class').forEach(function(node) {
1541        const link = document.createElement('a');
1542
1543        // Переносим все атрибуты, кроме служебного data-link.
1544        Array.prototype.forEach.call(node.attributes, function(attr) {
1545            if (attr.name !== 'data-link') {
1546                link.setAttribute(attr.name, attr.value);
1547            }
1548        });
1549
1550        link.setAttribute('href', node.dataset.link);
1551        link.innerHTML = node.innerHTML;
1552        link.classList.remove('hidden-link-class');
1553
1554        node.replaceWith(link);
1555    });
1556}
1557ready(function() {
1558    replaceHiddenLink();
1559
1560    // $('.smartfilter').on('click', 'a.js-set-filter-url', function(e) {
1561    //     e.preventDefault();
1562    //     var $this = $(this);
1563    //     var url = $this.attr('href');
1564    //     var urlParts = url.split('?', 2);
1565    //     let event = new CustomEvent("goto_url", {
1566    //         bubbles: true,
1567    //         detail: {
1568    //             url: urlParts[0],
1569    //             url_data: urlParts[1] || '',
1570    //         }
1571    //     });
1572    //     e.target.dispatchEvent(event);
1573    // });
1574});
1575
1576ready(function() {
1577    // Параметры товара не в URL (SEO): при клике кладём их в куку, страница товара их подхватит.
1578    function rememberHrefParams(link) {
1579        const params = link && link.dataset.hrefParams;
1580        if (params) {
1581            BX.setCookie('productHrefParams' + link.dataset.layerId, params, {expires: 30 * 1, path: '/'});
1582        }
1583    }
1584
1585    on(document, 'click', '.b-doors a[data-href-params], .new_items a[data-href-params]', function() {
1586        rememberHrefParams(this);
1587    });
1588    on(document, 'mouseup', '.b-doors a[data-href-params], .new_items a[data-href-params]', function() {
1589        rememberHrefParams(this);
1590    });
1591
1592    on(document, 'click', '.b-doors .js-show-complect-info, .new_items .js-show-complect-info', function(e) {
1593        e.preventDefault();
1594
1595        const parentLink = this.closest('.js-datalayer-product, .js-datalayer-product-click');
1596        const link = parentLink.matches('.js-datalayer-product-click')
1597            ? parentLink
1598            : qs('.js-datalayer-product-click', parentLink);
1599        if (!link) {
1600            return;
1601        }
1602
1603        rememberHrefParams(link);
1604
1605        const url = link.getAttribute('href');
1606        const icon = qs('.catalog_card_price__ico', this);
1607        if (icon) {
1608            icon.classList.add('loading');
1609        }
1610
1611        // $.get(url, cb) -> fetch + DOMParser (раньше страницу парсил jQuery через $(html))
1612        fetch(url, {credentials: 'same-origin'})
1613            .then(function(response) {
1614                return response.text();
1615            })
1616            .then(function(html) {
1617                const doc = new DOMParser().parseFromString(html, 'text/html');
1618                const h1 = qs('.b-main-content h1', doc);
1619                const complect = qs('.b-door-complect', doc);
1620                const complectPrice = qs('.b-buy-price--wrapper', doc);
1621
1622                const title = qs('.popup_complect_info .js-title');
1623                const content = qs('.popup_complect_info .js-content');
1624                if (title) {
1625                    title.textContent = h1 ? h1.textContent : '';
1626                }
1627                if (content) {
1628                    content.innerHTML = '';
1629                    if (complectPrice) {
1630                        content.append(complectPrice);
1631                    }
1632                    if (complect) {
1633                        content.append(complect);
1634                    }
1635                }
1636
1637                fire(qs('.popup_complect'), 'open');
1638            })
1639            .finally(function() {
1640                if (icon) {
1641                    icon.classList.remove('loading');
1642                }
1643            });
1644    });
1645
1646    on(document, 'click', '.popup_complect_back', function() {
1647        fire(qs('.popup_complect'), 'close');
1648    });
1649
1650    on(document, 'open', '.popup_complect', function() {
1651        const lower_nav = qs('.lower_nav');
1652
1653        this.classList.add('active');
1654        document.body.style.overflow = 'hidden';
1655        if (lower_nav) {
1656            lower_nav.style.display = 'none';
1657        }
1658    });
1659
1660    on(document, 'close', '.popup_complect', function() {
1661        const lower_nav = qs('.lower_nav');
1662
1663        this.classList.remove('active');
1664        document.body.style.overflow = 'visible';
1665        if (lower_nav) {
1666            lower_nav.style.display = '';
1667        }
1668    });
1669});
1670
1671ready(function() {
1672    const intro = qs('.intro');
1673    const popup_nav = qs('.popup_nav');
1674    const lower_nav = qs('.lower_nav');
1675    const catalogMenu = qs('.ext-catalog');
1676    const catalogMenuContainer = qs('.catalog-menu-container');
1677    const hub = qs('.popups-hub');
1678
1679    // Аналог jQuery :visible - элемент реально отрисован (не display:none у себя или родителя).
1680    function isVisible(el) {
1681        return !!(el && el.getClientRects().length);
1682    }
1683
1684    if (catalogMenu && catalogMenuContainer) {
1685        catalogMenu.append(catalogMenuContainer.cloneNode(true));
1686        qsa(':scope > ul', catalogMenu).forEach(function(ul) {
1687            ul.remove();
1688        });
1689    }
1690
1691    function openPopup(linkId) {
1692        const popupContent = qs('[data-popup="' + linkId + '"]');
1693        const tempPopup = document.getElementById('popup_catalog_menu');
1694        if (!tempPopup || !hub) {
1695            return;
1696        }
1697
1698        const newPopup = tempPopup.cloneNode(true);
1699        newPopup.removeAttribute('id');
1700        newPopup.setAttribute('data-popup', linkId);
1701
1702        const content = qs('[data-content]', newPopup);
1703        if (content) {
1704            content.innerHTML = popupContent ? popupContent.innerHTML : '';
1705        }
1706        newPopup.classList.add('active');
1707
1708        hub.append(newPopup);
1709    }
1710
1711    function closePopup() {
1712        const popups = qsa('.popup_catalog.active');
1713
1714        if (popups.length > 1) {
1715            // Открыт вложенный попап - закрываем только верхний.
1716            popups[popups.length - 1].remove();
1717            return;
1718        }
1719
1720        popups.forEach(function(popup) {
1721            popup.classList.remove('active');
1722        });
1723
1724        if (!popup_nav || !popup_nav.classList.contains('active')) {
1725            if (popup_nav) {
1726                popup_nav.classList.remove('active');
1727            }
1728            document.body.style.overflow = 'visible';
1729            if (lower_nav) {
1730                lower_nav.style.display = '';
1731            }
1732        }
1733        if (hub) {
1734            hub.innerHTML = '';
1735        }
1736    }
1737
1738    let catalogMenuTimeout;
1739    if (catalogMenu) {
1740        // mouseenter/mouseleave не всплывают, поэтому подписываемся напрямую, без делегирования.
1741        catalogMenu.addEventListener('mouseenter', function() {
1742            if (catalogMenuTimeout) {
1743                clearTimeout(catalogMenuTimeout);
1744                catalogMenuTimeout = null;
1745            }
1746            if (!catalogMenu.classList.contains('active')) {
1747                catalogMenu.classList.add('hover');
1748                intro && intro.classList.add('menu-hover');
1749                qsa('.active[data-popup-link]', catalogMenu).forEach(function(item) {
1750                    item.classList.remove('active');
1751                });
1752            }
1753        });
1754
1755        catalogMenu.addEventListener('mouseleave', function() {
1756            catalogMenuTimeout = setTimeout(function() {
1757                catalogMenu.classList.remove('hover');
1758                intro && intro.classList.remove('menu-hover');
1759                catalogMenuTimeout = null;
1760            }, 1000);
1761        });
1762    }
1763
1764    on(document, 'click', '.ext-catalog [data-close-popup]', function(e) {
1765        e.preventDefault();
1766        catalogMenu.classList.remove('active');
1767        catalogMenu.classList.remove('hover');
1768        qsa('.active[data-popup]', catalogMenu).forEach(function(item) {
1769            item.classList.remove('active');
1770        });
1771    });
1772
1773    on(document, 'click', '.popup_nav_links [data-popup-link]', function(e) {
1774        // Раньше подписка висела на трёх корнях (.popup_nav, .popups-hub, .ext-catalog ...);
1775        // делегируем от document и отсекаем чужие клики по родителю.
1776        const root = this.closest('.popup_nav, .popups-hub, .ext-catalog .catalog-menu-container');
1777        if (!root) {
1778            return;
1779        }
1780
1781        const linkId = this.dataset.popupLink;
1782        const container = this.closest('.catalog-menu-left, .popup_catalog_content');
1783        const parent = this.closest('.ext-catalog, .popup');
1784        let force2column = false;
1785
1786        if (parent && parent.matches('.ext-catalog')) {
1787            catalogMenu.classList.add('active');
1788            force2column = true;
1789        }
1790
1791        if (container && container.matches('.catalog-menu-left')) {
1792            const containerParent = container.closest('.popup_catalog_content, .catalog-menu-container');
1793            const container2 = containerParent && qs('.catalog-menu-right', containerParent);
1794
1795            if (container2 && (isVisible(container2) || force2column)) {
1796                qsa('[data-popup]', container2).forEach(function(el) {
1797                    el.classList.remove('active');
1798                });
1799
1800                const pane = qs('[data-popup="' + linkId + '"]', container2);
1801                if (pane) {
1802                    pane.classList.add('active');
1803                    const scrolable = qs('.popup_catalog_scrollable', pane);
1804                    if (scrolable) {
1805                        scrolable.scrollTo(0, 0);
1806                    }
1807                }
1808
1809                if (this.matches('.popup_nav_link__parent')) {
1810                    if (this.classList.contains('active')) {
1811                        return;
1812                    }
1813                    qsa('.popup_nav_link__parent', containerParent).forEach(function(el) {
1814                        el.classList.remove('active');
1815                    });
1816                    this.classList.add('active');
1817                }
1818
1819                e.preventDefault();
1820                return;
1821            }
1822        }
1823
1824        e.preventDefault();
1825        openPopup(linkId);
1826    });
1827
1828    on(document, 'click', '.popups-hub [data-close-popup]', function(e) {
1829        e.preventDefault();
1830        closePopup();
1831    });
1832
1833    on(document, 'click', '.popups-hub [data-back-popup]', function(e) {
1834        e.preventDefault();
1835        const popup = this.closest('.popup_catalog');
1836        if (popup) {
1837            popup.classList.remove('active');
1838        }
1839    });
1840
1841    on(document, 'open', '.popup_catalog', function() {
1842        // Второй аргумент (content) в jQuery-версии никто никогда не передавал - выкинут.
1843        this.classList.add('active');
1844    });
1845
1846    on(document, 'back', '.popup_catalog', function() {
1847        this.classList.remove('active');
1848    });
1849});
1850
1851ready(function() {
1852    on(document, 'click', '[data-tab] [data-nav]', function() {
1853        const parent = this.closest('[data-tab]');
1854        if (!parent) {
1855            return;
1856        }
1857        const id = this.dataset.nav;
1858
1859        qsa('[data-nav], [data-pane]', parent).forEach(function(el) {
1860            el.classList.remove('active');
1861        });
1862        this.classList.add('active');
1863
1864        const pane = qs('[data-pane="' + id + '"]', parent);
1865        if (pane) {
1866            pane.classList.add('active');
1867        }
1868    });
1869});
1870
1871ready(function() {
1872    // Шаг прокрутки = расстояние между двумя соседними элементами.
1873    function stepWidth(root, itemSelector) {
1874        const first = qs(itemSelector + ':first-child', root);
1875        const second = first && first.nextElementSibling;
1876        if (!first || !second) {
1877            return 0;
1878        }
1879        return second.getBoundingClientRect().left - first.getBoundingClientRect().left;
1880    }
1881
1882    // dir: -1 - влево, 1 - вправо. Прокручиваем ровно на один шаг от текущей позиции.
1883    function slideBy(scroll, width, dir) {
1884        if (!scroll || !width) {
1885            return;
1886        }
1887        const num = Math.round(scroll.scrollLeft / width);
1888        scroll.scroll({left: (num + dir) * width, top: 0, behavior: 'smooth'});
1889    }
1890
1891    function markActive(slide) {
1892        Array.prototype.forEach.call(slide.parentElement.children, function(el) {
1893            el.classList.remove('active');
1894        });
1895        slide.classList.add('active');
1896    }
1897
1898    // Стрелки внутри самого слайда: помимо прокрутки переносят класс active на соседний слайд.
1899    on(document, 'click', '[data-slide] [data-slide-prev], [data-slide] [data-slide-next]', function() {
1900        const slide = this.closest('[data-slide]');
1901        const slider = slide.closest('[data-slider]');
1902        const scroll = slide.closest('[data-slider-content]');
1903        const dir = this.matches('[data-slide-prev]') ? -1 : 1;
1904
1905        slideBy(scroll, stepWidth(slider, '[data-slide]'), dir);
1906
1907        const sibling = dir < 0 ? slide.previousElementSibling : slide.nextElementSibling;
1908        if (sibling) {
1909            markActive(sibling);
1910        }
1911    });
1912
1913    // Стрелки слайдера (снаружи слайдов).
1914    on(document, 'click', '[data-slider] [data-slide-left], [data-slider] [data-slide-right]', function() {
1915        const slider = this.closest('[data-slider]');
1916        const scroll = qs('[data-slider-content]', slider);
1917        const dir = this.matches('[data-slide-left]') ? -1 : 1;
1918
1919        slideBy(scroll, stepWidth(slider, '[data-slide]'), dir);
1920    });
1921
1922    // Универсальная "листалка" (data-slideable) - та же механика, другие атрибуты.
1923    on(document, 'click', '[data-slideable] [data-slideable-left], [data-slideable] [data-slideable-right]', function() {
1924        const parent = this.closest('[data-slideable]');
1925        const scroll = qs('[data-slideable-content]', parent);
1926        const dir = this.matches('[data-slideable-left]') ? -1 : 1;
1927
1928        slideBy(scroll, stepWidth(parent, '[data-slideable-item]'), dir);
1929    });
1930});
1931
1932ready(function() {
1933	on(document, 'click', '.city-ask .change', function() {
1934        this.closest('.city-ask').style.display = 'none';
1935
1936        const changeBtn = qs('.b-header-city-change-btn');
1937        if (changeBtn) {
1938            changeBtn.click();
1939        }
1940    });
1941
1942    on(document, 'click', '.city-ask .accept', function() {
1943		BX.setCookie('BITRIX_SM_SELECT_CITY', '1', {path: '/', domain: '.portaprima.ru', expires: 86400});
1944        this.closest('.city-ask').style.display = 'none';
1945    });
1946});
1947
1948function checkAndShowHurryBuyPopup() {
1949  // Имя куки для флага
1950  const COOKIE_NAME = 'hurry_up_buy_shown';
1951  
1952  // Функция для получения значения куки
1953  function getCookie(name) {
1954    const matches = document.cookie.match(new RegExp(
1955      '(?:^|; )' + name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1') + '=([^;]*)'
1956    ));
1957    return matches ? decodeURIComponent(matches[1]) : undefined;
1958  }
1959  
1960  // Функция для установки куки
1961  function setCookie(name, value, days) {
1962    const date = new Date();
1963    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
1964    const expires = 'expires=' + date.toUTCString();
1965    document.cookie = name + '=' + value + ';' + expires + ';path=/';
1966  }
1967  
1968  // Проверяем наличие флага в куках
1969  if (!getCookie(COOKIE_NAME)) {
1970    const button = document.querySelector('#hurry_up_buy_btn');
1971    if (button) {
1972        button.click();
1973        // Устанавливаем флаг в куки на 1 день
1974        setCookie(COOKIE_NAME, 'true', 1);
1975    }
1976  }
1977}
1978
1979ready(function() {
1980    let maxHeight;
1981    let parent;
1982    document.querySelectorAll('.review__item').forEach((review) => {
1983        const height = review.clientHeight;
1984        if (maxHeight === undefined || (maxHeight < height)) {
1985            maxHeight = height;
1986            parent = review.parentNode;
1987        }
1988    });
1989    if (maxHeight && parent) {
1990        parent.classList.add('reviews__items_with_hidden')
1991        parent.style.setProperty('--review-height', maxHeight + 'px');
1992        document.querySelectorAll('.review__item').forEach((review) => {
1993            review.classList.add('review__item_hidden')
1994        });
1995    }
1996});
1997ready(function() {
1998    // var colorTimeout;
1999    // function nextColor() {
2000    //     var $inputs = $('.popup_colortunes-cover.active .popup-colortunes-cover-colors input');
2001    //     let i = 0;
2002    //     let iSelected = 0;
2003    //     $inputs.each(function() {
2004    //         i += 1;
2005    //         if ($(this).is(':checked')) {
2006    //             iSelected = i;
2007    //         }
2008    //     });
2009
2010    //     if ((iSelected < $inputs.length) && $inputs.eq(iSelected)) {
2011    //         $inputs.eq(iSelected).trigger('click');
2012    //     }
2013    //     else {
2014    //         $inputs.eq(0).trigger('click');
2015    //     }
2016    //     nextColorTimeout();
2017    // }
2018    // function clearColorTimeout() {
2019    //     if (colorTimeout) {
2020    //         clearTimeout(colorTimeout);
2021    //     }
2022    // }
2023    // function nextColorTimeout() {
2024    //     clearColorTimeout();
2025    //     colorTimeout = setTimeout(() => {
2026    //         nextColor();
2027    //     }, 3000);
2028    // }
2029    on(document, 'click', '.colortunes-cover-popup-btn', function(e) {
2030        e.preventDefault();
2031        const popup = document.querySelector('#colortunes-cover-popup');
2032        // Данные события едут в detail (у jQuery это был второй аргумент .trigger).
2033        fire(popup, 'open', {
2034            'coverGroupId': this.dataset.coverGroupId,
2035            'solutionId': this.dataset.solutionId,
2036        });
2037        // nextColorTimeout();
2038    });
2039    on(document, 'click', '.popup_colortunes-cover .popup_back', function() {
2040        fire(this.closest('.popup_colortunes-cover'), 'close');
2041    });
2042    function sortColors(popup, groupId) {
2043        const covers = colortunesCover && colortunesCover[groupId] || {};
2044        // Сортируем ключи в порядке убывания, чтобы проще было элементы впоследствии сортировать
2045        const sortedKeys = Object.keys(covers).sort((a, b) => covers[b].sort - covers[a].sort);
2046
2047        const colors = popup.querySelector('.popup-colortunes-cover-colors');
2048        colors.querySelectorAll('label').forEach(label => label.style.display='none');
2049        sortedKeys.forEach(key => {
2050            const input = colors.querySelector(`input[value="${key}"]`);
2051            if (input) {
2052                const label = input.closest('label');
2053                if (label) {
2054                    label.style.display = '';
2055                    // Открепляем label от DOM
2056                    label.remove();
2057                    // Добавляем первым элементом в colors
2058                    colors.prepend(label);
2059                }
2060            }
2061        });
2062        colors.dataset.color = sortedKeys[sortedKeys.length-1];
2063    }
2064
2065    function selectColor(popup, data) {
2066        if (!data) {
2067            return;
2068        }
2069        const formText = popup.querySelector('.b24-form-field-text textarea');
2070        const title = popup.querySelector('.js-title');
2071        if (title) {
2072            title.innerHTML = data.title;
2073            if (formText) {
2074                formText.value = data.title;
2075            }
2076        }
2077        const text = popup.querySelector('.js-text');
2078        if (title && text && formText) {
2079            formText.value = formText.value + "\n";
2080        }
2081        if (text) {
2082            text.innerHTML = data.text;
2083            if (formText) {
2084                formText.value = formText.value ? formText.value + data.text : data.text;
2085            }
2086        }
2087        const bg = popup.querySelector('.js-bg');
2088        if (bg) {
2089            bg.style.backgroundImage = '';
2090            bg.style.backgroundColor = '';
2091            bg.style.color = '';
2092            if (data.header_bg) {
2093                bg.style.backgroundImage = `url(${data.header_bg})`;
2094                bg.style.backgroundSize = 'cover';
2095                bg.style.backgroundPosition = 'center';
2096                bg.style.backgroundRepeat = 'no-repeat';
2097            } 
2098            else if (data.color) {
2099                bg.style.backgroundColor = data.color;
2100            }
2101            if (data.header_bg_text_color) {
2102                bg.style.color = data.header_bg_text_color;
2103            }
2104        }
2105        const product = popup.querySelector('.js-product');
2106        if (product) {
2107            product.src = data.product_img;
2108        }
2109        // console.log(groupId, colorId, cover, covers);
2110        // nextColorTimeout();
2111    }
2112    on(document, 'open', '.popup_colortunes-cover', function(e) {
2113        const config = e.detail || {};
2114        const lower_nav = document.querySelector('.lower_nav');
2115        const popup = this;
2116        // const $popup = $(popup);
2117
2118        // const template = popup.querySelector('template');
2119        // if (template) {
2120        //     const content = template.content.cloneNode(true);
2121        //     template.replaceWith(content);
2122        // }
2123        if (config.coverGroupId) {
2124            popup.dataset.coverGroupId = config.coverGroupId;
2125            sortColors(popup, config.coverGroupId);
2126            const colors = popup.querySelector('.popup-colortunes-cover-colors');
2127            colors.style.display = '';
2128            const colorId = colors && colors.dataset.color || '';
2129            if (colorId) {
2130                const color = colors.querySelector(`#colortunes-cover-color-${colorId}`);
2131                if (color) {
2132                    color.checked = true;
2133                }
2134
2135                const covers = colortunesCover && colortunesCover[config.coverGroupId] || {};
2136                const cover = covers && covers[colorId] || false;
2137                selectColor(popup, cover);
2138            }
2139        }
2140        if (config.solutionId) {
2141            const colors = popup.querySelector('.popup-colortunes-cover-colors');
2142            colors.style.display = 'none';
2143            const solution = colortunesSolution && colortunesSolution[config.solutionId] || false
2144            selectColor(popup, solution);
2145        }
2146
2147        popup.classList.add('active');
2148        document.body.style.overflow = 'hidden';
2149        lower_nav.style.display = "none";
2150    });
2151    on(document, 'close', '.popup_colortunes-cover', function() {
2152        // clearColorTimeout();
2153        const lower_nav = qs('.lower_nav');
2154
2155        this.classList.remove('active');
2156        document.body.style.overflow = 'visible';
2157        if (lower_nav) {
2158            lower_nav.style.display = '';
2159        }
2160    });
2161    on(document, 'change', '.popup_colortunes-cover input', function() {
2162        const colorId = this.value;
2163        const popup = this.closest('.popup_colortunes-cover');
2164        const groupId = popup.dataset.coverGroupId;
2165
2166        const covers = colortunesCover && colortunesCover[groupId] || {};
2167        const cover = covers && covers[colorId] || false;
2168        selectColor(popup, cover);
2169    });
2170    
2171});
2172
2173ready(function() {
2174    qsa('.js-mouse-scroll').forEach(function(slider) {
2175        let isDown = false;
2176        let startX;
2177        let scrollLeft;
2178      
2179        slider.style.cursor = 'grab';
2180      
2181        slider.addEventListener('mousedown', (e) => {
2182          isDown = true;
2183          slider.style.cursor = 'grabbing';
2184          startX = e.pageX - slider.offsetLeft;
2185          scrollLeft = slider.scrollLeft;
2186          e.preventDefault();
2187        });
2188      
2189        slider.addEventListener('mouseleave', () => {
2190          isDown = false;
2191          slider.style.cursor = 'grab';
2192        });
2193      
2194        slider.addEventListener('mouseup', () => {
2195          isDown = false;
2196          slider.style.cursor = 'grab';
2197        });
2198      
2199        slider.addEventListener('mousemove', (e) => {
2200          if (!isDown) return;
2201          const x = e.pageX - slider.offsetLeft;
2202          const walk = (x - startX) * 1.5;
2203          slider.scrollLeft = scrollLeft - walk;
2204        });
2205    });
2206});
2207/* End */
2208;
2209; /* Start:"a:4:{s:4:"full";s:57:"/local/templates/portaprima/js/favorite.js?17865233018641";s:6:"source";s:42:"/local/templates/portaprima/js/favorite.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
2210// Избранное: кнопки-сердечки и счётчик.
2211//
2212// Состояние избранного персональное, а страницы каталога и карточки отдаются из кеша
2213// (в т.ч. композитного, мимо PHP), поэтому в html его отрисовать нельзя: кнопки
2214// приходят нейтральными, а активные отмечает этот скрипт после ответа сервера.
2215//
2216// Запросы идут на /ajax/favorite.php — отдельную страницу, чтобы не собирать ради
2217// сохранения избранного каталог или карточку.
2218(function () {
2219    'use strict';
2220
2221    var URL_AJAX = '/ajax/favorite.php';
2222    var ACTION_PARAM = 'favorite_action';
2223    var buttonSelector = '.btn-favorite[data-product-id]';
2224    var state = {}; // "товар:предложение" => true
2225
2226    function request(params) {
2227        var url = new URL(URL_AJAX, location.origin);
2228        Object.keys(params).forEach(function (key) {
2229            url.searchParams.set(key, params[key]);
2230        });
2231        url.searchParams.set('AJAX', 'y');
2232
2233        return fetch(url.toString(), {
2234                credentials: 'same-origin',
2235                headers: {'X-Requested-With': 'XMLHttpRequest'},
2236            })
2237            .then(function (response) {
2238                return response.ok ? response.json() : Promise.reject(response.status);
2239            });
2240    }
2241
2242    function key(productId, offerId) {
2243        return String(parseInt(productId, 10) || 0) + ':' + String(parseInt(offerId, 10) || 0);
2244    }
2245
2246    function buttonKey(button) {
2247        return key(button.dataset.productId, button.dataset.offerId);
2248    }
2249
2250    function applyState(data) {
2251        state = {};
2252        (data.items || []).forEach(function (item) {
2253            state[key(item.PRODUCT_ID, item.OFFER_ID)] = true;
2254        });
2255
2256        document.querySelectorAll(buttonSelector).forEach(function (button) {
2257            var active = !!state[buttonKey(button)];
2258            button.classList.toggle('active', active);
2259            button.setAttribute('aria-pressed', active ? 'true' : 'false');
2260            button.title = active ? 'Убрать из избранного' : 'Добавить в избранное';
2261        });
2262
2263        document.querySelectorAll('.js-favorite-count').forEach(function (el) {
2264            // у бейджа в шапке пустое значение вместо нуля - так он скрывается
2265            // правилом :empty; обычному счётчику нужно само число, включая 0
2266            var isBadge = el.hasAttribute('data-favorite-badge');
2267            el.textContent = (isBadge && !data.count) ? '' : data.count;
2268        });
2269    }
2270
2271    // Убирать ли карточку из списка сразу после снятия из избранного — решает PHP
2272    // (параметр REMOVE_ON_UNFAVORITE компонента, атрибут на обёртке списка).
2273    // Когда список опустел, перезагружаем: пустое состояние страницы рисует сервер.
2274    function removeCard(button) {
2275        var card = button.closest('.catalog_card');
2276        if (!card || !card.closest('[data-favorite-remove-cards]')) {
2277            return;
2278        }
2279
2280        card.classList.add('catalog_card_removing');
2281        setTimeout(function () {
2282            var list = card.parentNode;
2283            card.remove();
2284            if (list && !list.querySelector('.catalog_card')) {
2285                location.reload();
2286            }
2287        }, 200);
2288    }
2289
2290    function toggle(button) {
2291        if (button.dataset.favoriteBusy) {
2292            return;
2293        }
2294        button.dataset.favoriteBusy = '1';
2295
2296        // переключаем сразу, не дожидаясь ответа: клик должен ощущаться мгновенно
2297        var active = !button.classList.contains('active');
2298        button.classList.toggle('active', active);
2299        button.setAttribute('aria-pressed', active ? 'true' : 'false');
2300
2301        request({
2302                [ACTION_PARAM]: 'TOGGLE_FAVORITE',
2303                PRODUCT_ID: parseInt(button.dataset.productId, 10) || 0,
2304                OFFER_ID: parseInt(button.dataset.offerId, 10) || 0,
2305            })
2306            .then(function (data) {
2307                applyState(data);
2308                if (!active) {
2309                    removeCard(button);
2310                }
2311            })
2312            .catch(function (error) {
2313                button.classList.toggle('active', !active); // не сохранилось - возвращаем как было
2314                button.setAttribute('aria-pressed', !active ? 'true' : 'false');
2315                console.error('favorite toggle failed', error);
2316            })
2317            .then(function () {
2318                delete button.dataset.favoriteBusy;
2319            });
2320    }
2321
2322    // Поделиться подборкой: состав уже зашит в ссылку на стороне PHP.
2323    // Где есть системное «Поделиться» — отдаём его, иначе копируем ссылку в буфер.
2324    function share(link) {
2325        var url = link.dataset.favoriteShare || link.href;
2326
2327        if (navigator.share) {
2328            navigator.share({title: 'Подборка дверей Porta prima', url: url}).catch(function () {});
2329            return;
2330        }
2331
2332        if (navigator.clipboard) {
2333            navigator.clipboard.writeText(url).then(function () {
2334                var label = link.dataset.doneLabel || 'Ссылка скопирована';
2335                if (link.dataset.shareBusy) {
2336                    return;
2337                }
2338                link.dataset.shareBusy = '1';
2339                var text = link.lastChild;
2340                var prev = text.textContent;
2341                text.textContent = ' ' + label;
2342                setTimeout(function () {
2343                    text.textContent = prev;
2344                    delete link.dataset.shareBusy;
2345                }, 2000);
2346            }).catch(function () {
2347                location.href = url; // не дали доступ к буферу - пусть копирует из адресной строки
2348            });
2349            return;
2350        }
2351
2352        location.href = url;
2353    }
2354
2355    // делегирование: карточка товара и списки каталога перерисовываются аяксом
2356    document.addEventListener('click', function (e) {
2357        var shareLink = e.target.closest('[data-favorite-share]');
2358        if (shareLink) {
2359            e.preventDefault();
2360            share(shareLink);
2361            return;
2362        }
2363
2364        // отдельной генерации PDF нет: печатаем страницу, в диалоге печати
2365        // пользователь может выбрать «Сохранить как PDF»
2366        var printLink = e.target.closest('[data-favorite-print]');
2367        if (printLink) {
2368            e.preventDefault();
2369            window.print();
2370            return;
2371        }
2372
2373        var clear = e.target.closest('[data-favorite-clear]');
2374        if (clear) {
2375            // без JS ссылка и так работает: /ajax/favorite.php вернёт на страницу
2376            e.preventDefault();
2377            request({[ACTION_PARAM]: 'CLEAR_FAVORITES'}).then(function () {
2378                location.reload(); // список избранного на странице надо перерисовать
2379            }).catch(function (error) {
2380                console.error('favorite clear failed', error);
2381                location.href = clear.href;
2382            });
2383            return;
2384        }
2385
2386        var button = e.target.closest(buttonSelector);
2387        if (!button) {
2388            return;
2389        }
2390        e.preventDefault();
2391        toggle(button);
2392    });
2393
2394    function init() {
2395        if (!document.querySelector(buttonSelector) && !document.querySelector('.js-favorite-count')) {
2396            return; // на странице нечего отмечать
2397        }
2398        request({[ACTION_PARAM]: 'STATE'}).then(applyState).catch(function (error) {
2399            console.error('favorite state failed', error);
2400        });
2401    }
2402
2403    if (document.readyState === 'loading') {
2404        document.addEventListener('DOMContentLoaded', init);
2405    } else {
2406        init();
2407    }
2408
2409    window.ppFavorite = {refresh: init};
2410})();
2411
2412/* End */
2413;
2414; /* Start:"a:4:{s:4:"full";s:87:"/local/templates/.default/components/scody/cookie/.default/script.min.js?17706187851160";s:6:"source";s:68:"/local/templates/.default/components/scody/cookie/.default/script.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
2415class CookieManager{constructor(e={}){this.settings={containerId:"cookieDiv",cookieName:"acceptCookie",cookieValue:"accepted",cookieExpireDays:30,checkCookieTimeout:1e3,...e},this.settings.cookieDiv=document.getElementById(this.settings.containerId),document.addEventListener("DOMContentLoaded",()=>{setTimeout(()=>this.checkCookie(),this.settings.checkCookieTimeout)})}setCookie(e,i,o){o=new Date(Date.now()+864e5*o).toUTCString();document.cookie=e+`=${i}; expires=${o}; path=/;`}getCookie(e){e=document.cookie.match(new RegExp(`(^| )${e}=([^;]+)`));return e?decodeURIComponent(e[2]):""}checkCookie(){this.getCookie(this.settings.cookieName)!==this.settings.cookieValue?(this.settings.cookieDiv.style.display="flex",this.setCookie(this.settings.cookieName,"",this.settings.cookieExpireDays),this.settings.cookieDiv.classList.remove("cookie__hide")):this.closeCookieDiv()}acceptCookies(){this.setCookie(this.settings.cookieName,this.settings.cookieValue,this.settings.cookieExpireDays),this.closeCookieDiv()}closeCookieDiv(){this.settings.cookieDiv&&(this.settings.cookieDiv.classList.add("cookie__hide"),setTimeout(()=>this.settings.cookieDiv.remove(),1e3))}}
2416/* End */
2417;
2418; /* Start:"a:4:{s:4:"full";s:68:"/local/templates/portaprima/js/commonCatalog_new2.js?178403932461193";s:6:"source";s:52:"/local/templates/portaprima/js/commonCatalog_new2.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
2419var $$ = $$ || {};
2420
2421$$.equalHeight = function(container){
2422    if (container !== undefined) var targets = container.find('[data-equal]');
2423    else targets = $('[data-equal]');
2424
2425    if (targets.length == 0) return;
2426
2427    var groups = {};
2428
2429    targets.each(function(){
2430        var gr = $(this).attr("data-equal");
2431        var h = $(this).height();
2432        if (groups[gr] === undefined || groups[gr] < h) groups[gr] = h;
2433    });
2434
2435    _.forEach(groups, function(value, key){
2436        targets.filter('[data-equal=' + key + ']').css('min-height', value);
2437    });
2438};
2439
2440$('a[href^="#"]').click(function(e){
2441
2442	href = $(this).attr('href');
2443	if (href != '#') {
2444        if (href != '#tabs-credit' && href != '#tabs-rassrochka' && !/^#(show|hide):atumquiz/.test(href)) {
2445            e.preventDefault();
2446            $$.obj_controls.scrollTo($(href + ':first').offset().top, 20);
2447        }
2448    }
2449
2450});
2451
2452//элементы управления
2453$$.controls = function(){
2454    this.selectors = {
2455        popup: '.js-popup',  //всплывающее окно
2456        add2cart: '.js-add2cart', //кнопка - добавить в корзину
2457		quantity: '.js-quantity'	//блок изменения количества
2458    };
2459	
2460    this.body = $('body');
2461	
2462	this.number_format = function(number, decimals, dec_point, thousands_sep){
2463		number = (number + '').replace(/[^0-9+\-Ee.]/g, '');
2464		var n = !isFinite(+number) ? 0 : +number,
2465			prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
2466			sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
2467			dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
2468			s = '',
2469			toFixedFix = function(n, prec){
2470				var k = Math.pow(10, prec);
2471				return '' + Math.round(n * k) / k;
2472			};
2473			
2474		// Fix for IE parseFloat(0.55).toFixed(0) = 0;
2475		s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
2476		if(s[0].length > 3){
2477			s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
2478		}
2479		if((s[1] || '').length < prec){
2480			s[1] = s[1] || '';
2481			s[1] += new Array(prec - s[1].length + 1).join('0');
2482		}
2483		return s.join(dec);
2484	}
2485	
2486	this.scrollTo = function(pos, shift, params){
2487		if(!params) params = {};
2488		params.ignore_fixed_header = params.ignore_fixed_header || false;
2489		
2490		shift = parseInt(shift) || 0;
2491		if(!params.ignore_fixed_header && site.header.isFixed())
2492			shift += site.header.$root.height() + (parseInt(site.header.$root.css('top')) || 0);
2493		pos = pos - shift;
2494
2495		$('html, body').animate({scrollTop: pos}, 500);
2496	}
2497	
2498    this.bindEvents = function(){
2499
2500        this.body.on('click', this.selectors.popup, function(e){
2501            e.preventDefault();
2502            var target = $(e.currentTarget);
2503            if (!target.hasClass('disabled')){
2504                target.openPopUp({width: 480});
2505            }
2506        }.bind(this));
2507
2508		this.body.on('click', this.selectors.quantity + ' i', function(e){
2509            e.preventDefault();
2510            var $target = $(e.currentTarget),
2511				$qt = $target.parent().find('input'),
2512				val = $qt.val() * 1;
2513			
2514            if($target.attr('data-qt') * 1 == -1) val = val - 1;
2515            else val = val + 1;
2516			
2517			$qt.val(val).trigger('blur');
2518
2519			$(this.selectors.add2cart).attr('data-qt', val);
2520		}.bind(this));
2521		
2522        this.body.on('click', this.selectors.add2cart, function(e){
2523            e.preventDefault();
2524            var target = $(e.currentTarget);
2525            var self = this;
2526
2527            var url = target.attr('href') || target.data('href') || null;
2528            ;
2529            if (url != null && url.match(/#/gi)) url = url.split('#')[0] + ' #' + url.split('#')[1];
2530
2531            var ga_event = target.attr('data-ga'),
2532				ga_label = target.attr('data-ga-label'),
2533				data = target.attr('data-add'),
2534				properties = target.attr('data-properties'),
2535				detailUrl = target.attr('data-detail-url'),
2536				set_qt = target.data('qt');
2537
2538			if(detailUrl === undefined) detailUrl='';
2539
2540            if (!url || !data) return;
2541
2542            $.ajax({
2543                type: "GET",
2544                url: url,
2545                data: 'add2basket=' + data + '&properties=' + properties + '&set_qt=' + set_qt+'&detailUrl='+detailUrl,
2546                dataType: 'json',
2547                success: function(result){
2548                    if(result.added > 0){
2549						BX.onCustomEvent('OnBasketChange');
2550						if(result.message) {
2551							var popupBuy = document.querySelector('.popup_buy');
2552							if (popupBuy) {
2553								popupBuy.classList.add('active');
2554                    			document.body.style.overflow = 'hidden';
2555							}
2556							else {
2557								$.fancybox.open(result.message);
2558							}
2559						}
2560						if (window['updateCatalogBasketIn']) {
2561							window.currentBasketItems = result.basket || [];
2562							updateCatalogBasketIn();
2563						}
2564
2565						$$.metrika.pushEvent(ga_event, {'label' : ga_label});
2566						$$.metrika.addBasketProduct(result.metrika);
2567                    }
2568                },
2569                error: function(){
2570                    if(result.message) $.fancybox.open(result.message);
2571                }
2572            });
2573        }.bind(this));
2574
2575    };
2576
2577    this.init = function(){
2578        this.bindEvents();
2579    };
2580
2581    this.init();
2582};
2583
2584//topik [05.03.2017]: Metrika.
2585// ВНИМАНИЕ: это commonCatalog_new.js без аналитики - она вынесена в catalogAnalytics.js.
2586// Подключать вместе с ним; если аналитика не подключена (например, счётчики отключены
2587// через ?analitic_scripts=disable_all), каталог всё равно работает: вызовы уходят
2588// в заглушку ниже. Реальный $$.metrika перетрёт её при инициализации catalogAnalytics.js.
2589//
2590// Каталог зовёт аналитику только через $$.metrika.* (9 мест); vk_ecomm/ga_ecomm
2591// дёргает уже она сама - поэтому связь односторонняя и разрез проходит чисто.
2592$$.metrika = $$.metrika || {
2593	pushEvent: function(){},
2594	addBasketProduct: function(){},
2595	removeBasketProduct: function(){},
2596	viewOrder: function(){},
2597	viewBasket: function(){},
2598	viewProduct: function(){},
2599	productList: function(){},
2600};
2601
2602
2603//topik [05.03.2017]: History.
2604$$._history = function(){
2605	this.poping = false;
2606	
2607	this.initState = function(obj){
2608		if(!window.history.state || !window.history.state.data){
2609			window.history.replaceState({
2610				name: obj.nodes.header.html(),
2611				obj: obj.variable,
2612				params: false,
2613				data: JSON.stringify(obj.getData())
2614			}, '', '');
2615		}
2616		else this.popState(window.history.state);
2617	};
2618	
2619	this.pushState = function(obj, params, data){
2620		if(this.poping) return false;			//topik: Не сделать push во время updateViewport из popa-а
2621		if(!$$[obj.variable]) return false;		//topik: Делать push только для основных объектов страницы.
2622		
2623		if(params.add){
2624			params.add = false;
2625			data.content = obj.nodes.content.html();
2626		}
2627		
2628		window.history.pushState({
2629			name: obj.nodes.header.html(),
2630			obj: obj.variable,
2631			params: JSON.stringify(params),
2632			data: JSON.stringify(data)
2633		}, '', (obj.URL ? obj.URL : ''));
2634	};
2635	
2636	this.popState = function(state){
2637		if(state && state.obj && $$[state.obj]){
2638			this.poping = true;
2639			$$[state.obj].updateViewport(JSON.parse(state.params), JSON.parse(state.data), true);
2640			this.poping = false;
2641		}
2642	};
2643	
2644    this.init = function(){
2645		if('scrollRestoration' in window.history)
2646			window.history.scrollRestoration = 'manual';
2647		
2648		window.onpopstate = function(e){
2649			$$.history.popState(e.state);
2650		};
2651    };
2652	
2653	this.init();
2654};
2655
2656//загрузчик
2657$$.ajaxLoader = function(parent){
2658    this.parent = parent;
2659    this.body = $('body');
2660
2661    this.start = function(params){
2662        var parent = this.parent;
2663        var self = this;
2664        if (parent.loading) return;
2665        parent.loading = true;
2666        this.body.addClass('ajax-loading');
2667
2668        $.ajax({
2669            type: "GET",
2670            url: params.href,
2671            data: params.data ? params.data + '&AJAX=Y' : 'AJAX=Y',
2672            dataType: 'json',
2673            success: function(result){
2674                parent.loading = false;
2675                self.body.removeClass('ajax-loading');
2676                if(typeof params.success == 'function') params.success(params, result);
2677                replaceHiddenLink()
2678            },
2679            error: function(result){
2680                parent.loading = false;
2681                self.body.removeClass('ajax-loading');
2682                if(typeof params.error == 'function') params.error(params, result);
2683            }
2684        });
2685    };
2686};
2687
2688//Корзина и оформление заказа
2689$$.basketOrder = function(root){
2690	var _self = this;
2691	
2692    this.root = root;
2693	if (!this.root.length) {
2694		return;
2695	}
2696
2697    this.selectors = {
2698        checker: '.js-co-checker',
2699        side_comment: '.js-co-comment',
2700        section: '.js-section',
2701		add: '.js-mb-add',
2702        delete: '.js-mb-delete',
2703		clear: '#b-basket-btn-clear',
2704		order: '#b-basket-btn-order',
2705        quantity: '.js-qt',
2706        cbox: '.js-cc-cbox',
2707		required: '.js-form-group-required'
2708    };
2709
2710    this.nodes = {
2711        basket: this.root.find('.js-main-basket'),
2712        order: this.root.find('.js-main-order')
2713    };
2714
2715    this.loader = new $$.ajaxLoader(this);
2716
2717	this.ChangeBasketURL = '/ajax/v2/ajaxChangeBasket.php';
2718	
2719    this.initCbox = function(){
2720    };
2721
2722    this.uniform = function(obj){
2723        obj.find('input[type="radio"], input[type="checkbox"]').uniform();
2724        obj.find('select').not('.select-picker').not('.b-select-native').selectbox();
2725		const phones = obj.find('.mf_phone');
2726		phones && phones.length && phones.maskPhone();
2727    };
2728
2729    this.updateViewport = function(params, data)
2730	{
2731        if(data.cart !== undefined)
2732		{
2733			this.nodes.basket.html(data.cart);
2734			BX.onCustomEvent('OnBasketChange');
2735		}
2736		if(data.order !== undefined)
2737		{
2738            this.nodes.order.html(data.order);
2739            this.uniform(this.nodes.order);
2740        }
2741    };
2742
2743	this.orderFormCheck = function(submitForm)
2744	{
2745		if(this.arSavedNotValidInputId === undefined || submitForm === 'Y')
2746			this.arSavedNotValidInputId = [];
2747
2748		var bValid = true,
2749			arSavedNotValidInputId = this.arSavedNotValidInputId,
2750			arWrapsToValidate = submitForm === 'Y' ? this.nodes.order.find(this.selectors.required) : $('#' + arSavedNotValidInputId.join(', #')).closest('.form-group');
2751
2752		arWrapsToValidate.each(function(){
2753			var $wrap = $(this),
2754				$input = $wrap.find('input'),
2755				inp_type = $input.prop('type'),
2756				regex_email = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
2757
2758			$wrap.removeClass('is_required is_wrong g-error');
2759
2760			if(
2761				inp_type == 'text' && $.trim($input.val()) == ''
2762				|| $wrap.hasClass('form-group--email') && !regex_email.test($input.val())
2763				|| inp_type == 'checkbox' && !$input.prop('checked')
2764			){
2765				bValid = false;
2766
2767				if(inp_type == 'checkbox') cls = 'is_required g-error';
2768				else cls = $.trim($input.val()) == '' ? 'is_required' : 'is_wrong';
2769				$wrap.addClass(cls);
2770
2771				if(submitForm === 'Y')
2772					arSavedNotValidInputId.push($input.prop('id'));
2773			}
2774		});
2775
2776		return bValid;
2777	};
2778
2779	this.clearBasket = function(){
2780		var self = this;
2781		this.loader.start({
2782			href: this.ChangeBasketURL,
2783			data: 'clear_basket=Y',
2784			success: function(params, result){
2785				self.updateViewport(params, result);
2786				$$.metrika.removeBasketProduct(result.metrika);
2787			}
2788		});
2789	}
2790	
2791    this.bindEvents = function(){
2792
2793        this.nodes.order.on('click', this.selectors.checker, function(e){
2794            var target = $(e.currentTarget);
2795            var id = target.attr('id');
2796            var parent = target.closest(this.selectors.section);
2797            parent.find(this.selectors.side_comment).removeClass('active').filter('[data-id="' + id + '"]').addClass('active');
2798            parent.find(this.selectors.checker).closest('label').removeClass('active');
2799            target.closest('label').addClass('active');
2800        }.bind(this));
2801		
2802        this.nodes.basket.on('blur', this.selectors.quantity, function(e){
2803			var $qt = $(e.currentTarget),
2804				val = parseInt($qt.val()),
2805				preval = parseInt($qt.data('qt')),
2806				self = this;
2807			
2808			if(val <= 0 || isNaN(val)) val = preval;
2809			$qt.data('qt', val).val(val);
2810			
2811			if(val !== preval){
2812				this.loader.start({
2813					href: this.ChangeBasketURL,
2814					data: 'qt_basket=Y&id=' + $qt.data('id') + '&qt=' + val,
2815					success: function(params, result){
2816						self.updateViewport(params, result);
2817					}
2818				});
2819			}
2820        }.bind(this));
2821
2822        this.nodes.basket.on('click', this.selectors.delete, function(e){
2823            e.preventDefault();
2824            var $target = $(e.currentTarget);
2825            var self = this;
2826            this.loader.start({
2827                href: this.ChangeBasketURL,
2828                data: 'del_basket=Y&id=' + $target.data('id'),
2829                success: function(params, result){
2830                    self.updateViewport(params, result);
2831					$$.metrika.removeBasketProduct(result.metrika);
2832                }
2833            });
2834        }.bind(this));
2835
2836        this.nodes.basket.on('click', this.selectors.add, function(e){
2837            e.preventDefault();
2838            var $target = $(e.currentTarget);
2839            var self = this;
2840            this.loader.start({
2841                href: this.ChangeBasketURL,
2842                data: 'add_basket=Y&id=' + $target.data('id'),
2843                success: function(params, result){
2844                    self.updateViewport(params, result);
2845                }
2846            });
2847        }.bind(this));
2848
2849        this.nodes.basket.on('click', this.selectors.clear, function(e){
2850            e.preventDefault();
2851			$.fancybox.open('<div class="b-pop-system"><p class="b-pop-system-ttl">Подтвердите удаление<br>всех товаров из&nbsp;корзины.</p><span class="btn btn-red-fill" onclick="if($$.obj_basket_order !== undefined) $$.obj_basket_order.clearBasket(); $.fancybox.close();">Удалить</span><span class="btn" data-fancybox-close="">Отмена</span></div>');
2852        }.bind(this));
2853
2854        this.nodes.basket.on('click', this.selectors.order, function(e){
2855			e.preventDefault();
2856
2857			if (window.basketMetrika && basketMetrika.length) {
2858				$$.metrika.viewOrder(basketMetrika);
2859			}
2860			
2861			//topik [24.09.2020]: Вместо прокрутки к форме, она теперь открывается в попапе.
2862			//$$.obj_controls.scrollTo(this.nodes.order.offset().top, 25);
2863			$.fancybox.open({
2864				src: this.nodes.order,
2865				type: 'inline',
2866				animationEffect: 'material',
2867				baseClass: 'b-pop-form',
2868				autoFocus: false
2869			});
2870        }.bind(this));
2871
2872    };
2873
2874    this.init = function(){
2875        this.initCbox();
2876		this.uniform(this.nodes.order);
2877        this.bindEvents();
2878    };
2879
2880    this.init();
2881};
2882
2883//общий каталог
2884$$.commonCatalog = function(root){
2885	this.variable = 'catalog_common';
2886	this.root = root;
2887
2888	this.nodes = {
2889		header: $('h1'),
2890		content: $('#b-catalog-list')
2891	};
2892
2893	this.selectors = {
2894		pagenav: '.b-pagenav',
2895		pagenav_selector: '.js-pagenav'
2896	};
2897
2898	this.loading = false;
2899	this.loader = new $$.ajaxLoader(this);
2900	this.filter = new $$.catalogFilter(this);
2901	this.sorting = new $$.catalogSorting(this);
2902
2903	this.updateViewport = function(params, data){
2904		if(data.filter !== undefined && this.filter.updateViewport) this.filter.updateViewport(params, data);
2905		if(data.sorting !== undefined) this.sorting.updateViewport(params, data);
2906		if(data.content !== undefined){
2907			var $content = $(data.content),
2908				$ul = this.nodes.content.children('ul'),
2909				$new_items;
2910			if(!$ul.length && this.nodes.content.children('.catalog_cards_wrap')) {
2911				$ul = this.nodes.content.children('.catalog_cards_wrap'),
2912				$new_items = $($content.filter('.catalog_cards_wrap').html());
2913			}
2914			else {
2915				$new_items = $($content.filter('ul').html());
2916			}
2917			
2918			if(!$ul.length) this.nodes.content.append($content);
2919			else{
2920				if(params.add) $ul.append($new_items);
2921				else{
2922					if($new_items.length) $ul.html($new_items);
2923					else alert('Не найдено ни одного товара');
2924				}
2925				
2926				this.nodes.content.children(this.selectors.pagenav).html($content.filter(this.selectors.pagenav).html());
2927				
2928				$pagenav_shown = this.nodes.content.children(this.selectors.pagenav).find('.b-pagelist-shown span');
2929				if($pagenav_shown.length) $pagenav_shown.html($ul.children('li').length);
2930			}
2931		}
2932		if(data.header !== undefined) this.nodes.header.html(data.header);
2933		if(data.url !== undefined) this.URL = data.url;
2934		
2935		if(params.scroll){
2936			if (this.nodes.header.length) {
2937				$$.obj_controls.scrollTo(this.nodes.header.offset().top, 15);
2938			}
2939		}
2940		
2941		$$.history.pushState(this, params, data);	//HISTORY_COMMENT раскомментировать для использования истории.
2942	};
2943	
2944	this.setEmptyCatalog = function(params, data){
2945		this.nodes.content.html('<p>Нет товаров, удовлетворяющих критериям фильтра.<br>Попробуйте изменить или сбросить параметры фильтра</p>');
2946	}
2947
2948	this.bindEvents = function(){
2949
2950		//постраничный вывод
2951		this.root.on('click', this.selectors.pagenav_selector, function(e){
2952			e.preventDefault();
2953			var target = $(e.currentTarget),
2954				url = target.attr('href') || target.data('href') || null,
2955				add = target.data('add') ? true : false,
2956				self = this;
2957
2958			this.loader.start({
2959				add: add,
2960				scroll: !add,
2961				href: url,
2962				data: '',				
2963				success: function(params, data){
2964					self.updateViewport(params, data);
2965				}
2966			});			
2967		}.bind(this));
2968		
2969	};
2970
2971	this.getData = function(){
2972		return {
2973			filter: this.filter.root.html(),
2974			sorting: this.sorting.root.html(),
2975			content: this.nodes.content.html(),
2976			header: this.nodes.header.html()
2977		};
2978	};
2979	
2980	this.init = function(){
2981		this.bindEvents();
2982	};
2983
2984	this.init();
2985};
2986
2987//каталог дверей
2988$$.doorCatalog = function(root){
2989	this.variable = 'catalog';
2990	this.root = root;
2991
2992	this.nodes = {
2993		header: $('h1'),
2994		content: $('#b-catalog-list'),
2995		preset: $('#b-preset-text'),
2996		info: $('#b-seotext')
2997	};
2998
2999	this.selectors = {
3000		pagenav: '.b-pagenav',
3001		pagenav_selector: '.js-pagenav',
3002		no_mobile: '.js-no-mobile'
3003	};
3004	
3005	this.loading = false;
3006	this.loader = new $$.ajaxLoader(this);
3007	this.filter = new $$.catalogFilter(this);
3008	this.sorting = new $$.catalogSorting(this);
3009	this.is_mobile = ($(document).width() < 768);
3010
3011	this.updateViewport = function(params, data){
3012		if(data.filter !== undefined && this.filter.updateViewport) this.filter.updateViewport(params, data);
3013		if(data.sorting !== undefined) this.sorting.updateViewport(params, data);
3014		if(data.content !== undefined) {
3015			var old_items = this.nodes.content.children('ul');
3016			var old_items2 = this.nodes.content.find('.catalog_cards');
3017			var $content = $(data.content),
3018				new_items;
3019			if (old_items2.length) {
3020				new_items = $content.filter('.catalog_cards');
3021				if (!new_items.length) {
3022					new_items = $content.find('.catalog_cards');
3023				}
3024			}
3025			else {
3026				new_items = $content.filter('ul');
3027			}
3028			var $new_items = $(new_items.html()),
3029				$ul = old_items2.length ? old_items2 : old_items;
3030			if(params.add) $ul.append($new_items);
3031			else{
3032				if($new_items.length) $ul.html($new_items);
3033				else alert('Не найдено ни одного товара');
3034			}
3035			
3036			var $newNav = $content.filter(this.selectors.pagenav);
3037			if (!$newNav || !$newNav.length) {
3038				$newNav = $content.find(this.selectors.pagenav);
3039			}
3040			var $contentNav = this.nodes.content.children(this.selectors.pagenav);
3041			if (!$contentNav || !$contentNav.length) {
3042				$contentNav = this.nodes.content.find(this.selectors.pagenav);
3043			}
3044			$contentNav.html($newNav.html());
3045			
3046			$pagenav_shown = $contentNav.find('.b-pagelist-shown span');
3047			if($pagenav_shown.length) $pagenav_shown.html($ul.children('li').length);
3048			
3049			$ul.trigger('updateViewport');
3050		}
3051		if ((data.items_cnt !== undefined) && (data.items_cnt !== '') && $('.js-catalog-element-cnt').length) {
3052			$('.js-catalog-element-cnt').html(data.items_cnt_formated)
3053			if (!params.add) {
3054				$('.js-catalog-element-cnt-from').html(data.items_cnt_from)
3055			}
3056			$('.js-catalog-element-cnt-to').html(data.items_cnt_to)
3057		}
3058		//С появлением и скрытие кода пресетов есть проблемы - т.к. там полно слайдеров и их нужно будет переинициализировать.
3059		//if(data.preset !== undefined) this.nodes.preset.css('display', 'block').html(data.preset);
3060		//else this.nodes.preset.css('display', 'none');
3061		if(data.info !== undefined) this.nodes.info.css('display', 'block').html(data.info);
3062		else this.nodes.info.css('display', 'none');
3063		if(data.header !== undefined) this.nodes.header.html(data.header);
3064		if(data.url !== undefined) this.URL = data.url;
3065		
3066		if(params.scroll || this.is_mobile && !params.add){
3067			if (this.nodes.header.length) {
3068				$$.obj_controls.scrollTo(this.nodes.header.offset().top, 15);
3069			}
3070		}
3071		
3072		$$.history.pushState(this, params, data);	//HISTORY_COMMENT раскомментировать для использования истории.
3073
3074		// if (window['LazyLoad']) {
3075		// 	var myLazyLoad = new LazyLoad({
3076		// 		elements_selector: ".lazy"
3077		// 	});
3078		// }
3079
3080    };
3081	
3082	this.setEmptyCatalog = function(params, data){
3083		this.nodes.content.html('<p>Нет товаров, удовлетворяющих критериям фильтра.<br>Попробуйте изменить или <a href="/mezhkomnatnye-dveri/">сбросить параметры фильтра.</a></p>');
3084	}
3085
3086	this.bindEvents = function(){
3087		
3088		//эти ссылки не должны работать на мобильных
3089		this.nodes.content.on('click', this.selectors.no_mobile, function(e){
3090			if(this.is_mobile){
3091				e.preventDefault();
3092				return false;
3093			}
3094		}.bind(this));
3095		
3096		//постраничный вывод
3097		this.root.on('click', this.selectors.pagenav_selector, function(e){
3098			e.preventDefault();
3099			var target = $(e.currentTarget),
3100				url = target.attr('href') || target.data('href') || null,
3101				add = target.data('add') ? true : false,
3102				self = this;
3103
3104			this.loader.start({
3105				add: add,
3106				scroll: !add,
3107				href: url,
3108				data: '',
3109				success: function(params, data){
3110					self.updateViewport(params, data);
3111
3112					$(".b-doors")
3113						.find(".glass-tabs")
3114						.find("a")
3115						.on("click", function () {
3116
3117							let glassTabsCurrentLink = $(this),
3118								offers = glassTabsCurrentLink.closest(".b-doors-el-offers"),
3119								offersItems = offers.find(".js-datalayer-product");
3120
3121							let index = $(this).closest("li").data("index");
3122
3123							let offerActive = offersItems.filter("[data-layer-id=" + index + "]");
3124
3125							if (offerActive.length > 0) {
3126								offersItems.hide();
3127								offerActive.show();
3128							}
3129
3130							return false;
3131						});
3132				}
3133			});
3134		}.bind(this));
3135
3136	};
3137
3138	this.getData = function(){
3139		return {
3140			filter: this.filter.root.html(),
3141			sorting: this.sorting.root.html(),
3142			content: this.nodes.content.html(),
3143			info: this.nodes.info.html(),
3144			header: this.nodes.header.html()
3145		};
3146	};
3147	
3148	this.init = function(){
3149		this.bindEvents();
3150	};
3151
3152	this.init();
3153};
3154
3155//список дверей
3156$$.doorList = function(root){
3157	this.root = root;
3158
3159	this.selectors = {
3160		quickview: '.js-quickview'
3161	};
3162	
3163	this.doorsOfferSliders = function(){
3164		var self = this;
3165		
3166		this.root.children('ul').children('li').each(function(){
3167			var $li = $(this);
3168
3169			if(!$li.data('offer-slider-on')){
3170				$li.data('offer-slider-on', true);
3171
3172				var $nav = $li.find('.b-doors-el-offers-nav'),
3173					$nav_prev = $nav.find('.arr-l'),
3174					$nav_next = $nav.find('.arr-r'),
3175					$offers = $li.find('.b-doors-el-offers'),
3176					$offers_lis = $offers.children('li'),
3177					n = $offers_lis.length,
3178					cur = 0;
3179
3180				if(n){
3181					$nav_prev.click(function(){
3182						if(cur > 0){
3183							offer_w = Math.round($offers_lis.eq(cur).outerWidth() * 100) / 100;
3184
3185							cur--;
3186							shift = shift = 0 - cur*offer_w;
3187							$offers_lis.eq(0).animate({'margin-left': shift+'px'}, 250);
3188
3189							$offers_lis.eq(cur).css('opacity', 0.1).animate({'opacity': 1}, 500);
3190							$offers_lis.eq(cur+2).css('opacity', 1).animate({'opacity': 0.1}, 500);
3191
3192							if(cur == 0) $nav_prev.addClass('disabled');
3193							else $nav_prev.removeClass('disabled');
3194							$nav_next.removeClass('disabled');
3195						}
3196					});
3197
3198					$nav_next.click(function(){
3199						if(cur < n - 2){
3200							offer_w = Math.round($offers_lis.eq(cur).outerWidth() * 100) / 100;
3201
3202							cur++;
3203							shift = shift = 0 - cur*offer_w;
3204							$offers_lis.eq(0).animate({'margin-left': shift+'px'}, 250);
3205
3206							$offers_lis.eq(cur+1).css('opacity', 0.1).animate({'opacity': 1}, 500);
3207							$offers_lis.eq(cur-1).css('opacity', 1).animate({'opacity': 0.1}, 500);
3208
3209							if(cur == n-2) $nav_next.addClass('disabled');
3210							else $nav_next.removeClass('disabled');
3211							$nav_prev.removeClass('disabled');
3212						}
3213					});
3214				}
3215			}
3216		});
3217	};
3218	
3219	this.bindEvents = function(){
3220		
3221		//topik [18.01.2019]: Обновление слайдеров предложений при обновлении списка дверей.
3222		this.root.on('updateViewport', function(){
3223            this.doorsOfferSliders();
3224			$$.metrika.productList(this.root);
3225		}.bind(this));
3226		
3227		//topik [18.01.2019]: Быстрый просмотр.
3228		this.root.on('click', this.selectors.quickview, function(e){
3229            e.preventDefault();
3230			
3231			var $target = $(e.currentTarget),
3232				$door = false;
3233			
3234			$.fancybox.open({
3235				src: $target.data('src'),
3236				type: 'ajax',
3237				afterShow: function(){
3238					$door = new $$.doorDetail($('#b-door-quickview'), {'quickview' : true});
3239					$door.root.find('select').not('.select-picker').not('.b-select-native').selectbox();
3240				},
3241				afterClose: function(){
3242					$door = false;
3243				}
3244			});
3245		}.bind(this));
3246
3247	};
3248	
3249	this.init = function(){
3250		this.bindEvents();
3251		this.doorsOfferSliders();
3252		$$.metrika.productList(this.root);
3253	};
3254
3255	this.init();
3256};
3257
3258//фильтр каталога товаров
3259$$.catalogFilter = function(parent){
3260	this.parent = parent;
3261	this.root = $('#b-filter');
3262	if (!this.root.length) {
3263		return;
3264	}
3265
3266	this.selectors = {
3267		opener: '.b-filter-show',
3268		set_filter: '.js-set-filter',
3269		set_filter_url: '.js-set-filter-url',
3270		filter_list: '.b-filter-ul',
3271		filter_items: '.b-filter-ul > li',
3272		filter_input_check: '.b-filter-pop input[type="checkbox"]',
3273		filter_input_text: '.b-filter-pop input[type="text"]',
3274		filter_popup: '.b-filter-pop',
3275		filter_popup_btn: '.b-filter-ul > li > .b-filter-li-ttl',
3276		filter_clear: '.b-filter-ul li.selected > .b-filter-li-ttl > .cross',
3277		filter_reset: '.b-filter-reset',
3278		complex_filter_field: '.js-complex-field',
3279		filter_color_ctrl: '.js-color-ctrl',
3280		filter_cover_ctrl: '.js-cover-ctrl'
3281	};
3282
3283	this.updateViewport = function(params, data){
3284		if(params.updateFilter !== false){
3285			this.root.html(data.filter);
3286			this.setAllCover();
3287			if ($.fn.uniform) {
3288				this.uniform(this.root);
3289			}
3290			this.updateFilterItems();
3291			if (window.initInteriorFilterContentCheckboxes) {
3292				initInteriorFilterContentCheckboxes();
3293			}
3294		}
3295	};
3296
3297	this.setAllCover = function(){
3298		var self = this;
3299		this.root.find(this.selectors.filter_cover_ctrl).each(function(){
3300			self.setCover($(this).data('cover'));
3301		});
3302	};
3303
3304	this.setCover = function(cover_id){
3305		var cover_ctrl = this.root.find(this.selectors.filter_cover_ctrl + '[data-cover=' + cover_id + ']');
3306		cover_ctrl.prop(
3307			'checked',
3308			this.root.find(this.selectors.filter_color_ctrl + '[data-cover=' + cover_id + ']:not(:checked)').length == 0
3309		);
3310		cover_ctrl.uniform();
3311	};
3312	
3313	this.uniform = function(obj){
3314		var inputs = obj.find('input[type="radio"], input[type="checkbox"]');
3315		if (inputs.length && $.fn.uniform) {
3316			inputs.uniform().filter('[data-color]').each(function(){
3317				$(this).parent().css('background-image', 'url("' + $(this).attr('data-color') + '")');
3318				$(this).parent().parent().addClass('g-color sm');
3319			});
3320		}
3321	};
3322
3323	this.updateFilterItems = function(){
3324		var self = this;
3325		this.root.find(this.selectors.filter_items).each(function(){
3326			self.updateFilterItemName($(this));
3327		});
3328	};
3329
3330	this.updateFilterItemName = function($li){
3331		var $li_name = $li.children('.b-filter-li-ttl');
3332		
3333		if($li.data('type') == 'price'){
3334			var $inputs = $li.find('input[type="text"]'),
3335				$min = $inputs.filter('[data-interval="min"]'),
3336				$max = $inputs.filter('[data-interval="max"]'),
3337				min_val = $min.val(),
3338				max_val = $max.val();
3339			
3340			if(!min_val && !max_val){
3341				$li.removeClass('selected');
3342				$li_name.html($li.data('name'));
3343			}else{
3344				$li.addClass('selected');
3345				if(min_val && max_val) $li_name.html(min_val + ' - ' + max_val + ' руб.');
3346				else if(min_val) $li_name.html('От ' + min_val + ' руб.');
3347				else $li_name.html('До ' + max_val + ' руб.');
3348				$li_name.append('<span class="cross"></span>');
3349			}
3350		}else{
3351			var $checked_inputs = $li.find('input:checked'),
3352				nSelected = $checked_inputs.length;
3353			
3354			if(nSelected <= 0){
3355				$li.removeClass('selected');
3356				$li_name.html($li.data('name'));
3357			}else{
3358				$li.addClass('selected');
3359				if(nSelected == 1) $li_name.html($checked_inputs.closest('label').text());
3360				else $li_name.html($li.data('name-r') + ': ' + nSelected);
3361				$li_name.append('<span class="cross"></span>');
3362			}
3363		}
3364	}
3365	
3366	this.updateFilterBtn = function(bActivate = ''){
3367		if(this.FilterBtnUpdatePause) return false;
3368		
3369		if(
3370			typeof this.FilterParams == 'undefined'
3371			|| bActivate === false
3372		)
3373			this.FilterParams = this.getFilterParams();
3374		
3375		if(bActivate === true) this.root.addClass('m-filter-pop-btn-visible');
3376		else if(bActivate === false) this.root.removeClass('m-filter-pop-btn-visible');
3377		else{
3378			if(this.FilterParams == this.getFilterParams()) this.root.removeClass('m-filter-pop-btn-visible');
3379			else this.root.addClass('m-filter-pop-btn-visible');
3380		}
3381	};
3382
3383	this.clearFilterItemInputs = function($li){
3384		this.FilterBtnUpdatePause = true;
3385		
3386		if($li.data('type') == 'price'){
3387			$li.find('input[type="text"]').val('');
3388		}else{
3389			var $checked_inputs = $li.find('input:checked');
3390			if($checked_inputs.length > 0) $checked_inputs.click().uniform();
3391		}
3392		
3393		this.FilterBtnUpdatePause = false;
3394	}
3395
3396	this.readonlyFilterInputsText = function(v){
3397		$inps = this.root.find(this.selectors.filter_input_text).prop('readonly', v);
3398	}
3399
3400	this.getFilterParams = function(){
3401		//topik: Пустые текстовые поля предварительно деактивируем, чтобы не передавать их в запросе формы.
3402		//topik [31.08.2018]: А потом включаем назад, т.к. фильтр больше не перезагружается.
3403		var result = '',
3404			$inps = this.root.find(this.selectors.filter_input_text);
3405		
3406		$inps.each(function(){
3407			if($(this).val() == '') $(this).prop('disabled', true);
3408		});
3409		
3410		var result = this.root.find('form').serialize();
3411		
3412		$inps.each(function(){
3413			if($(this).val() == '') $(this).prop('disabled', false);
3414		});
3415		
3416		return result;
3417	};
3418	
3419	this.setFilter = function(){
3420		var parent = this.parent,
3421			self = this;
3422		
3423		self.readonlyFilterInputsText(true);
3424		parent.loader.start({
3425			href: self.root.find('form').attr('action'),
3426			data: self.getFilterParams() + '&set_filter=Y',
3427			updateFilter: false,
3428			success: function(params, data){
3429				self.readonlyFilterInputsText(false);
3430				parent.updateViewport(params, data);
3431				self.updateFilterBtn(false);
3432			},
3433			error: function(params, data){
3434				self.readonlyFilterInputsText(false);
3435				parent.setEmptyCatalog(params, data);
3436			}
3437		});
3438	};
3439	
3440	this.bindEvents = function(){
3441		
3442		//topik: Открытие свёрнутого фильтра по кнопке.
3443		this.root.on('click', this.selectors.opener, function(e){
3444			this.root.addClass('open');
3445		}.bind(this));
3446		
3447		//topik: Комплексные поля фильтра (1 чекбокс отмечает несколько скрытых параметров).
3448		//	При этом не отмеченные скрытые параметры отключаются, чтобы не отправляться в запросе формы.
3449		this.root.on('change', this.selectors.complex_filter_field, function(e){
3450			e.preventDefault();
3451			var target = $(e.currentTarget);
3452			if(target.prop('checked')) $(target.attr('data-target')).prop('disabled', false).val(target.attr('data-value'));
3453			else $(target.attr('data-target')).prop('disabled', true).val('');
3454			this.updateFilterBtn();
3455		}.bind(this));
3456
3457		//topik: Поля цвета для фильтра.
3458		this.root.on('change', this.selectors.filter_color_ctrl, function(e){
3459			e.preventDefault();
3460			this.setCover($(e.currentTarget).data('cover'));
3461			this.updateFilterItemName(this.root.find(this.selectors.filter_cover_ctrl).first().closest('li'));
3462			this.updateFilterBtn();
3463		}.bind(this));
3464
3465		//topik: Поля покрытия для фильтра.
3466		this.root.on('change', this.selectors.filter_cover_ctrl, function(e){
3467			e.preventDefault();
3468			var target = $(e.currentTarget);
3469			var cover_id = target.data('cover');
3470			var color_ctrl = this.root.find(this.selectors.filter_color_ctrl + '[data-cover=' + cover_id + ']');
3471			if(target.prop('checked')){
3472				color_ctrl.prop('checked', true);
3473				color_ctrl.parent().addClass('checked');
3474			} else {
3475				color_ctrl.prop('checked', false);
3476				color_ctrl.parent().removeClass('checked');
3477			}
3478			this.updateFilterItemName(color_ctrl.first().closest('li'));
3479			this.updateFilterBtn();
3480		}.bind(this));
3481		
3482		//topik: Открытие и закрытие всплывающих окошек фильтра.
3483		this.root.on('click', this.selectors.filter_popup_btn, function(e){
3484			e.preventDefault();
3485			
3486			var $target = $(e.currentTarget),
3487				$li = $target.parent(),
3488				$li_list = this.root.find(this.selectors.filter_items),
3489				self = this;
3490			
3491			if(!$li.hasClass('opened') && !$li.hasClass('disabled')){
3492				$li.addClass('opened');
3493				
3494				setTimeout(function(){
3495					$('body').on('click.filter-opener', function(e){
3496						if($(e.target).closest(self.selectors.filter_popup).length == 0 && !$(e.target).is(self.selectors.filter_popup)){
3497							$li.removeClass('opened');
3498							$('body').off('click.filter-opener');
3499						}
3500					});
3501				},100);
3502			}
3503		}.bind(this));
3504		
3505		//topik: Клик по чекбоксам.
3506		this.root.on('click', this.selectors.filter_input_check, function(e){
3507			this.updateFilterItemName($(e.currentTarget).closest('li'));
3508			this.updateFilterBtn();
3509		}.bind(this));
3510		
3511		//topik: Работа с текстовыми инпутами.
3512		this.root.on('input', this.selectors.filter_input_text, function(e){
3513			var $target = $(e.currentTarget),
3514				$li = $target.closest('li'),
3515				val = $target.val().toString(),
3516				preval = $target.data('val').toString();
3517			
3518			val = parseInt(val.replace(/[^-0-9]/gim, ''));
3519			preval = parseInt(preval.replace(/[^-0-9]/gim, ''));
3520			
3521			if(!preval) preval = '';
3522			if(val <= 0 || isNaN(val)) val = '';
3523			$target.val(val).data('val', val);
3524			
3525			if(val != preval){
3526				var $inputs = $li.find('input[type="text"]'),
3527					$min = $inputs.filter('[data-interval="min"]'),
3528					$max = $inputs.filter('[data-interval="max"]'),
3529					$error = $li.find('.error');
3530				
3531				this.updateFilterItemName($li);
3532				
3533				if($min.val() && $max.val() && parseInt($min.val()) >= parseInt($max.val())){
3534					this.updateFilterBtn(false);
3535					$error.slideDown(200);
3536				} else {
3537					this.updateFilterBtn();
3538					$error.slideUp(200);
3539				}
3540			}
3541		}.bind(this));
3542		
3543		//topik: Очистка установленного свойства фильтра.
3544		this.root.on('click', this.selectors.filter_clear, function(e){
3545			e.preventDefault();
3546			e.stopPropagation();
3547			var $li = $(e.currentTarget).closest('li');
3548			this.clearFilterItemInputs($li);
3549			this.updateFilterItems();
3550			this.setFilter();
3551			this.root.removeClass('open');
3552		}.bind(this));
3553		
3554		//topik: Сброс параметров фильтра.
3555		this.root.on('click', this.selectors.filter_reset, function(e){
3556			e.preventDefault();
3557			var self = this;
3558			this.root.find(this.selectors.filter_items).each(function(){
3559				self.clearFilterItemInputs($(this));
3560			});
3561			this.updateFilterItems();
3562			this.setFilter();
3563		}.bind(this));
3564		
3565		//topik: Применить фильтр.
3566		this.root.on('click', this.selectors.set_filter, function(e){
3567			e.preventDefault();
3568			this.setFilter();
3569			this.root.removeClass('open');
3570			return false;
3571		}.bind(this));
3572
3573		this.root.on('goto_url', this.selectors.set_filter_url, function(e){
3574			e.preventDefault();
3575			var self = this;
3576			var parent = this.parent;
3577			var $form = $('.smartfilter');
3578			var url = $form.attr('action');
3579			var clearFilter = !!(e.detail.url_type && (e.detail.url_type === 'delete'));
3580			var data = e.detail.url_data
3581				? e.detail.url_data
3582				: (clearFilter ? 'del_filter=Y' : ($form.serialize() + '&set_filter=Y'));
3583			if (e.detail.url) {
3584				url = e.detail.url;
3585			}
3586			parent.loader.start({
3587				href: url,
3588				data: data,
3589				updateFilter: clearFilter,
3590				success: function(params, data){
3591					let event = new CustomEvent("filter_applied", {
3592						bubbles: true,
3593					});
3594					self.root[0].dispatchEvent(event);
3595
3596					parent.updateViewport(params, data);
3597				},
3598				error: function(params, data){
3599					parent.setEmptyCatalog(params, data);
3600				}
3601			});
3602		}.bind(this));
3603
3604	};
3605
3606	this.init = function(){
3607		this.bindEvents();
3608		this.uniform(this.root);
3609		this.setAllCover();
3610		this.updateFilterItems();
3611		this.updateFilterBtn(false);
3612	};
3613	this.init();
3614};
3615
3616//сортировка каталога товаров
3617$$.catalogSorting = function(parent){
3618	this.parent = parent;
3619	this.root = $('#b-sorting');
3620
3621	this.selectors = {
3622		sort: '.b-sorting-sort',
3623		pagecount: '.b-sorting-pagecount',
3624	};
3625
3626	this.updateViewport = function(params, data){
3627		this.root.html(data.sorting);
3628		this.updateItems();
3629	};
3630
3631	this.updateItems = function(){
3632		var $sort = this.root.find(this.selectors.sort),
3633			$pagecount = this.root.find(this.selectors.pagecount);
3634		
3635		if($sort.length){
3636			var $div = $('<div>'), $span = $('<span>');
3637			$sort.html('Сортировать по:');
3638			$.each($sort.data('content'), function(index, el){
3639				var $new = $(el.active ? '<b>' + el.name + '</b>' : '<u data-href="' + el.href + '">' + el.name + '</u>');
3640				if(el.cssclass) $new.addClass(el.cssclass);
3641				if(el.active) $div.append($new.clone());
3642				$span.append($new);
3643			});
3644			$sort.append($div.append($span));
3645		}
3646		
3647		if($pagecount.length){
3648			var $div = $('<div>'), $span = $('<span>');
3649			$pagecount.html('Показывать:');
3650			$.each($pagecount.data('content'), function(index, el){
3651				if(el.active) $div.append('<b>' + el.name + '</b>');
3652				$span.append(el.active ? '<b>' + el.name + '</b>' : '<u data-href="' + el.href + '">' + el.name + '</u>');
3653			});
3654			$pagecount.append($div.append($span));
3655		}
3656	};
3657	
3658	this.setSorting = function(e){
3659		e.preventDefault();
3660		var parent = this.parent;
3661		var target = $(e.currentTarget);
3662		parent.loader.start({
3663			href: target.attr('data-href'),
3664			data: '',
3665			success: function(params, data){
3666				parent.updateViewport(params, data);
3667			}
3668		});
3669	};
3670	
3671	this.bindEvents = function(){
3672		//сортировка и количество выводимых элементов
3673		this.root.on('click', this.selectors.sort + ' u', this.setSorting.bind(this));
3674		this.root.on('click', this.selectors.pagecount + ' u', this.setSorting.bind(this));
3675	};
3676
3677	this.init = function(){
3678		this.bindEvents();
3679		this.updateItems();
3680	};
3681	this.init();
3682};
3683
3684//левое меню каталога
3685$$.sideCatalog = function(root){
3686	this.root = root;
3687
3688	this.nodes = {
3689		exps: root.find('.b-catalog-side-l-sect--exp')
3690	};
3691
3692	this.selectors = {
3693		sect_title: '.b-side-b-title'
3694	};
3695	
3696	this.classes = {
3697		sect_cont: 'b-catalog-side-l-sect-cont',
3698	};
3699
3700	this.initExps = function(){
3701		var self = this;
3702		this.nodes.exps.each(function(){
3703			var $sect = $(this),
3704				$title = $sect.children(self.selectors.sect_title);
3705				
3706			$sect.wrapInner('<div class="' + self.classes.sect_cont + '"></div>').prepend($title);
3707			var $cont = $sect.children('.' + self.classes.sect_cont);
3708			
3709			if($sect.hasClass('closed')) $cont.hide();
3710			$title.click(function(){self.toggleSect($sect, $cont);});
3711		});
3712	};
3713
3714	this.toggleSect = function($sect, $cont){
3715		if(typeof $cont == 'undefined') $cont = $sect.children('.' + self.classes.sect_cont);
3716		
3717		$cont.animate({height: 'toggle', opacity: 'toggle'}, 200, 'swing');
3718		$sect.toggleClass('closed');
3719	}
3720	
3721	this.init = function(){
3722		this.initExps();
3723	};
3724
3725	this.init();
3726};
3727
3728//карточка двери
3729$$.doorDetail = function(root, params){
3730	this.variable = 'door_detail';
3731    this.root = root;
3732    this.quickview = (params && params.quickview == true) ? true : false;
3733
3734	this.selectors = {
3735		door: '#b-door',
3736		popup_info: '.js-popup-info',
3737		other_offers: '.js-other_offers li',
3738		param_selector: '.js-param-selector',
3739		block_dropdown: '.js-block-dropdown',
3740		accss_input: '.js-accss-input',
3741		accss_selector: '.js-accss-selector',
3742		block_buy: '.js-b-buy',
3743		quantity: '.js-quantity input',
3744		price: '.js-price',
3745		viewed: '#b-door-prods-viewed'
3746	};
3747
3748    this.nodes = {
3749        header: this.quickview ? this.root.parent().children('.h1') : $('h1'),
3750        door_furniture: this.quickview ? false : new $$.commonCatalogSwitcher($('#b-door-furniture')),
3751    };
3752
3753    this.loading = false;
3754    this.loader = new $$.ajaxLoader(this);
3755
3756    this.updateViewport = function(params, data, bHistory){
3757        if(data.door !== undefined){
3758			this.root.html(data.door);
3759			this.nodes.door_furniture = this.quickview ? false : new $$.commonCatalogSwitcher($('#b-door-furniture'));
3760            this.root.find('select').not('.select-picker').not('.b-select-native').selectbox();
3761        }
3762        if(data.header !== undefined){
3763            this.nodes.header.html(data.header);
3764        }
3765        if(data.viewed !== undefined){
3766            $(this.selectors.viewed).html(data.viewed);
3767        }
3768
3769		this.productProcess(params, data, bHistory);
3770		if(!this.quickview && this.TITLE)
3771			document.title = this.TITLE;
3772		// Заполнение query для истории
3773		// if(this.URL !== params.href) this.URL = params.href;
3774		
3775		if(!this.quickview)
3776			$$.history.pushState(this, params, data);	//HISTORY_COMMENT раскомментировать для использования истории.
3777    };
3778	
3779	this.initProductData = function(){
3780		this.nodes.door = $(this.selectors.door);
3781		
3782		if(this.ID) this.prev_ID = this.ID;
3783		if(this.OFFER_ID) this.prev_OFFER_ID = this.OFFER_ID;
3784		
3785		this.ID = this.nodes.door.data('id');
3786		this.OFFER_ID = this.nodes.door.data('offer');
3787		this.URL = this.nodes.door.data('url');
3788		this.TITLE = this.nodes.door.data('title');
3789	};
3790	
3791	this.initBlocks = function(){
3792		if(this.arBlocksOpened === undefined) this.arBlocksOpened = [];
3793		
3794		$.each(this.arBlocksOpened, function(index, value){
3795			var $block = $('#' + value);
3796			$block.addClass('no-transition');
3797			$block.removeClass('collapsed').children('.b-block-content').prop('style', '');
3798			setTimeout(function(){$block.removeClass('no-transition');}, 100);
3799		});
3800	};
3801	
3802	this.productProcess = function(params, data, bHistory){
3803		this.initProductData();
3804		this.initBlocks();
3805		window.site && site.sliders();
3806		
3807		if(bHistory !== true && this.prev_OFFER_ID !== this.OFFER_ID)
3808			$$.metrika.viewProduct(this.nodes.door);
3809	};
3810	
3811    this.bindEvents = function(){
3812		
3813		this.root.on('click', this.selectors.other_offers, function(e){
3814			e.preventDefault();
3815			var $target = $(e.currentTarget);
3816			
3817			if(!$target.hasClass('active')){
3818				$target.parent().children('li').removeClass('active');
3819				$target.addClass('active');
3820				$('#'+$target.data('target')).val($target.data('value')).change();
3821			}
3822		}.bind(this));
3823		
3824        this.root.on('click', this.selectors.popup_info, function(e){
3825            e.preventDefault();
3826			
3827			var $target = $(e.currentTarget);
3828			$.fancybox.open({
3829				src: '#' + $target.data('source'),
3830				type: 'inline',
3831				baseClass: 'fancybox-bg-light'
3832			});
3833        }.bind(this));
3834
3835        this.root.on('click', this.selectors.block_dropdown, function(e){
3836            e.preventDefault();
3837			
3838			var $target = $(e.currentTarget),
3839				$block = $target.parent(),
3840				block_id = $block.prop('id');
3841			
3842			if($block.hasClass('collapsed')) this.arBlocksOpened.push(block_id);
3843			else this.arBlocksOpened.splice($.inArray(this.arBlocksOpened, block_id), 1);
3844			
3845			$block.toggleClass('collapsed').children('.b-block-content').animate({height: 'toggle', opacity: 'toggle'}, 300, 'swing');
3846        }.bind(this));
3847		
3848        this.root.on('change', this.selectors.param_selector, function(e){
3849            var target = $(e.currentTarget);
3850            var self = this;
3851			var url = this.URL;
3852			var form = this.root.find('form');
3853			var formData = form.serialize();
3854			var selectedOptions = form.find('option[data-set-url="1"]:selected');
3855
3856			var queryPos = url.search(/\?/);
3857			if (queryPos !== -1) {
3858				url = url.substr(0, queryPos);
3859			}
3860			if (selectedOptions.length) {
3861				selectedOptions.each(function() {
3862					var $select = $(this).closest('select');
3863					var inputName = $select.attr('name');
3864					var inputValue = $select.val();
3865					var inputStr = inputName+'='+inputValue;
3866					formData = formData.replace('&'+inputStr+'&', '&');
3867					formData = formData.replace(inputStr+'&', '');
3868					formData = formData.replace('&'+inputStr, '');
3869					if (url.search(/\?/) === -1) {
3870						url = url + '?';
3871					}
3872					else {
3873						url = url + '&';
3874					}
3875					url = url + inputStr;
3876				});
3877			}
3878            this.loader.start({
3879                href: url,
3880                data: formData + '&DOOR_ID=' + this.ID + '&PRM_CHANGED=' + target.attr('name'),
3881                success: function(params, data){
3882                    self.updateViewport(params, data);
3883                }
3884            });
3885        }.bind(this));
3886		
3887        this.root.on('click', this.selectors.accss_selector, function(e){
3888            var $target = $(e.currentTarget);
3889			
3890			if(!$target.hasClass('active')){
3891				var $block = $target.closest('.b-block'),
3892					$input = $block.find(this.selectors.accss_input);
3893				var self = this;
3894				
3895				$input.val($target.data('accss-el-id'));
3896				$block.find(this.selectors.accss_selector).removeClass('active');
3897				$target.addClass('active');
3898				
3899				this.loader.start({
3900					href: this.URL,
3901					data: this.root.find('form').serialize() + '&DOOR_ID=' + this.ID + '&PRM_CHANGED=' + $input.attr('name'),
3902					success: function(params, data){
3903						self.updateViewport(params, data);
3904					}
3905				});
3906			}
3907        }.bind(this));
3908		
3909        this.root.on('blur', this.selectors.quantity, function(e){
3910			var $qt = $(e.currentTarget),
3911				val = parseInt($qt.val()),
3912				preval = parseInt($qt.data('qt'));
3913			
3914			if(val <= 0 || isNaN(val)) val = preval;
3915			$qt.data('qt', val).val(val);
3916			
3917			if(val !== preval){
3918				if($qt.data('update')){
3919					var self = this;
3920					
3921					this.loader.start({
3922						href: this.URL,
3923						data: this.root.find('form').serialize() + '&DOOR_ID=' + this.ID,
3924						success: function(params, data){
3925							self.updateViewport(params, data);
3926						}
3927					});
3928				}else{
3929					var $block = $qt.closest(this.selectors.block_buy),
3930						$price = $block.find(this.selectors.price),
3931						$btn = $block.find($$.obj_controls.selectors.add2cart);
3932					
3933					$price.html($$.obj_controls.number_format(parseInt($price.data('price-unit')) * val, 0, '.', ' '));
3934					$btn.data('qt', val);
3935				}
3936			}
3937        }.bind(this));
3938
3939    };
3940
3941	this.getData = function(){
3942		return {
3943			door: this.root.html(),
3944			header: this.nodes.header.html()
3945		};
3946	};
3947	
3948    this.init = function(){
3949        this.productProcess();
3950		this.bindEvents();
3951    };
3952    this.init();
3953};
3954
3955//карточка молдинга
3956$$.moldingDetail = function(root, params){
3957	this.variable = 'molding_detail';
3958    this.root = root;
3959    this.quickview = (params && params.quickview == true) ? true : false;
3960
3961	this.selectors = {
3962		door: '#b-door',
3963		popup_info: ".js-popup-info",
3964		param_selector: '.js-param-selector',
3965		block_buy: '.js-b-buy',
3966		quantity: '.js-quantity input',
3967		price: '.js-price',
3968		viewed: '#b-door-prods-viewed'
3969	};
3970
3971    this.nodes = {
3972        header: this.quickview ? this.root.parent().children('.h1') : $('h1'),
3973        door_furniture: this.quickview ? false : new $$.commonCatalogSwitcher($('#b-door-furniture')),
3974    };
3975
3976    this.loading = false;
3977    this.loader = new $$.ajaxLoader(this);
3978
3979	this.arrayIntersection = function(array1, array2) {
3980		return array1.filter(function(n) {
3981			return array2.indexOf(n) !== -1;
3982		});
3983	}
3984
3985    this.updateViewport = function(params, data, bHistory){
3986        if(data.door !== undefined){
3987			this.root.html(data.door);
3988			this.nodes.door_furniture = this.quickview ? false : new $$.commonCatalogSwitcher($('#b-door-furniture'));
3989            this.root.find('select').not('.select-picker').not('.b-select-native').selectbox();
3990        }
3991        if(data.header !== undefined){
3992            this.nodes.header.html(data.header);
3993        }
3994        if(data.viewed !== undefined){
3995            $(this.selectors.viewed).html(data.viewed);
3996        }
3997
3998		this.productProcess(params, data, bHistory);
3999		if(!this.quickview && this.TITLE)
4000			document.title = this.TITLE;
4001		
4002		if(!this.quickview)
4003			$$.history.pushState(this, params, data);	//HISTORY_COMMENT раскомментировать для использования истории.
4004    };
4005	
4006	this.initProductData = function(){
4007		this.nodes.door = $(this.selectors.door);
4008		
4009		if(this.ID) this.prev_ID = this.ID;
4010		if(this.OFFER_ID) this.prev_OFFER_ID = this.OFFER_ID;
4011		
4012		this.ID = this.nodes.door.data('id');
4013		this.OFFER_ID = this.nodes.door.data('offer');
4014		this.URL = this.nodes.door.data('url');
4015		this.TITLE = this.nodes.door.data('title');
4016		this.COLOR = this.nodes.door.data('color');
4017	};
4018	
4019	this.initBlocks = function(){
4020		if(this.arBlocksOpened === undefined) this.arBlocksOpened = [];
4021		
4022		$.each(this.arBlocksOpened, function(index, value){
4023			var $block = $('#' + value);
4024			$block.addClass('no-transition');
4025			$block.removeClass('collapsed').children('.b-block-content').prop('style', '');
4026			setTimeout(function(){$block.removeClass('no-transition');}, 100);
4027		});
4028
4029		var $prices = $('.b-buy-price');
4030		var $selectedPrice = $prices.filter(`[data-offer-id='${this.OFFER_ID}']`);
4031		$prices.not($selectedPrice).hide();
4032		$selectedPrice.show();
4033
4034		var $imgs = $('.b-door-img [data-offer-id]');
4035		var $selectedImg = $imgs.filter(`[data-offer-id='${this.OFFER_ID}']`);
4036		$imgs.not($selectedImg).hide();
4037		$selectedImg.fadeIn(500);
4038
4039		$(this.selectors.block_buy).find('.js-add2cart').each(function() {
4040			var buyBtn = $(this);
4041			buyBtn.attr('data-add', '{"'+this.OFFER_ID+'":1}');
4042			buyBtn.attr('data-properties', '{"'+this.OFFER_ID+'":{"color":"'+this.COLOR+'"}}');
4043		});
4044	};
4045	
4046	this.productProcess = function(params, data, bHistory){
4047		this.initProductData();
4048		this.initBlocks();
4049		window.site && site.sliders();
4050		
4051		if(bHistory !== true && this.prev_OFFER_ID !== this.OFFER_ID)
4052			$$.metrika.viewProduct(this.nodes.door);
4053	};
4054	
4055    this.bindEvents = function(){
4056		var self = this;
4057
4058		this.root.on('click', this.selectors.popup_info, function(e){
4059            e.preventDefault();
4060			
4061			var $target = $(e.currentTarget);
4062			$.fancybox.open({
4063				src: '#' + $target.data('source'),
4064				type: 'inline',
4065				baseClass: 'fancybox-bg-light'
4066			});
4067        }.bind(this));
4068
4069        this.root.on('change', this.selectors.param_selector, function(e){
4070            var target = $(e.currentTarget);
4071			// console.log(target.attr('name'));
4072			if (target.attr('name') == 'door_cover') {
4073				var offerIds = $(target).find('option:selected').data('offerIds') || [];
4074				var $selectLinked = $('#door_color');
4075				var $options = $selectLinked.find('option');
4076				var $activeOptions = $options.filter(function() {
4077					var colorOfferId = $(this).data('offerIds');
4078					return self.arrayIntersection(colorOfferId, offerIds).length > 0;
4079				});
4080				$activeOptions.prop('disabled', false);
4081				$options.not($activeOptions).prop('disabled', true);
4082				$selectLinked.trigger('refresh');
4083
4084				var $options2 = $selectLinked.find('option').not(':disabled');
4085				if (!$options2.filter(':selected').length) {
4086					$selectLinked.find('option:selected').prop('selected', false);
4087					$options2.eq(0).prop('selected', true);
4088				}
4089				$selectLinked.trigger('change');
4090				$selectLinked.trigger('input');
4091				$selectLinked.trigger('refresh');
4092			}
4093			if (target.attr('name') == 'door_color') {
4094				var $selectedOption = $(target).find('option:selected');
4095				var offerIds = $selectedOption.data('offerIds') || '';
4096				if (offerIds.length) {
4097					this.OFFER_ID = offerIds[0];
4098					this.COLOR = $selectedOption.text().trim();
4099				}
4100				
4101				var $selectLinked = $('#door_flaps');
4102				if (!$selectLinked.length) {
4103					this.initBlocks();
4104				}
4105				else {
4106					var $options = $selectLinked.find('option');
4107					var $activeOptions = $options.filter(function() {
4108						var flapOfferId = $(this).data('offerIds');
4109						return self.arrayIntersection(flapOfferId, offerIds).length > 0;
4110					});
4111					$activeOptions.prop('disabled', false);
4112					$options.not($activeOptions).prop('disabled', true);
4113					$selectLinked.trigger('refresh');
4114					
4115					var $options2 = $selectLinked.find('option').not(':disabled');
4116					if (!$options2.filter(':selected').length) {
4117						$selectLinked.find('option:selected').prop('selected', false);
4118						$options2.eq(0).prop('selected', true);
4119					}
4120					$selectLinked.trigger('change');
4121					$selectLinked.trigger('input');
4122					$selectLinked.trigger('refresh');
4123				}
4124				// console.log(target.data());
4125			}
4126			if (target.attr('name') == 'door_flaps') {
4127				var offerIds = $(target).find('option:selected').data('offerIds') || [];
4128				var colorOfferIds = $('#door_color option:selected').data('offerIds') || '';
4129				var newOfferIds =  self.arrayIntersection(colorOfferIds, offerIds);
4130				this.OFFER_ID = newOfferIds[0] || 0;
4131				this.initBlocks();
4132			}
4133			
4134			// debugger;
4135            // this.loader.start({
4136            //     href: this.URL,
4137            //     data: this.root.find('form').serialize() + '&DOOR_ID=' + this.ID + '&PRM_CHANGED=' + target.attr('name'),
4138            //     success: function(params, data){
4139            //         self.updateViewport(params, data);
4140            //     }
4141            // });
4142        }.bind(this));
4143		
4144        this.root.on('blur', this.selectors.quantity, function(e){
4145			var $qt = $(e.currentTarget),
4146				val = parseInt($qt.val()),
4147				preval = parseInt($qt.data('qt'));
4148			
4149			if(val <= 0 || isNaN(val)) val = preval;
4150			$qt.data('qt', val).val(val);
4151			
4152			if(val !== preval){
4153				if($qt.data('update')){
4154					var self = this;
4155					
4156					this.loader.start({
4157						href: this.URL,
4158						data: this.root.find('form').serialize() + '&DOOR_ID=' + this.ID,
4159						success: function(params, data){
4160							self.updateViewport(params, data);
4161						}
4162					});
4163				}else{
4164					var $block = $qt.closest(this.selectors.block_buy),
4165						$price = $block.find(this.selectors.price),
4166						$btn = $block.find($$.obj_controls.selectors.add2cart);
4167					
4168					$price.html($$.obj_controls.number_format(parseInt($price.data('price-unit')) * val, 0, '.', ' '));
4169					$btn.data('qt', val);
4170				}
4171			}
4172        }.bind(this));
4173
4174		$('#door_cover').trigger('change');
4175    };
4176
4177	this.getData = function(){
4178		return {
4179			door: this.root.html(),
4180			header: this.nodes.header.html()
4181		};
4182	};
4183	
4184    this.init = function(){
4185        this.productProcess();
4186		this.bindEvents();
4187    };
4188    this.init();
4189};
4190
4191
4192//табы фурнитуры
4193$$.commonCatalogSwitcher = function(root){
4194    this.root = root;
4195
4196    this.nodes = {
4197        tabs: root.find('.js-cc-tab'),
4198        catalog: new $$.commonCatalog($('#b-door-furniture-catalog'))
4199    };
4200
4201    this.updateViewport = function(params, data){
4202        this.nodes.catalog.updateViewport(params, data);
4203    };
4204
4205    this.bindEvents = function(){
4206        this.nodes.tabs.on('click', function(e){
4207            e.preventDefault();
4208			
4209			this.root.addClass('active');
4210			
4211			var $target = $(e.currentTarget);
4212			if($target.hasClass('active')) return;
4213            
4214			this.nodes.tabs.removeClass('active');
4215			$target.addClass('active');
4216
4217			var self = this;
4218            this.nodes.catalog.loader.start({
4219				add: false,
4220				scroll: false,
4221                href: '/mezhkomnatnye-dveri/catalog_parts/door_furniture.php',
4222                data: 'CATALOG_ID=' + $target.data('id'),
4223                success: function(params, data){
4224                    self.updateViewport(params, data);
4225                }
4226            });
4227
4228        }.bind(this));
4229    };
4230
4231    this.init = function(){
4232		this.bindEvents();
4233    };
4234    this.init();
4235};
4236
4237
4238//topik [18.12.2017]: Постраничная навигация.
4239//-----{
4240$$.pageNav = function(root){
4241	this.variable = 'b_page';
4242	this.root = root;
4243
4244	this.selectors = {
4245		pagenav: '.b-pagenav',
4246		pagenav_selector: '.js-pagenav',
4247		pagenav_shown: '.b-pagelist-shown span'
4248	};
4249
4250	this.nodes = {
4251		header: $('h1'),
4252		elements: this.root.find('.'+this.root.attr('id')+'-list')
4253	}
4254	this.nodes.siblings = this.nodes.elements.siblings();
4255	
4256	this.loading = false;
4257	this.loader = new $$.ajaxLoader(this);
4258	
4259	this.updateViewport = function(params, data){
4260
4261		if(data.content !== undefined){
4262			var $content = $(data.content);
4263			
4264			this.nodes.siblings.each(function(){
4265				var $target = $(this).removeClass('active'),
4266					$packet = $content.filter('.'+$target.attr('class').replace(' ', '.'));
4267				
4268				$target.html($packet.length ? $packet.html() : '');
4269			});
4270			
4271			$new_items = $($content.filter('.'+this.nodes.elements.attr('class').replace(' ', '.')).html());
4272			if($new_items.length){
4273				if(!params.add) this.nodes.elements.html($new_items);
4274				else{
4275					$new_items.hide();
4276					this.nodes.elements.append($new_items);
4277					$new_items.slideDown(300);
4278				}
4279				
4280				this.updateItems($new_items);
4281				
4282				$pagenav_shown = this.nodes.siblings.find(this.selectors.pagenav_shown);
4283				if($pagenav_shown.length) $pagenav_shown.html(this.nodes.elements.children().length);
4284			}
4285		};
4286		
4287		if(data.title) document.title = data.title;
4288		
4289		if(params.scroll){
4290			$$.obj_controls.scrollTo($('#b-content').offset().top + 1, 0, {ignore_fixed_header: true});
4291		}
4292		
4293		$$.history.pushState(this, params, data);
4294	};
4295	
4296	this.updateItems = function($items){
4297		if(!$items) $items = this.nodes.elements.children();
4298		$items.each(function(){
4299			var $li = $(this),
4300				$li_img = $li.find('.b-news-list-img'),
4301				$li_content = $li.find('.b-news-list-content'),
4302				$btn_more = $li_content.find('btn');
4303			
4304			if(!$btn_more.length){
4305				var href = $li_content.find('.b-news-list-name a').attr('href');
4306				$li_content.append('<a href="'+href+'" class="btn">Подробнее</a>');
4307				if($li.hasClass('m-has-img'))
4308					$li_img.replaceWith('<a href="'+href+'" class="b-news-list-img">'+$li_img.html()+'</a>');
4309			}
4310		});
4311	};
4312
4313	this.bindEvents = function(){
4314	
4315		this.root.on('click', this.selectors.pagenav_selector, function(e){
4316			e.preventDefault();
4317			var $target = $(e.currentTarget),
4318				url = $target.attr('href') || $target.data('href') || null,
4319				add = $target.data('add') ? true : false,
4320				self = this;
4321
4322			this.loader.start({
4323				add: add,
4324				scroll: !add,
4325				href: url,
4326				data: '',
4327				success: function(params, data){
4328					self.URL = url;
4329					self.updateViewport(params, data);
4330				}
4331			});
4332		}.bind(this));		
4333	
4334		this.root.on('click', '.b-page-menu li.active u', function(e){
4335			e.preventDefault();
4336			var $target = $(e.currentTarget),
4337				self = this;
4338
4339			$target.closest('.b-page-menu').toggleClass('active');
4340		}.bind(this));
4341		
4342	};
4343
4344	this.getData = function(){
4345		return {
4346			content: this.root.html(),
4347			title: document.title
4348		};
4349	};
4350	
4351	this.init = function(){
4352		this.bindEvents();
4353		this.updateItems();
4354	};
4355	this.init();
4356}
4357//-----}
4358
4359//-----{
4360//-----}
4361
4362//-----{
4363//-----}
4364
4365$(function(){
4366	$$.obj_controls = new $$.controls();
4367	$$.history = new $$._history();
4368	
4369	var $catalog_side = $('#b-catalog-side');
4370	if($catalog_side.length) $$.catalog_side = new $$.sideCatalog($catalog_side);
4371	
4372	$obj = $('#b-door-detail');
4373	if($obj.length){
4374		$$.door_detail = new $$.doorDetail($obj);
4375		if (!/clear_cache=Y/.test(location.search)) {
4376			// $$.history.initState($$.door_detail);
4377		}
4378	}
4379	$obj = $('#b-catalog-doors');
4380	if($obj.length){
4381		$$.catalog = new $$.doorCatalog($obj);
4382		//$$.history.initState($$.catalog);
4383	}
4384	$obj = $('#b-catalog-common');
4385	if($obj.length){
4386		$$.catalog_common = new $$.commonCatalog($obj);
4387		// $$.history.initState($$.catalog_common);
4388	}
4389	$obj = $('#b-molding-detail');
4390	if($obj.length){
4391		$$.molding_detail = new $$.moldingDetail($obj);
4392		// $$.history.initState($$.door_detail);
4393	}
4394	
4395	$('.b-doors').each(function(index, el){$$.doorList($(el));});
4396	
4397	$obj = $('#b-news');
4398	if($obj.length){
4399		$$.b_page = new $$.pageNav($obj);
4400		$$.history.initState($$.b_page);
4401	}
4402	
4403	$$.obj_basket_order = new $$.basketOrder($('.js-basket-order'));
4404});
4405/* End */
4406;
4407; /* Start:"a:4:{s:4:"full";s:66:"/local/templates/portaprima/js/catalogAnalytics.js?178403931620035";s:6:"source";s:50:"/local/templates/portaprima/js/catalogAnalytics.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
4408// Аналитика каталога: Яндекс.Метрика / dataLayer, VK Retargeting, GA e-commerce.
4409// Вынесено из commonCatalog_new.js: это независимый слой, каталог работает и без него
4410// (например, при ?analitic_scripts=disable_all файл можно просто не подключать -
4411// в commonCatalog_new.js есть заглушка $$.metrika, поэтому вызовы не упадут).
4412//
4413// Связь односторонняя: каталог зовёт $$.metrika.*, а vk_ecomm/ga_ecomm дёргает уже она сама.
4414
4415var $$ = $$ || {};
4416
4417// --- Мини-хелперы вместо jQuery ---------------------------------------------------
4418// Каталог (commonCatalog_new.js) пока не мигрирован и передаёт сюда jQuery-объекты,
4419// поэтому вход нормализуем: принимаем и jQuery-обёртку, и обычный DOM-элемент.
4420function anEl(node) {
4421	if (!node) return null;
4422	return node.jquery ? node[0] : node;
4423}
4424
4425function anEls(nodes) {
4426	if (!nodes) return [];
4427	if (nodes.jquery) return Array.prototype.slice.call(nodes.get());
4428	if (nodes instanceof Element) return [nodes];
4429	return Array.prototype.slice.call(nodes);
4430}
4431
4432// ВАЖНО: jQuery .data() приводит типы ("12345" -> 12345, "true" -> true), а dataset
4433// отдаёт строки. Для dataLayer/GA цена обязана быть числом, иначе e-commerce ломается.
4434// Повторяем поведение jQuery.
4435function anData(node, key) {
4436	var el = anEl(node);
4437	if (!el) return undefined;
4438
4439	var raw = el.getAttribute('data-' + key);
4440	if (raw === null) return undefined;
4441	if (raw === '') return '';
4442	if (raw === 'true') return true;
4443	if (raw === 'false') return false;
4444	if (raw === 'null') return null;
4445
4446	// Число - только если строка ровно им и является (иначе "8 800..." станет 8).
4447	var num = Number(raw);
4448	if (raw.trim() !== '' && !isNaN(num) && String(num) === raw.trim()) return num;
4449
4450	if (raw[0] === '{' || raw[0] === '[') {
4451		try { return JSON.parse(raw); } catch (e) { /* не JSON - вернём строкой */ }
4452	}
4453	return raw;
4454}
4455
4456function anSetData(node, key, value) {
4457	var el = anEl(node);
4458	if (el) el.setAttribute('data-' + key, value);
4459}
4460// ----------------------------------------------------------------------------------
4461
4462$$._metrika = function(){
4463	// this.id = 22603441;
4464	this.id = '';
4465	this.YaCounters = [];
4466	
4467	this.selectors = {
4468		product : '.js-datalayer-product',
4469		product_click : '.js-datalayer-product-click'
4470	};
4471	
4472	this.products = [];
4473	
4474	window.dataLayer = window.dataLayer || [];
4475	
4476	var self = this;
4477	
4478	//topik [25.01.2021]: Метод отправляет заявку Comagic, только когда сам скрипт Comagic подключен.
4479	//	Событие может отправляться при загрузке страницы, но скрипт сервиса в этот момент может быть ещё не загружен.
4480	//-----{
4481	this.ComagicAddRequest = function(obj_raw){
4482		var obj = {name: '', email: '', phone: '', message: ''};
4483		for(var i in obj_raw) obj[i] = obj_raw[i];
4484		
4485		if(typeof Comagic !== 'undefined' && typeof Comagic.addOfflineRequest === 'function'){
4486			Comagic.addOfflineRequest(obj);
4487			console.log(obj);
4488		}
4489		else{
4490			setTimeout(function(){ this.ComagicAddRequest(obj); }.bind(this), 700);
4491		}
4492	}
4493	//-----}
4494	
4495	//topik [16.08.2020]: Метод для получения номера текущего счетчика Яндекс.Метрики.
4496	//	По умолчанию - номер счетчика основного сайта (22603441).
4497	//topik [29.09.2020]: Теперь счетчиков может быть несколько.
4498	//	Поэтому собираем их все и каждое событие вызываем для каждого счетчика.
4499	//-----{
4500	this.waitForYm = function(){
4501		let metrikaObj = (window.Ya && (window.Ya.Metrika || window.Ya.Metrika2)) || null;
4502		ymCounterNum = (metrikaObj && metrikaObj.counters && (metrikaObj.counters() || [0])[0].id) || 0;
4503
4504		let ymCounterObj = window['yaCounter' + ymCounterNum] || null;
4505		if(ymCounterObj){
4506			this.id = ymCounterNum;
4507			this.YaCounters = metrikaObj.counters();
4508			// console.log('waitForYm', this.id, this.YaCounters);
4509			/*
4510			$.each(this.YaCounters, function(el){
4511				console.log(el.id);
4512			});
4513			*/
4514			return;
4515		}
4516		
4517		this.waitYmTimeCnt = (this.waitYmTimeCnt || 0) + 1;
4518		if(this.waitYmTimeCnt > 20) return;
4519		else if(this.waitYmTimeCnt > 15) interval = 1000;
4520		else if(this.waitYmTimeCnt > 8) interval = 500;
4521		else interval = 250;
4522		
4523		setTimeout(function(){ this.waitForYm(); }.bind(this), interval);
4524	}
4525	this.waitForYm();
4526	//-----}
4527	
4528	this.pushEvent = function(event_code, params = {}){
4529		if(!event_code) return false;
4530		
4531		action = params.action || 'click';
4532		label = params.label || '';
4533		
4534		if(typeof ga !== 'undefined'){
4535			ga('send', 'event', event_code, action, label);
4536			console.log('GA: ' + event_code + ' [action:' + action + '; label:' + label + ']');
4537		}
4538		
4539		if(typeof ym !== 'undefined'){
4540			if (this.id) {
4541				ym(this.id, 'reachGoal', event_code);
4542			}
4543			//console.log('YM: ' + event_code + ' - ' + this.id);
4544		}
4545		
4546		if(typeof _txq !== 'undefined'){
4547			event_code_txq = false;
4548			
4549			if(event_code == 'add_v_korziny_kartochka') event_code_txq = 'basket';
4550			else if(event_code == 'door_turnkey') event_code_txq = 'door';
4551			else if(event_code == 'ask_partner_corp') event_code_txq = 'question_partner';
4552			else if(event_code == 'pochtabank_form_send') event_code_txq = 'installment_plan';
4553			else if(event_code == 'zakaz_peregorodki') event_code_txq = 'interior_partition';
4554			else if(event_code == 'vyzov_zamer') event_code_txq = 'gauge';
4555			else if(event_code == 'zakaz_zvonok') event_code_txq = 'call_back';
4556			else if(event_code == 'ask_partner_franshiza') event_code_txq = 'franchise';
4557			else if(event_code == 'order_processed') event_code_txq = 'order_processed';
4558			
4559			if(event_code_txq){
4560				_txq.push(['track', event_code_txq]);
4561				//console.log('TXQ: ' + event_code_txq);
4562			}
4563		}
4564	}
4565	
4566	this.formatProductsArray = function(products, action){
4567		Object.keys(products).forEach(function(i){
4568			var product = {},
4569				product_f = {};
4570
4571			// В products приходят либо готовые объекты (из ajax-ответа), либо DOM/jQuery-узлы.
4572			var node = products[i];
4573			var isNode = node && (node.jquery || node instanceof Element);
4574			if(!isNode) product = node;
4575			else{
4576				product = {
4577					'id': anData(node, 'id'),
4578					'name' : anData(node, 'name'),
4579					'price': anData(node, 'price'),
4580					'brand': anData(node, 'brand'),
4581					'category': anData(node, 'section-path'),
4582					'variant' : anData(node, 'size')
4583				};
4584			} 
4585			
4586			if(product.id) product_f.id = product.id;
4587			if(product.name) product_f.name = product.name;
4588			if(action != 'remove' && product.price) product_f.price = product.price;
4589			if(action != 'remove') product_f.brand = product.brand ? product.brand : self.brand;
4590			if(product.category) product_f.category = product.category;
4591			if(action != 'remove' && product.variant) product_f.variant = product.variant;
4592			if(action != 'remove' && product.quantity) product_f.quantity = product.quantity;
4593			
4594			products[i] = product_f;
4595		});
4596		return products;
4597	}
4598	
4599	this.viewProduct = function($product){
4600		product = this.initProductData($product, 'detail');
4601		
4602		console.log(
4603			"event: detail\n" + 
4604			"name: "  + product.name + "\n" + 
4605			"id: "  + product.id + "\n" + 
4606			"price: "  + product.price + "\n" + 
4607			"brand: "  + product.brand + "\n" + 
4608			"category: "  + product.category + "\n" + 
4609			"variant: "  + product.variant + "\n" + 
4610			"list: "  + (BX.getCookie('portaprimaMetrikaProductList') || '') + "\n" + 
4611			"position: "  + product.position
4612		);
4613		
4614		BX.setCookie('portaprimaMetrikaProductList', false, {expires: -1, path: '/'});
4615
4616
4617		// tooltipster - jQuery-плагин и к аналитике отношения не имеет (исторический хвост).
4618		// Зовём, только если jQuery с плагином на странице есть: файл от них не зависит.
4619		if (window.jQuery && window.jQuery.fn && window.jQuery.fn.tooltipster) {
4620			window.jQuery(".tooltip").tooltipster({
4621				theme: "tooltipster-my-shadow",
4622				maxWidth: 200,
4623				// trigger: "click",
4624				contentAsHTML: true
4625			});
4626		}
4627
4628		/*
4629		window.dataLayer.push({
4630			'ecommerce': {
4631				'detail': {
4632					'products': this.formatProductsArray(products, 'detail')
4633				}
4634			}
4635		});
4636		*/
4637		if ($$.vk_ecomm) {
4638			$$.vk_ecomm.viewProduct(product);
4639		}
4640		if ($$.ga_ecomm) {
4641			$$.ga_ecomm.viewProduct(product);
4642		}
4643	}
4644	
4645	this.addBasketProduct = function(products){
4646		/*
4647		window.dataLayer.push({
4648			'ecommerce': {
4649				'add': {
4650					'products': this.formatProductsArray(products, 'add')
4651				}
4652			}
4653		});
4654		*/
4655		if ($$.vk_ecomm) {
4656			$$.vk_ecomm.addBasketProduct(products);
4657		}
4658		if ($$.ga_ecomm) {
4659			$$.ga_ecomm.addBasketProduct(products);
4660		}
4661	}
4662	
4663	this.removeBasketProduct = function(products){
4664		/*
4665		window.dataLayer.push({
4666			'ecommerce': {
4667				'remove': {
4668					'products': this.formatProductsArray(products, 'remove')
4669				}
4670			}
4671		});
4672		*/
4673		if ($$.vk_ecomm) {
4674			$$.vk_ecomm.removeBasketProduct(products);
4675		}
4676		if ($$.ga_ecomm) {
4677			$$.ga_ecomm.removeBasketProduct(products);
4678		}
4679	}
4680	
4681	this.purchaseOrder = function(id, sum, products){
4682		/*
4683		window.dataLayer.push({
4684			'ecommerce': {
4685				'purchase': {
4686					'actionField': { 'id': id },
4687					'products': this.formatProductsArray(products, 'purchase')
4688				}
4689			}
4690		});
4691		*/
4692		if ($$.vk_ecomm) {
4693			$$.vk_ecomm.purchaseOrder(id, products);
4694		}
4695		if ($$.ga_ecomm) {
4696			$$.ga_ecomm.purchaseOrder(id, sum, products);
4697		}
4698	}
4699	
4700	this.clickProduct = function(product){
4701		if (!product) {
4702			return;
4703		}
4704		console.log(
4705			"event: click\n" + 
4706			"name: "  + product.name + "\n" + 
4707			"id: "  + product.id + "\n" + 
4708			"price: "  + product.price + "\n" + 
4709			"brand: "  + product.brand + "\n" + 
4710			"category: "  + product.category + "\n" + 
4711			"variant: "  + product.variant + "\n" + 
4712			"list: "  + product.list + "\n" + 
4713			"position: "  + product.position
4714		);
4715		
4716		BX.setCookie('portaprimaMetrikaProductList', product.list, {expires: 60*1, path: '/'});
4717	}
4718	
4719	this.productImpressions = function(products){
4720		// console.log('list: ' + products.length);
4721
4722		for (key in products)
4723		{
4724			let item = products[key];
4725			let itemID = item.id;
4726			let itemBlock = document.querySelector('.js-datalayer-product[data-layer-id="'+itemID+'"]');
4727			let itemLink = itemBlock && itemBlock.querySelector(':scope > a.js-datalayer-product-click');
4728			let itemUrl = itemLink ? itemLink.getAttribute('href') : '';
4729
4730			itemUrl = BX.util.add_url_param(itemUrl, {'mode': 'quickview'});
4731		}
4732		if ($$.ga_ecomm) {
4733			$$.ga_ecomm.viewProducts(products);
4734		}
4735		// console.log('productImpressions', products);
4736	}
4737	
4738	this.initProductData = function($product, action){
4739		var node = anEl($product);
4740		var product = {
4741			'name' : (anData(node, 'layer-name') || (anData(node, 'name') || '')),
4742			'id' : (anData(node, 'layer-id') || (anData(node, 'id') || '')),
4743			'price' : (anData(node, 'layer-price') || (anData(node, 'price') || '')),
4744			'brand' : (anData(node, 'layer-brand') || (anData(node, 'brand') || '')),
4745			'category' : (anData(node, 'layer-category') || (anData(node, 'section-path') || '')),
4746			'variant' : (anData(node, 'layer-variant') || (anData(node, 'variant') || '')),
4747			'list' : (anData(node, 'layer-list') || window.location.pathname),
4748			'position' : (anData(node, 'layer-position') || (anData(node, 'position') || ''))
4749		};
4750		
4751		if(action == 'detail') delete product.list;
4752		if(action == 'detail') delete product.position;
4753		
4754		return product;
4755	}
4756	
4757	this.productListInit = function($list){
4758		var list = anEl($list);
4759		if(!list) return undefined;
4760
4761		if(!anData(list, 'layer-inited')){
4762			var list_id = Math.floor(Math.random() * 10000);
4763
4764			self.products[list_id] = [];
4765
4766			// Делегирование внутри списка (было $list.on('click', selector, fn)).
4767			list.addEventListener('click', function(e){
4768				var target = e.target.closest(self.selectors.product_click);
4769				if (target && list.contains(target)) {
4770					self.clickProduct(self.products[list_id][anData(target, 'layer-id')]);
4771				}
4772			});
4773
4774			// jQuery .data(key, value) писал во ВНУТРЕННЕЕ хранилище, а не в DOM.
4775			// Пишем в data-атрибут: читается тем же anData(), заодно видно в инспекторе.
4776			anSetData(list, 'layer-list_id', list_id);
4777			anSetData(list, 'layer-inited', true);
4778
4779			return list_id;
4780		}
4781
4782		return anData(list, 'layer-list_id');
4783	}
4784	
4785	this.productList = function($list){
4786		var list = anEl($list);
4787		var list_id = this.productListInit(list),
4788			products = [];
4789
4790		if(!list) return;
4791
4792		Array.prototype.forEach.call(list.querySelectorAll(this.selectors.product), function(product_node){
4793			if(!anData(product_node, 'layer-inited')){
4794				var product = self.initProductData(product_node);
4795
4796				self.products[list_id][product.id] = product;
4797				products.push(product);
4798
4799				anSetData(product_node, 'layer-inited', true);
4800			}
4801		});
4802
4803		this.productImpressions(products);
4804	}
4805
4806	this.viewBasket = function(products){
4807		if ($$.ga_ecomm) {
4808			$$.ga_ecomm.viewBasket(products);
4809		}
4810	}
4811
4812	this.viewOrder = function(products){
4813		if ($$.ga_ecomm) {
4814			$$.ga_ecomm.viewOrder(products);
4815		}
4816	}
4817}
4818
4819$$._vk_ecomm = function(){
4820	var PIXEL_ID = 3306496
4821	var self = this;
4822	var bufferPushData = [];
4823	
4824	this.inited = function() {
4825		var inited = window._tmr && window._tmr.push;
4826		if (!inited) {
4827			return false;
4828		}
4829
4830		self.restore();
4831
4832		return true;
4833	}
4834
4835	this.restore = function() {
4836		if (bufferPushData.length) {
4837			console.log('vk restore push', pushData);
4838			for (let index = 0; index < bufferPushData.length; index++) {
4839				_tmr.push(bufferPushData[index]);
4840			}
4841			bufferPushData = [];
4842		}
4843	}
4844
4845	this.push = function(pushData) {
4846		if (!self.inited()) {
4847			console.log('vk save push', pushData);
4848			bufferPushData.push(pushData);
4849		}
4850		else {
4851			console.log('vk push', pushData);
4852			_tmr.push(pushData);
4853		}
4854	}
4855
4856	this.viewProduct = function(product) {
4857		console.log('vk viewProduct', product);
4858		this.push({
4859			type: "reachGoal",
4860			id: PIXEL_ID,
4861			value: ''+product.price,
4862			goal: "viewProduct",
4863			params: {
4864				product_id: ''+product.id}
4865			}
4866		);
4867	}
4868
4869	this.addBasketProduct = function(products) {
4870		console.log('vk addBasketProduct', products);
4871		for (var index = 0; index < products.length; index++) {
4872			var product = products[index];
4873			self.push({
4874				type: "reachGoal",
4875				id: PIXEL_ID,
4876				value: ''+product.price,
4877				goal: "addToCart",
4878				params: {
4879					product_id: ''+product.id
4880				}
4881			});
4882		}
4883	}
4884
4885	this.removeBasketProduct = function(products) {
4886		// console.log('vk removeBasketProduct', products);
4887	}
4888
4889	this.purchaseOrder = function(orderId, products) {
4890		console.log('vk purchaseOrder', orderId, products);
4891		var product_ids = [];
4892		var sum = 0;
4893		for (var index = 0; index < products.length; index++) {
4894			var product = products[index];
4895			// Конвертирование к строке
4896			product_ids.push('' + product.id);
4897			// Конвертирование к числу
4898			sum += product.price * 1 * product.quantity * 1;
4899		}
4900		self.push({
4901			type: "reachGoal",
4902			id: PIXEL_ID,
4903			value: '' + sum,
4904			goal: "purchase",
4905			params: {
4906				product_id: product_ids
4907			}
4908		});
4909	}
4910}
4911
4912$$._ga_ecomm = function(){
4913	var self = this;
4914	var bufferPushData = [];
4915	
4916	this.inited = function() {
4917		var inited = window.dataLayer && window.dataLayer.push;
4918		if (!inited) {
4919			return false;
4920		}
4921
4922		self.restore();
4923
4924		return true;
4925	}
4926
4927	this.restore = function() {
4928		if (bufferPushData.length) {
4929			// console.log('ga restore push', pushData);
4930			for (let index = 0; index < bufferPushData.length; index++) {
4931				dataLayer.push(bufferPushData[index]);
4932			}
4933			bufferPushData = [];
4934		}
4935	}
4936
4937	this.push = function(pushData) {
4938		if (!self.inited()) {
4939			// console.log('ga save push', pushData);
4940			bufferPushData.push(pushData);
4941		}
4942		else {
4943			console.log('ga push', pushData);
4944			dataLayer.push(pushData);
4945		}
4946	}
4947
4948	this.processProduct = function(product) {
4949		product.categories = product.category ? product.category.split(/\s*\/\s*/) : '';
4950		var result = {
4951			'item_name': product.name, // Название товара, карточку которого пользователь просматривает
4952			'item_id': product.id, // Идентификатор товара
4953			'price': product.price, // Цена 1 единицы товара
4954			'item_brand': product.brand, // Бренд товара
4955			'quantity': product.quantity, // Параметр, в котором фиксируется количество товара
4956			'item_variant': product.variant, // Вариант товара, карточку которого просматривает пользователь
4957			// 'discount': '100',  //	Размер скидки на товар, карточку которого просматривает пользователь
4958		};
4959		for (let index = 0; index < product.categories.length; index++) {
4960			const prefix = index ? ''+(index+1) : '';
4961			result['item_category'+prefix] = product.categories[index];
4962		}
4963		return result;
4964	}
4965
4966	this.processProducts = function(products) {
4967		var result = [];
4968		for (let index = 0; index < products.length; index++) {
4969			let product = this.processProduct(products[index]);
4970			product['index'] = index + 1;
4971			result[index] = product;
4972		}
4973		return result;
4974	}
4975
4976	this.viewProducts = function(products) {
4977		// console.log('ga viewProducts', products);
4978		this.push({
4979			'event': 'view_item_list',
4980			'ecommerce': {
4981				'items': this.processProducts(products)
4982			}
4983		});
4984	}
4985
4986	this.viewProduct = function(product) {
4987		// console.log('ga viewProduct', product);
4988		this.push({
4989			'event': 'view_item',
4990			'ecommerce': {
4991				'items': [this.processProduct(product)]
4992			}
4993		});
4994	}
4995
4996	this.addBasketProduct = function(products) {
4997		// console.log('ga addBasketProduct', products);
4998		this.push({
4999			'event': 'add_to_cart',
5000			'ecommerce': {
5001				'items': this.processProducts(products)
5002			}
5003		});
5004	}
5005
5006	this.removeBasketProduct = function(products) {
5007		// console.log('ga removeBasketProduct', products);
5008		this.push({
5009			'event': 'remove_from_cart',
5010			'ecommerce': {
5011				'items': this.processProducts(products)
5012			}
5013		});
5014	}
5015
5016	this.viewBasket = function(products) {
5017		// console.log('ga viewBasket', products);
5018		this.push({
5019			'event': 'view_cart',
5020			'ecommerce': {
5021				'items': this.processProducts(products)
5022			}
5023		});
5024	}
5025
5026	this.viewOrder = function(products) {
5027		// console.log('ga viewOrder', products);
5028		this.push({
5029			'event': 'begin_checkout',
5030			'ecommerce': {
5031				'items': this.processProducts(products)
5032			}
5033		});
5034		sendYaReachGoal('klik-po-knopke-oformit-zakaz-korzina');
5035	}
5036
5037	this.purchaseOrder = function(orderId, sum, products) {
5038		// console.log('ga purchaseOrder', orderId, products);
5039		this.push({
5040			'event': 'purchase',
5041			'ecommerce': {
5042				'transaction_id': orderId, // Идентификатор транзакции
5043				'value': sum, // Общая сумма корзины на момент отправки события
5044				'currency': 'RUB',
5045				'shipping': 0, // Стоимость доставки
5046				'items': this.processProducts(products)
5047			}
5048		});
5049	}
5050}
5051
5052
5053function anReady(fn) {
5054	if (document.readyState === 'loading') {
5055		document.addEventListener('DOMContentLoaded', fn);
5056	} else {
5057		fn();
5058	}
5059}
5060
5061anReady(function(){
5062	// Реальные объекты аналитики перетирают заглушки из commonCatalog_new.js.
5063	$$.metrika = new $$._metrika();
5064	$$.vk_ecomm = new $$._vk_ecomm();
5065	$$.ga_ecomm = new $$._ga_ecomm();
5066
5067	if (window.basketMetrika && basketMetrika.length) {
5068		$$.metrika.viewBasket(basketMetrika);
5069	}
5070});
5071
5072/* End */
5073;
5074; /* Start:"a:4:{s:4:"full";s:66:"/bitrix/templates/portaprima-main/js/collection.js?178635668142063";s:6:"source";s:50:"/bitrix/templates/portaprima-main/js/collection.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
5075// Мини-хелперы вместо jQuery. Объявлены локально, чтобы файл не зависел от порядка
5076// подключения script.js (там такие же).
5077function collectionSibling(el, selector) {
5078    // Аналог $(el).siblings(selector): соседи по родителю, сам элемент не в счёт.
5079    if (!el || !el.parentElement) {
5080        return null;
5081    }
5082    const found = Array.prototype.find.call(el.parentElement.children, function(child) {
5083        return child !== el && child.matches(selector);
5084    });
5085    return found || null;
5086}
5087
5088function collectionToggle(el, visible) {
5089    // Аналог .show() / .hide()
5090    if (el) {
5091        el.style.display = visible ? '' : 'none';
5092    }
5093}
5094
5095window.addEventListener('DOMContentLoaded', () => {
5096    // const range_button = document.querySelectorAll('.interior_filter_range');
5097    // const range_button_left = document.querySelectorAll('.interior_filter_drag_left');
5098    // const range_button_right = document.querySelectorAll('.interior_filter_drag_right');
5099
5100    const input_left = document.getElementById('input_price_left');
5101    const input_min = input_left && Number(input_left.dataset.min) || 0;
5102    const input_left_exts = document.querySelectorAll('.input_price_left');
5103    const input_right = document.getElementById('input_price_right');
5104    const input_max = input_right && Number(input_right.dataset.max) || 10000;
5105    const input_right_exts = document.querySelectorAll('.input_price_right');
5106
5107    // let range_mousedown_left = false;
5108    // let range_left_clientX = range_button[0].getBoundingClientRect().left;
5109    // let range_mousedown_right = false;
5110    // let range_right_clientX = range_button[0].getBoundingClientRect().left;
5111
5112    zIndex = 100;
5113    // let width_range;
5114    // let range_button_index = 0;
5115    // range_button.forEach((range_button_, i) => {
5116    //     if (range_button_.offsetWidth) {
5117    //         width_range = range_button_.offsetWidth;
5118    //         range_button_index = i;
5119    //     }
5120    // })
5121
5122    // let leftDirection = 0;
5123    // let prev_left = 0;
5124    input_left_exts.forEach((input_left_ext) => {
5125        input_left_ext.addEventListener('change', () => {
5126            input_left.value = input_left_ext.value;
5127            var event = new Event('change');
5128            input_left.dispatchEvent(event);
5129        })
5130        input_left_ext.addEventListener('keyup', () => {
5131            input_left.value = input_left_ext.value;
5132            var event = new Event('keyup');
5133            input_left.dispatchEvent(event);
5134        })
5135    })
5136    function input_left_handler() {
5137        // range_button.forEach((range_button_, i) => {
5138        //     if (range_button_.offsetWidth) {
5139        //         width_range = range_button_.offsetWidth;
5140        //         range_button_index = i;
5141        //     }
5142        // });
5143        
5144        const left_limit = input_max*0.93;
5145        let ileft = input_left.value && Number(input_left.value) || input_min;
5146        if (ileft < input_min) {
5147            ileft = input_min;
5148        }
5149        let iright = input_right.value && Number(input_right.value) || input_max;
5150        if (iright > input_max) {
5151            iright = input_max;
5152        }
5153        input_left_exts.forEach((input_left_ext) => {
5154            if (input_left_ext.value != input_left.value) {
5155                input_left_ext.value = input_left.value
5156            }
5157        })
5158        if (ileft > iright) {
5159            input_left.value = iright;
5160            // procent_left = ileft/input_max;
5161            // range_button_left.forEach((range_button_left_) => {
5162            //     range_button_left_.style.left = `${width_range * procent_left - 10}px`;
5163            // })
5164        } else if (ileft <= input_max && ileft >= 0) {
5165            // procent_left = (ileft-input_min)/(input_max-input_min);
5166            // range_button_left.forEach((range_button_left_) => {
5167            //     range_button_left_.style.left = `${width_range * procent_left}px`;
5168            // })
5169        } else if (ileft > left_limit) {
5170            input_left.value = left_limit;
5171            // procent_left = (ileft-input_min)/(input_max-input_min);
5172            // range_button_left.forEach((range_button_left_) => {
5173            //     range_button_left_.style.left = `${width_range * procent_left}px`;
5174            // })
5175        } else if (ileft < 0) {
5176            input_left.value = '';
5177        }
5178        updateInputClearVisiabilty();
5179    }
5180    input_left && input_left.addEventListener('change', input_left_handler);
5181    input_left && input_left.addEventListener('keyup', input_left_handler);
5182
5183    input_right_exts.forEach((input_right_ext) => {
5184        input_right_ext.addEventListener('change', () => {
5185            input_right.value = input_right_ext.value;
5186            var event = new Event('change');
5187            input_right.dispatchEvent(event);
5188        })
5189        input_right_ext.addEventListener('keyup', () => {
5190            input_right.value = input_right_ext.value;
5191            var event = new Event('keyup');
5192            input_right.dispatchEvent(event);
5193        })
5194    })
5195     function input_right_handler() {
5196        // range_button.forEach((range_button_, i) => {
5197        //     if (range_button_.offsetWidth) {
5198        //         width_range = range_button_.offsetWidth;
5199        //         range_button_index = i;
5200        //     }
5201        // });
5202        let ileft = input_left.value && Number(input_left.value) || input_min;
5203        if (ileft < input_min) {
5204            ileft = input_min;
5205        }
5206        let iright = input_right.value && Number(input_right.value) || input_max;
5207        if (iright > input_max) {
5208            iright = input_max;
5209        }
5210        input_right_exts.forEach((input_right_ext) => {
5211            if (input_right_ext.value != input_right.value) {
5212                input_right_ext.value = input_right.value
5213            }
5214        })
5215        if (iright < ileft) {
5216            input_right.value = ileft;
5217            // procent_right = iright/input_max;
5218            // range_button_right.forEach((range_button_right_) => {
5219            //     range_button_right_.style.right = `${width_range - width_range * procent_right - 10}px`;
5220            // })
5221        } else if (iright && iright <= input_max && iright >= 0) {
5222            // procent_right = iright/input_max;
5223            // range_button_right.forEach((range_button_right_) => {
5224            //     range_button_right_.style.right = `${width_range - width_range * procent_right}px`;
5225            // })
5226        } else if (iright > input_max) {
5227            input_right.value = input_max;
5228            // range_button_right.forEach((range_button_right_) => {
5229            //     range_button_right_.style.right = `0px`;
5230            // })
5231        } else if (iright < 0) {
5232            input_right.value = 0;
5233        }
5234        updateInputClearVisiabilty();
5235    }
5236    input_right && input_right.addEventListener('change', input_right_handler);
5237    input_right && input_right.addEventListener('keyup', input_right_handler);
5238
5239    const interior_buttons = document.querySelectorAll('.interior_button');
5240    if (interior_buttons.length > 0) {
5241        interior_buttons.forEach(interior_button => {
5242            
5243            interior_button.addEventListener('click', () => {
5244                setTimeout(() => {
5245                    const active = interior_button.classList.contains('active');
5246                    if (active) {
5247                        const range_inner = interior_button.parentNode.querySelector('.interior_filter_range');
5248                        if (range_inner && !range_inner.classList.contains('inited')) {
5249                            range_inner.classList.add('inited');
5250
5251                            if (input_left.value) {
5252                                var event = new Event('change');
5253                                input_left.dispatchEvent(event);
5254                            }
5255                            if (input_right.value) {
5256                                var event = new Event('change');
5257                                input_right.dispatchEvent(event);
5258                            }
5259                        }
5260                    }
5261                }, 50);
5262            })
5263        })
5264    }
5265
5266    // const checkboxes_range_container = document.querySelectorAll('.checkbox_range_container');
5267    // range_button_left.forEach((range_button_left_) => {
5268    //     range_button_left_.addEventListener('mousedown', (e) => {
5269    //         range_mousedown_left = true;
5270    //         // range_button.forEach((range_button_, i) => {
5271    //         //     if (range_button_.offsetWidth) {
5272    //         //         width_range = range_button_.offsetWidth;
5273    //         //         range_button_index = i;
5274    //         //     }
5275    //         // });
5276    //         checkboxes_range_container.forEach((checkbox_range_container) => {
5277    //             const checkbox1 = checkbox_range_container.querySelector('input');
5278    //             checkbox1.checked = false;
5279    //         })
5280    //         range_button_left_.style.zIndex = `${zIndex+1}`;
5281    //         zIndex++
5282    //     })
5283    // })
5284
5285    // let procent_left = 0;
5286    // let procent_right = 1;
5287    // window.addEventListener('mousemove', (e) => {
5288    //     if (range_mousedown_left) {
5289    //         procent_left = (range_button_left[range_button_index].offsetLeft+10)/ width_range;
5290    //         if (procent_left >  1) {
5291    //             input_left.value = input_max;
5292    //         } else if (procent_left <= 0.05) {
5293    //             input_left.value = input_min;
5294    //         } else {
5295    //             input_left.value = Math.round(procent_left * (input_max - input_min))+input_min
5296    //         }
5297    //         input_left_exts.forEach((input_left_ext) => {
5298    //             if (input_left_ext.value != input_left.value) {
5299    //                 input_left_ext.value = input_left.value
5300    //             }
5301    //         })
5302    //     }
5303        
5304    //     if (range_mousedown_left && e.clientX-range_button[range_button_index].getBoundingClientRect().left-5 > 0 && (procent_left < procent_right || leftDirection < 0)) {
5305    //         range_button_left.forEach((range_button_left_) => {
5306    //             range_button_left_.style.left = `${e.clientX-range_button[range_button_index].getBoundingClientRect().left-5}px`;
5307    //         })
5308    //     } 
5309
5310    //     leftDirection = e.clientX - prev_left;
5311    //     prev_left = e.clientX;
5312    // })
5313    // window.addEventListener('mouseup', () => {
5314    //     range_mousedown_left = false;
5315    // })
5316
5317    // range_button_right.forEach((range_button_right_) => {
5318    //     range_button_right_.addEventListener('mousedown', (e) => {
5319    //         range_mousedown_right = true;
5320    //         // range_button.forEach((range_button_) => {
5321    //         //     if (range_button_.offsetWidth) {
5322    //         //         width_range = range_button_.offsetWidth;
5323    //         //     }
5324    //         // })
5325    
5326    //         checkboxes_range_container.forEach((checkbox_range_container) => {
5327    //             const checkbox1 = checkbox_range_container.querySelector('input');
5328    //             checkbox1.checked = false;
5329    //         })
5330    
5331    //         range_button_right_.style.zIndex = `${zIndex+1}`;
5332    //         zIndex++
5333    //     })
5334    // })
5335    // range_button_right.forEach((range_button_right_) => {
5336    //     range_button_right_.ondragstart = function() { return false; };
5337    // })
5338    // range_button_left.forEach((range_button_left_) => {
5339    //     range_button_left_.ondragstart = function() { return false; };
5340    // })
5341
5342    // let rightDirection = 0;
5343    // let prev_right = 0;
5344    // window.addEventListener('mousemove', (e) => {
5345    //     if (range_mousedown_right) {
5346    //         procent_right = (range_button_right[range_button_index].offsetLeft+10)/ width_range;
5347    //         if (procent_right >  1) {
5348    //             input_right.value = input_max;
5349    //         } else if (procent_right <= 0.05) {
5350    //             input_right.value = input_min;
5351    //         } else {
5352    //             input_right.value = Math.round(procent_right * (input_max-input_min)) + input_min
5353    //         }
5354    //         input_right_exts.forEach((input_right_ext) => {
5355    //             if (input_right_ext.value != input_right.value) {
5356    //                 input_right_ext.value = input_right.value
5357    //             }
5358    //         })
5359    //     }
5360    
5361    //     if (range_mousedown_right && -e.clientX+range_button[range_button_index].getBoundingClientRect().right-5.625625 > 0 && ((procent_left < procent_right) || rightDirection > 0)) {
5362    //         range_button_right.forEach((range_button_right_) => {
5363    //             range_button_right_.style.right = `${-e.clientX+range_button[range_button_index].getBoundingClientRect().right-5.65625}px`;
5364    //         })
5365    //     }
5366
5367    //     rightDirection = e.clientX - prev_right;
5368    //     prev_right = e.clientX;
5369    // })
5370    // window.addEventListener('mouseup', () => {
5371    //     range_mousedown_right = false;
5372    // })
5373
5374    window.initInteriorFilterContentCheckboxes = function() {
5375        const interior_filter_content_checkboxes = document.querySelectorAll('.interior_filter_content_checkbox');
5376        interior_filter_content_checkboxes.forEach((interior_filter_content_checkbox) => {
5377            if (interior_filter_content_checkbox.dataset.inited) {
5378                return;
5379            }
5380            interior_filter_content_checkbox.dataset.inited = true;
5381
5382            const checkbox1i = interior_filter_content_checkbox.querySelector('input')
5383            let invert = false;
5384            checkbox1i && checkbox1i.addEventListener('click', (e) => {
5385                if (interior_filter_content_checkbox.classList.contains('disabled')) {
5386                    e.preventDefault();
5387                    return;
5388                }
5389                invert = true;
5390                setTimeout(() => {
5391                    invert = false;
5392                }, 50);
5393            })
5394            interior_filter_content_checkbox.addEventListener('click', (e) => {
5395                if (interior_filter_content_checkbox.classList.contains('disabled')) {
5396                    e.preventDefault();
5397                    return;
5398                }
5399                
5400                const checkbox1 = interior_filter_content_checkbox.querySelector('input');
5401                let newValue = checkbox1.checked ? false : true;
5402                if (invert) {
5403                    newValue = !newValue;
5404                    invert = false;
5405                }
5406    
5407                const links = interior_filter_content_checkbox.dataset.ids;
5408                const linkParts = links && (links.search(',')) !== -1 && links.split(',') || false;
5409                if (links) {
5410                    const link_checkboxes = document.querySelectorAll(links);
5411                    link_checkboxes.forEach((link_checkbox) => {
5412                        link_checkbox.checked = newValue;
5413    
5414                        var event = new Event('change');
5415                        link_checkbox.dispatchEvent(event);
5416                    })
5417        
5418                    interior_filter_content_checkboxes.forEach((_interior_filter_content_checkbox) => {
5419                        const links2 = _interior_filter_content_checkbox.dataset.ids;
5420                        if ((links2 == links) || (linkParts && linkParts.indexOf(links2) !== -1)) {
5421                            const _checkbox1 = _interior_filter_content_checkbox.querySelector('input');
5422                            _checkbox1.checked = newValue;
5423    
5424                            var event = new Event('change');
5425                            _checkbox1.dispatchEvent(event);
5426                        }
5427                    })
5428                }
5429                else {
5430                    checkbox1.checked = newValue;
5431                }
5432                updateInputClearVisiabilty();
5433            })
5434        })
5435    }
5436    initInteriorFilterContentCheckboxes();
5437
5438    const range_container_checkboxes  = document.querySelectorAll('.checkbox_range_container');
5439    range_container_checkboxes.forEach((range_container_checkbox) => {
5440        range_container_checkbox.addEventListener('click', (e) => {
5441            let mins = [];
5442            let maxs = [];
5443            range_container_checkboxes.forEach((checkbox_container) => {
5444                const checkbox1 = checkbox_container.querySelector('input');
5445                if (checkbox1.checked) {
5446                    mins.push(checkbox_container.dataset.min);
5447                    maxs.push(checkbox_container.dataset.max);
5448                }
5449            });
5450
5451            const checkbox1 = range_container_checkbox.querySelector('input');
5452            if (checkbox1.checked) {
5453                console.log(mins, maxs);
5454                let cmin = range_container_checkbox.dataset.min;
5455                let cmax = range_container_checkbox.dataset.max;
5456                for (let i = 0; i < 2; i++) {
5457                    if (maxs.indexOf(cmin) !== -1) {
5458                        cmin = mins[maxs.indexOf(cmin)];
5459                    }
5460                    if (mins.indexOf(cmax) !== -1) {
5461                        cmax = maxs[mins.indexOf(cmax)];
5462                    }
5463                }
5464
5465                input_left.value = cmin || '';
5466                input_right.value = cmax || '';
5467                var event = new Event('change');
5468                input_left.dispatchEvent(event);
5469                var event = new Event('change');
5470                input_right.dispatchEvent(event);
5471
5472                console.log(range_container_checkbox.id);
5473            } else {
5474                if (!mins.length || !maxs.length) {
5475                    input_left.value = '';
5476                    input_right.value = '';
5477                }
5478                else {
5479                    let cmin = mins[mins.length-1];
5480                    let cmax = maxs[maxs.length-1];
5481                    for (let i = 0; i < 2; i++) {
5482                        if (maxs.indexOf(cmin) !== -1) {
5483                            cmin = mins[maxs.indexOf(cmin)];
5484                        }
5485                        if (mins.indexOf(cmax) !== -1) {
5486                            cmax = maxs[mins.indexOf(cmax)];
5487                        }
5488                    }
5489                    input_left.value = cmin || '';
5490                    input_right.value = cmax || '';
5491                }
5492
5493                var event = new Event('change');
5494                input_left.dispatchEvent(event);
5495
5496                var event = new Event('change');
5497                input_right.dispatchEvent(event);
5498            }
5499        })
5500    });
5501
5502    const input_clear = document.getElementById('interior_filter_button_clear');
5503    const hidden_inputs = document.querySelector('.interior_filter_hidden_input');
5504    const interior_filters = document.querySelectorAll('.filter_resize_container .interior_filter');
5505    updateInputClearVisiabilty();
5506    function updateInputClearVisiabilty() {
5507        if (!input_clear) {
5508            return;
5509        }
5510        let filled = false;
5511        if (input_left && input_left.value || input_right && input_right.value) {
5512            filled = true;
5513        }
5514
5515        hidden_inputs.querySelectorAll('input').forEach((input) => {
5516            if ((input.type == 'checkbox') && input.checked)  {
5517                filled = true;
5518            }
5519        })
5520
5521        if (filled) {
5522            input_clear.classList.add('visible');
5523        }
5524        else {
5525            input_clear.classList.remove('visible');
5526        }
5527    }
5528
5529    const interior_filter_sorts = document.querySelectorAll('.interior_filter_sort');
5530    if (interior_filter_sorts.length > 0) {
5531        interior_filter_sorts.forEach(interior_filter_sort => {
5532            interior_filter_sort.addEventListener('click', (e) => {
5533                const form = document.querySelector('.smartfilter');
5534                if (form) {
5535                    // Обработчиков submit у формы нет - jQuery .trigger('submit') здесь просто
5536                    // отправлял её. requestSubmit() делает то же самое, но по-нативному.
5537                    if (form.requestSubmit) {
5538                        form.requestSubmit();
5539                    } else {
5540                        form.submit();
5541                    }
5542                }
5543            });
5544        })
5545    }
5546
5547    const btnBurg = document.querySelector('.interior_filter_button.burgundy-bg');
5548    btnBurg && btnBurg.classList.remove('selected');
5549    interior_filters.forEach(interior_filter => {
5550        const btn = interior_filter.querySelector('.interior_filter_button');
5551        const inputs = interior_filter.querySelectorAll('input');
5552        let filled = false;
5553        inputs.forEach(input => {
5554            if (input.type == 'text') {
5555                if (input.value) {
5556                    filled = true;
5557                }
5558            }
5559            if (input.type == 'checkbox') {
5560                if (input.checked) {
5561                    filled = true;
5562                }
5563            }
5564        });
5565        if (filled) {
5566            btn.classList.add('selected');
5567            btnBurg.classList.add('selected');
5568        }
5569        else {
5570            btn.classList.remove('selected');
5571        }
5572    });
5573    document.querySelectorAll('.interior_filter_content_text').forEach(text => {
5574        let title = text.previousElementSibling;
5575        let j = 0;
5576        while(title && (!title.classList || !title.classList.contains('interior_filter_content_title'))) {
5577            title = text.previousElementSibling;
5578            j++;
5579            if (j > 10) {
5580                break;
5581            }
5582        }
5583        if (!title || !title.classList || !title.classList.contains('interior_filter_content_title')) {
5584            return;
5585        }
5586        const inputs = text.querySelectorAll('input');
5587        let filled = false;
5588        inputs.forEach(input => {
5589            if (input.type == 'text') {
5590                if (input.value) {
5591                    filled = true;
5592                }
5593            }
5594            if (input.type == 'checkbox') {
5595                if (input.checked) {
5596                    filled = true;
5597                }
5598            }
5599        });
5600        if (title.classList) {
5601            if (filled) {
5602                title.classList.add('selected');
5603            }
5604            else {
5605                title.classList.remove('selected');
5606            }
5607        }
5608    });
5609});
5610
5611// Отбор ещё не инициализированных элементов: initCollectionSliders() вызывается
5612// повторно для слайдеров, догруженных аяксом (см. initLazyCollections ниже), и без
5613// пометки на них бы повторно навесились обработчики уже готовых слайдеров.
5614function collectNewCollectionEls(selector) {
5615    const result = [];
5616    document.querySelectorAll(selector).forEach(el => {
5617        if (el.dataset.collectionInited) {
5618            return;
5619        }
5620        el.dataset.collectionInited = '1';
5621        result.push(el);
5622    });
5623    return result;
5624}
5625
5626// Слайдер коллекций
5627function initCollectionSliders() {
5628    const collection_slider_contents = collectNewCollectionEls('.collection_slider_content');
5629    if (!collection_slider_contents.length) {
5630        return;
5631    }
5632    const slider_tabs = collectNewCollectionEls('.collection_slider_tab');
5633    const slider_nav_lefts = collectNewCollectionEls('.collection_slider_left_arrow');
5634    const slider_nav_rights = collectNewCollectionEls('.collection_slider_right_arrow');
5635    let widthOfSlider = collection_slider_contents[0].getBoundingClientRect().width || 0;
5636
5637    let slider_left = 0;
5638
5639    collection_slider_contents.forEach((collection_slider_content) => {
5640        const imgContainer = collection_slider_content.querySelector('.collection_slider_img');
5641        if (!imgContainer) {
5642            return;
5643        }
5644        let intro_x;
5645        imgContainer.addEventListener('touchstart', (e) => {
5646            intro_x = e.changedTouches[0].pageX;
5647        }, { passive: true });
5648        imgContainer.addEventListener('touchend', (e) => {
5649            if (e.changedTouches[0].pageX < (intro_x-100)) {
5650                const slider_nav_right = collection_slider_content.querySelector('.collection_slider_right_arrow');
5651                if (slider_nav_right) {
5652                    slideCollectionRight(slider_nav_right);
5653                }
5654                
5655            } else if (e.changedTouches[0].pageX > (intro_x+100)) {
5656                const slider_nav_left = collection_slider_content.querySelector('.collection_slider_left_arrow');
5657                if (slider_nav_left) {
5658                    slideCollectionLeft(slider_nav_left);
5659                }
5660            }
5661        });
5662    })
5663
5664    
5665    window.addEventListener('resize', () => {
5666        widthOfSlider = collection_slider_contents[0].getBoundingClientRect().width;
5667    })
5668
5669    // Перетаскивание ленты табов мышкой - как .new_items в старом шаблоне
5670    // (local/templates/portaprima/js/script.js, функция scrolling).
5671    let tabsDragMove = false;
5672
5673    function enableTabsDrag(sliderTabs) {
5674        if (!sliderTabs || sliderTabs.dataset.dragInited) {
5675            return;
5676        }
5677        sliderTabs.dataset.dragInited = true;
5678
5679        let drag = false;
5680        let startX = 0;
5681        let startScroll = 0;
5682
5683        sliderTabs.addEventListener('mousedown', (e) => {
5684            drag = true;
5685            tabsDragMove = false;
5686            startX = e.pageX;
5687            startScroll = sliderTabs.scrollLeft;
5688        });
5689
5690        sliderTabs.addEventListener('mousemove', (e) => {
5691            if (!drag) {
5692                return;
5693            }
5694            const shift = e.pageX - startX;
5695            // Порог, чтобы дрожь руки при клике по табу не считалась перетаскиванием.
5696            if (!tabsDragMove && Math.abs(shift) < 5) {
5697                return;
5698            }
5699            tabsDragMove = true;
5700            e.preventDefault(); // иначе тянется выделение текста
5701            sliderTabs.scrollLeft = startScroll - shift;
5702        });
5703
5704        // mouseup ловим на document: курсор при перетаскивании часто уезжает за пределы ленты.
5705        document.addEventListener('mouseup', () => {
5706            if (!drag) {
5707                return;
5708            }
5709            drag = false;
5710            // click приходит после mouseup - флаг гасим с задержкой, чтобы обработчик таба его увидел.
5711            setTimeout(() => {
5712                tabsDragMove = false;
5713            }, 50);
5714        });
5715
5716        // Картинки табов перетаскиваются нативно - мешает.
5717        sliderTabs.addEventListener('dragstart', (e) => {
5718            e.preventDefault();
5719        });
5720    }
5721
5722    collectNewCollectionEls('.collection_slider_tabs').forEach(enableTabsDrag);
5723
5724    function scrollTabs(sliderTabs) {
5725        if (!sliderTabs) {
5726            return;
5727        }
5728        const slide = sliderTabs.querySelector('.collection_slider_tab.active');
5729        if (!slide) {
5730            return;
5731        }
5732
5733        let matrix_id = slide.dataset.matrix_id;
5734        let slider_tab_id = slide.dataset.slider_tab_id;
5735        let slide_id = Number(slide.dataset.slide_id);
5736        const matrix_suffix = matrix_id && `_m${matrix_id}` || ''
5737        const slider_selector = `#${slider_tab_id}${matrix_suffix}`;
5738        const width = sliderTabs.offsetWidth;
5739        let visibleWidth = 0;
5740        let fullWidth = 0;
5741        const slides = sliderTabs.querySelectorAll('.collection_slider_tab');
5742        slides.forEach((el) => {
5743            fullWidth += el.offsetWidth;
5744        });
5745        const bias = window.innerWidth && (window.innerWidth > 600) && 2 || 1;
5746        let slideWidth = fullWidth / slides.length;
5747        while((visibleWidth+slideWidth*bias) < width) {
5748            visibleWidth += slideWidth;
5749        }
5750
5751        let nextWidth = slideWidth*(slide_id+2);
5752        let scrollLeft = 0;
5753        if (visibleWidth < nextWidth) {
5754            scrollLeft = nextWidth - visibleWidth + slideWidth*bias;
5755        }
5756        if (sliderTabs.scrollLeft != scrollLeft) {
5757            sliderTabs.scroll({
5758                behavior: "smooth",
5759                left: scrollLeft,
5760            });
5761        }
5762    }
5763
5764    function slideCollectionLeft(slider_nav_left) {
5765        let matrix_id = slider_nav_left.dataset.matrix_id;
5766        let slider_nav_id = slider_nav_left.dataset.slider_nav_id;
5767        let slide_id = Number(slider_nav_left.dataset.slide_id);
5768
5769        if (slider_nav_id && slide_id!=1) {
5770            const matrix_suffix = matrix_id && `_m${matrix_id}` || ''
5771            const slide = document.querySelector(`#${slider_nav_id}${matrix_suffix}`);
5772            
5773            slider_left = -(slide_id-2)*widthOfSlider;
5774            slide.style.left=`${slider_left}px`;
5775            
5776            slider_tabs.forEach(el => {
5777                let el_matrix = el.dataset.matrix_id;
5778                let el_id = el.dataset.slider_tab_id;
5779                let tab_id = el.dataset.slide_id;
5780                if ((el_id == slider_nav_id) && (!matrix_id || (matrix_id == el_matrix))) {
5781                    el.classList.remove('active');
5782                    if (slide_id-2 == tab_id) {
5783                        el.classList.add('active');
5784                        updateSliderText(el);
5785                        scrollTabs(el.parentNode);
5786                    }
5787                }
5788            }) 
5789        }
5790    }
5791
5792    function slideCollectionRight(slider_nav_right) {
5793        let matrix_id = slider_nav_right.dataset.matrix_id;
5794        let slider_nav_id = slider_nav_right.dataset.slider_nav_id;
5795        let slide_id = Number(slider_nav_right.dataset.slide_id);
5796        let last = slider_nav_right.dataset.last
5797
5798        if (slider_nav_id && !last) {
5799            const matrix_suffix = matrix_id && `_m${matrix_id}` || ''
5800            const slide = document.querySelector(`#${slider_nav_id}${matrix_suffix}`);
5801            
5802            slider_left = -(slide_id)*widthOfSlider;
5803            slide.style.left=`${slider_left}px`;
5804            
5805            slider_tabs.forEach(el => {
5806
5807                let el_matrix = el.dataset.matrix_id;
5808                let el_id = el.dataset.slider_tab_id;
5809                let tab_id = el.dataset.slide_id;
5810                if ((el_id == slider_nav_id) && (!matrix_id || (matrix_id == el_matrix))) {
5811                    el.classList.remove('active');
5812                    if (slide_id == tab_id) {
5813                        el.classList.add('active');
5814                        updateSliderText(el);
5815                        scrollTabs(el.parentNode);
5816                    }
5817                }
5818                
5819            }) 
5820
5821        }
5822    }
5823
5824    function updateSliderText(slide) {
5825        const title = slide.dataset.sliderTitle;
5826        if (!title) {
5827            return;
5828        }
5829        const text = slide.dataset.sliderText;
5830        const url = slide.dataset.sliderUrl;
5831        const hint = slide.dataset.sliderHint;
5832
5833        const slider = slide.closest('.collection_slider');
5834        const description = slider && collectionSibling(slider, '.collection_description');
5835        if (!description) {
5836            return;
5837        }
5838
5839        const titleEl = description.querySelector('[data-title]');
5840        const textEl = description.querySelector('[data-text]');
5841        const linkEl = description.querySelector('[data-link]');
5842        const hintEl = description.querySelector('[data-hint]');
5843
5844        if (titleEl) {
5845            titleEl.innerHTML = title;
5846        }
5847        if (textEl) {
5848            textEl.innerHTML = text;
5849        }
5850
5851        collectionToggle(linkEl, !!url);
5852        if (url && linkEl) {
5853            linkEl.setAttribute('href', url);
5854        }
5855
5856        collectionToggle(hintEl, !!url);
5857        if (url && hintEl) {
5858            hintEl.innerHTML = hint;
5859        }
5860    }
5861    
5862    slider_tabs.forEach(slider_tab => {
5863        slider_tab.addEventListener('click', () => {
5864            if (tabsDragMove) {
5865                return; // клик - хвост перетаскивания ленты, таб не переключаем
5866            }
5867            let slider_tab_id = slider_tab.dataset.slider_tab_id;
5868            let matrix_id = slider_tab.dataset.matrix_id;
5869    
5870            slider_tabs.forEach(el => {
5871                let el_matrix = el.dataset.matrix_id;
5872                let el_id = el.dataset.slider_tab_id;
5873                if ((el_id == slider_tab_id) && (!matrix_id || (matrix_id == el_matrix))) {
5874                    el.classList.remove('active');
5875                }
5876            }) 
5877            slider_tab.classList.add('active');
5878            updateSliderText(slider_tab);
5879            let slide_tab_id = Number(slider_tab.dataset.slide_id);
5880            if (slider_tab_id) {
5881                const matrix_suffix = matrix_id && `_m${matrix_id}` || ''
5882                const slide = document.querySelector(`#${slider_tab_id}${matrix_suffix}`);
5883                slider_left = -slide_tab_id*widthOfSlider;
5884                slide.style.left=`${slider_left}px`;
5885            }
5886            scrollTabs(slider_tab.parentNode);
5887        })
5888        if (slider_tab.classList.contains('active')) {
5889            updateSliderText(slider_tab);
5890        }
5891    })
5892
5893    slider_nav_lefts.forEach(slider_nav_left => {
5894        slider_nav_left.addEventListener('click', () => {
5895            slideCollectionLeft(slider_nav_left);
5896        })
5897    })
5898
5899    slider_nav_rights.forEach(slider_nav_right => {
5900        slider_nav_right.addEventListener('click', () => {
5901            slideCollectionRight(slider_nav_right);
5902        })
5903    })
5904
5905    // Преключение слайдера матриц
5906    const collection_matrix_items = collectNewCollectionEls('.collection_matrix_item');
5907    const collections = document.querySelectorAll('.matrix_collection_item');
5908    
5909    collection_matrix_items.forEach(item => {
5910        item.addEventListener('click', () => {
5911            let slider_id = item.dataset.slider_id;
5912            collection_matrix_items.forEach(el => {
5913                let cslider_id = el.dataset.slider_id;
5914                if (slider_id && (cslider_id == slider_id)) {
5915                    el.classList.remove('active')
5916                }
5917            })
5918            item.classList.add('active');
5919    
5920            let matrix_id = item.dataset.matrix_id;
5921    
5922            collections.forEach(el => {
5923                let cslider_id = el.dataset.slider_id;
5924                if (slider_id && (cslider_id == slider_id)) {
5925                    el.classList.remove('active');
5926                    
5927                    let collection_id = el.dataset.matrix_id;
5928                    if (matrix_id == collection_id) {
5929                        el.classList.add('active');
5930                        scrollTabs(el.querySelector('.collection_slider_tabs'));
5931                    }
5932                }
5933    
5934            })
5935        })
5936    })
5937}
5938
5939// Отложенная загрузка слайдеров коллекций.
5940// PHP выводит плейсхолдер вместо слайдера, если его html ещё не в кеше (слайдер
5941// тяжёлый, их на странице до девяти — см. \Site\CollectionSlider). Здесь плейсхолдеры
5942// заменяются на настоящий html: сначала те, что рядом с экраном, потом фоном
5943// остальные — они всё равно должны попасть в кеш, иначе следующий посетитель снова
5944// получит плейсхолдеры.
5945const COLLECTION_LAZY_URL = '/ajax/collection_slider.php';
5946const COLLECTION_LAZY_CONCURRENCY = 2;
5947const collectionLazyQueue = [];
5948let collectionLazyActive = 0;
5949
5950// Скрипты, попавшие в DOM через innerHTML, браузер не выполняет, а в html слайдера
5951// есть загрузчик формы Б24 (кнопка «Заказать расчет», /include/catalog/collection_second_btn.php).
5952// Пересоздаём их, чтобы они отработали при вставке.
5953function reviveCollectionScripts(fragment) {
5954    fragment.querySelectorAll('script').forEach(oldScript => {
5955        const script = document.createElement('script');
5956        Array.from(oldScript.attributes).forEach(attr => {
5957            script.setAttribute(attr.name, attr.value);
5958        });
5959        script.textContent = oldScript.textContent;
5960        oldScript.replaceWith(script);
5961    });
5962}
5963
5964function loadLazyCollection(placeholder) {
5965    // подписанные на стороне PHP параметры компонента, подменить их нельзя
5966    const params = placeholder.dataset.collectionLazy;
5967    if (!params) {
5968        return Promise.resolve();
5969    }
5970
5971    return fetch(`${COLLECTION_LAZY_URL}?params=${encodeURIComponent(params)}`, {
5972            credentials: 'same-origin',
5973        })
5974        .then(response => response.ok ? response.text() : Promise.reject(response.status))
5975        .then(html => {
5976            const fragment = document.createElement('template');
5977            fragment.innerHTML = html;
5978            reviveCollectionScripts(fragment.content);
5979            placeholder.replaceWith(fragment.content);
5980            // ищет по документу только неинициализированные элементы, поэтому
5981            // безопасно вызывать после каждой вставки
5982            initCollectionSliders();
5983        })
5984        .catch(error => {
5985            // слайдер не показать - хотя бы убираем зарезервированную под него высоту
5986            placeholder.classList.add('collection_lazy_error');
5987            console.error('collection lazy load failed', error);
5988        });
5989}
5990
5991function collectionLazyNext() {
5992    while ((collectionLazyActive < COLLECTION_LAZY_CONCURRENCY) && collectionLazyQueue.length) {
5993        const placeholder = collectionLazyQueue.shift();
5994        if (!placeholder.isConnected) {
5995            continue;
5996        }
5997        collectionLazyActive++;
5998        loadLazyCollection(placeholder).then(() => {
5999            collectionLazyActive--;
6000            collectionLazyNext();
6001        });
6002    }
6003}
6004
6005function collectionLazyEnqueue(placeholder, priority) {
6006    const queued = collectionLazyQueue.indexOf(placeholder);
6007    if (queued >= 0) {
6008        if (priority && (queued > 0)) {
6009            collectionLazyQueue.splice(queued, 1);
6010            collectionLazyQueue.unshift(placeholder);
6011        }
6012        return;
6013    }
6014    if (placeholder.dataset.collectionLazyQueued) {
6015        return; // уже грузится или загружен
6016    }
6017
6018    placeholder.dataset.collectionLazyQueued = '1';
6019    if (priority) {
6020        collectionLazyQueue.unshift(placeholder);
6021    } else {
6022        collectionLazyQueue.push(placeholder);
6023    }
6024    collectionLazyNext();
6025}
6026
6027function initLazyCollections() {
6028    const placeholders = Array.from(document.querySelectorAll('[data-collection-lazy]'));
6029    if (!placeholders.length) {
6030        return;
6031    }
6032
6033    if (!('IntersectionObserver' in window)) {
6034        placeholders.forEach(placeholder => collectionLazyEnqueue(placeholder, false));
6035        return;
6036    }
6037
6038    const observer = new IntersectionObserver((entries) => {
6039        entries.forEach(entry => {
6040            if (!entry.isIntersecting) {
6041                return;
6042            }
6043            observer.unobserve(entry.target);
6044            collectionLazyEnqueue(entry.target, true);
6045        });
6046    }, { rootMargin: '600px 0px' });
6047
6048    placeholders.forEach(placeholder => observer.observe(placeholder));
6049
6050    // прогрев остальных: с задержкой, чтобы не мешать загрузке самой страницы
6051    setTimeout(() => {
6052        placeholders.forEach(placeholder => collectionLazyEnqueue(placeholder, false));
6053    }, 3000);
6054}
6055
6056window.addEventListener('DOMContentLoaded', () => {
6057    initCollectionSliders();
6058    initLazyCollections();
6059
6060    // Делегируем на document: чипсы фильтра перерисовываются при обновлении выдачи.
6061    document.addEventListener('click', function(e) {
6062        const chip = e.target.closest('.catalog_cards_settings_filter .catalog_cards_filter');
6063        if (!chip) {
6064            return;
6065        }
6066
6067        const tfor = chip.dataset.for;
6068        if (!tfor) {
6069            return;
6070        }
6071
6072        const input = document.getElementById(tfor);
6073        const label = input && collectionSibling(input, 'label');
6074        if (label) {
6075            if (window['smartFilter']) {
6076                window.smartFilter.instantApply = true;
6077            }
6078            label.click();
6079        }
6080        chip.remove();
6081    });
6082})
6083/* End */
6084;
6085; /* Start:"a:4:{s:4:"full";s:65:"/bitrix/templates/portaprima-main/js/swing_door.js?17863453648382";s:6:"source";s:50:"/bitrix/templates/portaprima-main/js/swing_door.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
6086const slider_container = document.querySelector('.slider_container');
6087if (slider_container) {
6088    const slider_right_arrow = document.querySelector('.slider_right_arrow');
6089    const slider_left_arrow = document.querySelector('.slider_left_arrow');
6090    const slide = document.querySelector('.slide');
6091    
6092    let slider_left = 0
6093    let slide_num = 0
6094    let slide_max = document.querySelectorAll('.slide').length
6095    
6096    slider_left_arrow.addEventListener('click', () => {
6097        if (slide_num > 0) {
6098            const slide_width = slide.getBoundingClientRect().width
6099            slide_num -= 1;
6100            slider_container.style.left = `${-slide_width*slide_num}px`
6101        }
6102    })
6103
6104    slider_right_arrow.addEventListener('click', () => {
6105        if (slide_num < (slide_max-1)) {
6106            const slide_width = slide.getBoundingClientRect().width
6107            slide_num += 1;
6108            
6109            slider_container.style.left = `${-slide_width*slide_num}px`
6110            console.log(-slider_left, slide_num)
6111        }
6112    })
6113}
6114
6115// Блоков меток на странице может быть несколько (до и после каталога), поэтому
6116// кнопку «Ещё...» ищем внутри каждого блока, а не по id.
6117const catalog_cards_blocks = [];
6118const catalog_cards_button_hidden = 'catalog_cards_button_more_hidden';
6119
6120document.querySelectorAll('.catalog_cards_button_more').forEach(button => {
6121    const container = button.parentElement;
6122    const filters = container && container.querySelector('.catalog_cards_filters');
6123    if (!filters) {
6124        return;
6125    }
6126
6127    catalog_cards_blocks.push({button, filters, container});
6128
6129    button.addEventListener('click', () => {
6130        const span = button.querySelector('span');
6131        if (filters.classList.contains('active')) {
6132            if (span && button.dataset.more) {
6133                span.innerText = button.dataset.more;
6134            }
6135            button.classList.remove('active');
6136            filters.classList.remove('active');
6137            container.classList.add('catalog_cards_settings_on_compact');
6138        } else  {
6139            if (span && button.dataset.hide) {
6140                span.innerText = button.dataset.hide;
6141            }
6142            button.classList.add('active');
6143            filters.classList.add('active')
6144            container.classList.remove('catalog_cards_settings_on_compact');
6145        }
6146        update_catalog_cards_filters()
6147    });
6148});
6149
6150// Решает две задачи для каждого блока меток:
6151// 1) нужна ли вообще кнопка «Ещё...» — она скрыта разметкой и показывается, только
6152//    если метки не помещаются в одну строку (высота контента больше видимой);
6153// 2) в свёрнутом виде контейнер меток растянут на всю ширину (flex-wrap не даёт ему
6154//    сжаться до фактически занятой строки), из-за чего между последней меткой и
6155//    кнопкой остаётся пустое место. Ужимаем контейнер по правому краю последней
6156//    метки первой строки — сами метки при этом не переносятся.
6157function update_catalog_cards_filters() {
6158    for (const {button, filters, container} of catalog_cards_blocks) {
6159        // сбрасываем ширину до 85% из CSS, чтобы мерить по доступному месту, а не по
6160        // предыдущему (ужатому) значению — иначе блок сможет только уменьшаться
6161        filters.style.width = '';
6162
6163        // мобильная вёрстка (<= 650px) — горизонтальный скролл, кнопка скрыта в CSS
6164        if (innerWidth <= 650) {
6165            continue;
6166        }
6167
6168        // в развёрнутом виде height: auto, переполнения не будет — кнопка нужна
6169        // заведомо, и ужимать контейнер не надо
6170        if (filters.classList.contains('active')) {
6171            continue;
6172        }
6173
6174        const overflows = filters.scrollHeight > filters.clientHeight + 1;
6175        button.classList.toggle(catalog_cards_button_hidden, !overflows);
6176        container.classList.toggle('catalog_cards_settings_on_compact', overflows);
6177        if (!overflows) {
6178            continue;
6179        }
6180
6181        const box = filters.getBoundingClientRect();
6182        const offset = 10;
6183        let row_right = 0;
6184
6185        for (const item of filters.children) {
6186            const rect = item.getBoundingClientRect();
6187            if (rect.top - box.top - offset > 1) {
6188                break; // началась вторая строка
6189            }
6190            row_right = Math.max(row_right, rect.right);
6191        }
6192
6193        if (row_right > 0) {
6194            filters.style.width = Math.ceil(row_right - box.left) + 'px';
6195        }
6196    }
6197}
6198
6199update_catalog_cards_filters()
6200addEventListener('load', update_catalog_cards_filters)
6201
6202let catalog_cards_filters_resize_timer = null;
6203addEventListener('resize', () => {
6204    clearTimeout(catalog_cards_filters_resize_timer)
6205    catalog_cards_filters_resize_timer = setTimeout(update_catalog_cards_filters, 100)
6206})
6207
6208if (innerWidth <= 750) {
6209    const interior_filter_content_texts = document.querySelectorAll('.interior_filter_content_text')
6210    const interior_filter_content_svgs = document.querySelectorAll('.interior_filter_content_svg')
6211    interior_filter_content_texts.forEach(interior_filter_content_text => {
6212        interior_filter_content_text.classList.add('hidden')
6213    })
6214
6215    interior_filter_content_svgs.forEach(interior_filter_content_svg => {
6216        interior_filter_content_svg.classList.remove('active')
6217    })
6218}
6219
6220addEventListener('resize', () => {
6221    if (innerWidth <= 750) {
6222        const interior_filter_content_texts = document.querySelectorAll('.interior_filter_content_text')
6223        const interior_filter_content_svgs = document.querySelectorAll('.interior_filter_content_svg')
6224        interior_filter_content_texts.forEach(interior_filter_content_text => {
6225            interior_filter_content_text.classList.add('hidden')
6226        })
6227    
6228        interior_filter_content_svgs.forEach(interior_filter_content_svg => {
6229            interior_filter_content_svg.classList.remove('active')
6230        })
6231    }
6232})
6233
6234
6235var popupBuy = document.querySelector('.popup_buy');
6236popupBuy && popupBuy.querySelector('.popup_buy_back').addEventListener('click', () => {
6237    popupBuy.classList.remove('active');
6238    document.body.style.overflow = 'visible';
6239    // lower_nav.style.display = "block";
6240})
6241popupBuy && popupBuy.querySelector('.popup_close').addEventListener('click', (e) => {
6242    e.preventDefault();
6243    popupBuy.classList.remove('active');
6244    document.body.style.overflow = 'visible';
6245    // lower_nav.style.display = "block";
6246})
6247
6248const interior_filter_content_mores = document.querySelectorAll('.interior_filter_content_more')
6249
6250interior_filter_content_mores.forEach(interior_filter_content_more => {
6251    interior_filter_content_more.addEventListener('click', (e) => {
6252        e.preventDefault();
6253        const filter = interior_filter_content_more.previousElementSibling;
6254        let expanded = filter.classList.contains('expanded');
6255        if (expanded) {
6256            filter.classList.remove('expanded');
6257            interior_filter_content_more.innerHTML = interior_filter_content_more.dataset.more;
6258        } else {
6259            let checkboxes = filter.querySelectorAll('.interior_filter_content_checkbox');
6260            let expandedHeight = 0;
6261            if (checkboxes.length > 0) {
6262                expandedHeight = checkboxes.length * checkboxes[0].getBoundingClientRect().height;
6263            }
6264            filter.style.setProperty('--expanded-height', expandedHeight + 'px');
6265            filter.classList.add('expanded');
6266            interior_filter_content_more.innerHTML = interior_filter_content_more.dataset.hide;
6267        }
6268    })
6269})
6270/* End */
6271;; /* /bitrix/templates/portaprima-main/js/script.js?178817727080091*/
6272; /* /local/templates/portaprima/js/favorite.js?17865233018641*/
6273; /* /local/templates/.default/components/scody/cookie/.default/script.min.js?17706187851160*/
6274; /* /local/templates/portaprima/js/commonCatalog_new2.js?178403932461193*/
6275; /* /local/templates/portaprima/js/catalogAnalytics.js?178403931620035*/
6276; /* /bitrix/templates/portaprima-main/js/collection.js?178635668142063*/
6277; /* /bitrix/templates/portaprima-main/js/swing_door.js?17863453648382*/

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.