PageSourceSearch

https://dental-pro.online/local/templates/new_dental/js/main.js?v=1790143077

js dental-pro.online collected 2026-10-02 05:42:49 UTC 33,378 bytes, 1,130 lines download raw bytes

1$(document).ready(function() {
2	function getAutoplayConfig() {
3		return {
4			delay: 7000,
5			disableOnInteraction: false,
6			pauseOnMouseEnter: true
7		};
8	}
9
10	function getSliderOriginalCount(selector) {
11		var $slider = $(selector);
12
13		if (!$slider.length) {
14			return 0;
15		}
16
17		return $slider.find('.swiper-wrapper > .swiper-slide').not('.swiper-slide-duplicate').length;
18	}
19
20	function getLoopConfig(selector, minSlides) {
21		var count = getSliderOriginalCount(selector);
22		var shouldLoop = count >= (minSlides || 2);
23
24		return {
25			loop: shouldLoop,
26			rewind: !shouldLoop
27		};
28	}
29
30	var topBannerLoopConfig = getLoopConfig('.top-banner__slider', 2);
31
32	new Swiper('.top-banner__slider', {
33		autoplay: topBannerLoopConfig.loop ? getAutoplayConfig() : false,
34		loop: topBannerLoopConfig.loop,
35		rewind: topBannerLoopConfig.rewind,
36		slidesPerView: 1,
37		effect: 'slide',
38		pagination: {
39			el: '.top-banner__pagination',
40			clickable: true
41		},
42		navigation: {
43			nextEl: '.top-banner__button--next',
44			prevEl: '.top-banner__button--prev'
45		}
46	});
47
48	var possibilitiesLoopConfig = getLoopConfig('.possibilities-slider', 2);
49
50	new Swiper('.possibilities-slider', {
51		autoplay: possibilitiesLoopConfig.loop ? {
52			delay: 2000,
53			disableOnInteraction: false,
54			pauseOnMouseEnter: true
55		} : false,
56		loop: possibilitiesLoopConfig.loop,
57		rewind: possibilitiesLoopConfig.rewind,
58		watchOverflow: true,
59		slidesPerView: 'auto',
60		spaceBetween: 20,
61		pagination: {
62			el: '.possibilities .swiper-pagination',
63			clickable: true
64		},
65		navigation: {
66			nextEl: '.possibilities-nav__button--next',
67			prevEl: '.possibilities-nav__button--prev'
68		},
69		breakpoints: {
70			0: {
71				slidesPerView: 'auto',
72				spaceBetween: 12
73			},
74			768: {
75				slidesPerView: 'auto',
76				spaceBetween: 20
77			}
78		}
79	});
80
81	var $historySlider = $('.history-slider');
82
83	if ($historySlider.length) {
84		var historyOriginalCount = parseInt($historySlider.attr('data-history-original-count'), 10) || getSliderOriginalCount('.history-slider');
85		var historyShouldLoop = historyOriginalCount > 1;
86
87		new Swiper('.history-slider', {
88			autoplay: historyShouldLoop ? getAutoplayConfig() : false,
89			loop: historyShouldLoop,
90			rewind: !historyShouldLoop,
91			watchOverflow: true,
92			slidesPerView: 2,
93			slidesPerGroup: 1,
94			spaceBetween: 35,
95			pagination: {
96				el: '.history .swiper-pagination',
97				clickable: true
98			},
99			navigation: {
100				nextEl: '.history-nav__button--next',
101				prevEl: '.history-nav__button--prev'
102			},
103			breakpoints: {
104				0: {
105					slidesPerView: 1,
106					spaceBetween: 16
107				},
108				768: {
109					slidesPerView: 2,
110					spaceBetween: 35
111				}
112			}
113		});
114	}
115
116	var changesLoopConfig = getLoopConfig('.changes-slider', 2);
117
118	new Swiper('.changes-slider', {
119		autoplay: changesLoopConfig.loop ? getAutoplayConfig() : false,
120		loop: changesLoopConfig.loop,
121		rewind: changesLoopConfig.rewind,
122		slidesPerView: 1,
123		spaceBetween: 30,
124		autoHeight: true,
125		pagination: {
126			el: '.changes .swiper-pagination',
127			clickable: true
128		},
129		navigation: {
130			nextEl: '.changes-nav__button--next',
131			prevEl: '.changes-nav__button--prev'
132		}
133	});
134
135	var implementationSwiper = null;
136
137
138	function toggleImplementationSwiper() {
139		if (window.innerWidth > 767) {
140			if (!implementationSwiper) {
141				implementationSwiper = new Swiper('.implementation-slider', {
142					autoplay: {
143						delay: 7000,
144						disableOnInteraction: false,
145						pauseOnMouseEnter: true,
146						stopOnLastSlide: true
147					},
148					loop: false,
149					rewind: false,
150					slidesPerView: 'auto',
151					spaceBetween: 24,
152					pagination: {
153						el: '.implementation .swiper-pagination',
154						clickable: true
155					},
156					navigation: {
157						nextEl: '.implementation-nav__button--next',
158						prevEl: '.implementation-nav__button--prev'
159					}
160				});
161			}
162		} else if (implementationSwiper) {
163			implementationSwiper.destroy(true, true);
164			implementationSwiper = null;
165		}
166	}
167
168	toggleImplementationSwiper();
169
170	$(window).on('resize', function() {
171		toggleImplementationSwiper();
172	});
173
174	var clientsLoopConfig = getLoopConfig('.clients-slider', 5);
175
176	new Swiper('.clients-slider', {
177		autoplay: clientsLoopConfig.loop ? {
178			delay: 1000,
179			disableOnInteraction: false,
180			pauseOnMouseEnter: true
181		} : false,
182		loop: clientsLoopConfig.loop,
183		rewind: clientsLoopConfig.rewind,
184		slidesPerView: 3.9,
185		spaceBetween: 30,
186		pagination: {
187			el: '.clients .swiper-pagination',
188			clickable: true
189		},
190		navigation: {
191			nextEl: '.clients-nav__button--next',
192			prevEl: '.clients-nav__button--prev'
193		},
194		breakpoints: {
195			0: {
196				slidesPerView: 1.12,
197				spaceBetween: 12
198			},
199			768: {
200				slidesPerView: 3.9,
201				spaceBetween: 30
202			}
203		}
204	});
205
206	var benefitsSwiper = null;
207
208	function toggleBenefitsSwiper() {
209		if (window.innerWidth <= 767) {
210			if (!benefitsSwiper) {
211				var benefitsLoopConfig = getLoopConfig('.benefits-slider', 2);
212
213				benefitsSwiper = new Swiper('.benefits-slider', {
214					autoplay: benefitsLoopConfig.loop ? getAutoplayConfig() : false,
215					loop: benefitsLoopConfig.loop,
216					rewind: benefitsLoopConfig.rewind,
217					slidesPerView: 'auto',
218					spaceBetween: 20,
219					freeMode: false
220				});
221			}
222		} else if (benefitsSwiper) {
223			benefitsSwiper.destroy(true, true);
224			benefitsSwiper = null;
225		}
226	}
227
228	toggleBenefitsSwiper();
229
230	$(window).on('resize', function() {
231		toggleBenefitsSwiper();
232	});
233
234	$('.tabs-items a').on('click', function(e) {
235		e.preventDefault();
236		var $tab = $(this);
237		var tabName = $tab.data('tab');
238		var tabTitle = $tab.data('title');
239
240		$tab.addClass('active').siblings().removeClass('active');
241		$('.tabs-selected span').text(tabTitle);
242		$('.tabs-content__item').removeClass('active');
243		$('.tabs-content__item[data-tab-content="' + tabName + '"]').addClass('active');
244	});
245
246	$('.accordion__trigger').on('click', function() {
247		var $item = $(this).closest('.accordion__item');
248		var $accordion = $item.closest('.accordion');
249
250		if ($item.hasClass('active')) {
251			return;
252		}
253
254		$accordion.find('.accordion__item').removeClass('active').find('.accordion__text').slideUp(200);
255		$item.addClass('active').find('.accordion__text').slideDown(200);
256	});
257
258	var reviewsLoopConfig = getLoopConfig('.reviews-slider', 2);
259
260	new Swiper('.reviews-slider', {
261		autoplay: reviewsLoopConfig.loop ? getAutoplayConfig() : false,
262		loop: reviewsLoopConfig.loop,
263		rewind: reviewsLoopConfig.rewind,
264		slidesPerView: 'auto',
265		spaceBetween: 12,
266		pagination: {
267			el: '.reviews-block .swiper-pagination',
268			clickable: true
269		},
270		navigation: {
271			nextEl: '.reviews-nav__button--next',
272			prevEl: '.reviews-nav__button--prev'
273		}
274	});
275
276	$('.mobile-header__menu-btn').on('click', function() {
277		var isOpen = $('body').toggleClass('mobile-menu-open').hasClass('mobile-menu-open');
278		$(this).attr('aria-expanded', isOpen ? 'true' : 'false');
279		$('.mobile-menu').attr('aria-hidden', isOpen ? 'false' : 'true');
280	});
281
282	function closeMobileSubmenu() {
283		$('.mobile-submenu').removeClass('active').attr('aria-hidden', 'true');
284	}
285
286	$('.mobile-menu__close').on('click', function() {
287		$('body').removeClass('mobile-menu-open');
288		$('.mobile-header__menu-btn').attr('aria-expanded', 'false');
289		$('.mobile-menu').attr('aria-hidden', 'true');
290		closeMobileSubmenu();
291	});
292
293	$('.js-mobile-submenu-open').on('click', function(e) {
294		if ($(window).width() > 767) {
295			return;
296		}
297		e.preventDefault();
298		var target = $(this).data('submenu');
299		closeMobileSubmenu();
300		$('#' + target).addClass('active').attr('aria-hidden', 'false');
301	});
302
303	$('.js-mobile-submenu-back').on('click', function() {
304		closeMobileSubmenu();
305	});
306
307
308	$('.mobile-menu a').on('click', function(e) {
309		if ($(window).width() <= 767 && !$(this).hasClass('js-mobile-submenu-open')) {
310			$('body').removeClass('mobile-menu-open');
311			$('.mobile-header__menu-btn').attr('aria-expanded', 'false');
312			$('.mobile-menu').attr('aria-hidden', 'true');
313			closeMobileSubmenu();
314		}
315	});
316
317	function newDentalFormatPhoneNumber(value) {
318		var digits = String(value || '').replace(/\D/g, '');
319		if (!digits.length) {
320			return '';
321		}
322		if (digits.charAt(0) === '8') {
323			digits = '7' + digits.slice(1);
324		}
325		if (digits.charAt(0) !== '7') {
326			digits = '7' + digits;
327		}
328		digits = digits.slice(0, 11);
329		var result = '+7';
330		if (digits.length >= 2) {
331			result += ' (' + digits.slice(1, 4);
332			if (digits.length >= 5) {
333				result += ') ' + digits.slice(4, 7);
334				if (digits.length >= 8) {
335					result += '-' + digits.slice(7, 9);
336					if (digits.length >= 10) {
337						result += '-' + digits.slice(9, 11);
338					}
339				}
340			}
341		}
342		return result;
343	}
344
345	function newDentalApplyPhoneMask(input, withValidation) {
346		if (!input || input.dataset.maskApplied === '1') {
347			return;
348		}
349
350		function validatePhone() {
351			if (!withValidation) {
352				return true;
353			}
354			var digits = input.value.replace(/\D/g, '');
355			if (digits.length !== 11) {
356				input.classList.add('phone-error');
357				return false;
358			}
359			input.classList.remove('phone-error');
360			return true;
361		}
362
363		input.addEventListener('focus', function() {
364			if (!input.value) {
365				input.value = '+7';
366			}
367		});
368
369		input.addEventListener('input', function(e) {
370			var oldValue = e.target.value;
371			var cursorPos = e.target.selectionStart || 0;
372			var newValue = newDentalFormatPhoneNumber(oldValue);
373			if (oldValue !== newValue) {
374				e.target.value = newValue;
375				var digitsBefore = oldValue.slice(0, cursorPos).replace(/\D/g, '').length;
376				var newCursorPos = 0;
377				var digitCount = 0;
378				for (var i = 0; i < newValue.length; i++) {
379					if (digitCount >= digitsBefore) {
380						break;
381					}
382					if (/\d/.test(newValue[i])) {
383						digitCount++;
384					}
385					newCursorPos = i + 1;
386				}
387				if (typeof e.target.setSelectionRange === 'function') {
388					e.target.setSelectionRange(newCursorPos, newCursorPos);
389				}
390			}
391			validatePhone();
392		});
393
394		input.addEventListener('blur', function() {
395			if (input.value.replace(/\D/g, '').length < 4) {
396				input.value = '';
397			}
398			validatePhone();
399		});
400
401		if (input.value) {
402			input.value = newDentalFormatPhoneNumber(input.value);
403		}
404
405		input.dataset.maskApplied = '1';
406		input._newDentalValidatePhone = validatePhone;
407	}
408
409	function newDentalInjectRecaptcha(siteToken, callback) {
410		if (!siteToken) {
411			if (typeof callback === 'function') {
412				callback(false);
413			}
414			return;
415		}
416
417		if (window.grecaptcha && typeof window.grecaptcha.execute === 'function') {
418			if (typeof callback === 'function') {
419				callback(true);
420			}
421			return;
422		}
423
424		var existing = document.querySelector('script[data-demo-recaptcha="1"]');
425		if (existing) {
426			existing.addEventListener('load', function() {
427				if (typeof callback === 'function') {
428					callback(true);
429				}
430			}, {once: true});
431			existing.addEventListener('error', function() {
432				if (typeof callback === 'function') {
433					callback(false);
434				}
435			}, {once: true});
436			return;
437		}
438
439		var script = document.createElement('script');
440		script.src = 'https://www.google.com/recaptcha/api.js?render=' + encodeURIComponent(siteToken);
441		script.async = true;
442		script.defer = true;
443		script.setAttribute('data-demo-recaptcha', '1');
444		script.onload = function() {
445			if (typeof callback === 'function') {
446				callback(true);
447			}
448		};
449		script.onerror = function() {
450			if (typeof callback === 'function') {
451				callback(false);
452			}
453		};
454		document.head.appendChild(script);
455	}
456
457	function newDentalRefreshRecaptchaToken(form, done) {
458		if (!form) {
459			if (typeof done === 'function') {
460				done(false);
461			}
462			return;
463		}
464
465		var tokenField = form.querySelector('[name="recaptcha_response"]');
466		var siteToken = form.getAttribute('data-recaptcha-site-key') || '';
467		if (!tokenField || !siteToken) {
468			if (typeof done === 'function') {
469				done(false);
470			}
471			return;
472		}
473
474		newDentalInjectRecaptcha(siteToken, function(ok) {
475			if (!ok || !window.grecaptcha || typeof window.grecaptcha.ready !== 'function') {
476				if (typeof done === 'function') {
477					done(false);
478				}
479				return;
480			}
481
482			window.grecaptcha.ready(function() {
483				window.grecaptcha.execute(siteToken, {action: 'form_send'}).then(function(token) {
484					tokenField.value = token || '';
485					if (typeof done === 'function') {
486						done(!!token);
487					}
488				}).catch(function() {
489					if (typeof done === 'function') {
490						done(false);
491					}
492				});
493			});
494		});
495	}
496
497	function newDentalInitManagedForms() {
498		var selector = '.investor-form--bitrix, .dp-form--presentation, .dp-form--clients, .dp-form--clients-secondary, .dp-form--blue-section';
499
500		document.querySelectorAll(selector).forEach(function(form) {
501			if (form.dataset.newDentalFormReady === '1') {
502				return;
503			}
504
505			var phoneField = form.querySelector('.js-phone-mask, .phone-mask-field');
506			if (phoneField) {
507				newDentalApplyPhoneMask(phoneField, form.classList.contains('investor-form--bitrix') || form.classList.contains('dp-form--presentation'));
508			}
509
510			newDentalRefreshRecaptchaToken(form);
511
512			form.addEventListener('submit', function(e) {
513				if (phoneField && typeof phoneField._newDentalValidatePhone === 'function' && !phoneField._newDentalValidatePhone()) {
514					e.preventDefault();
515					phoneField.focus();
516					return;
517				}
518
519				var tokenField = form.querySelector('[name="recaptcha_response"]');
520				var siteToken = form.getAttribute('data-recaptcha-site-key') || '';
521				if (!tokenField || tokenField.value || !siteToken) {
522					return;
523				}
524
525				e.preventDefault();
526				newDentalRefreshRecaptchaToken(form, function(ok) {
527					if (ok) {
528						form.submit();
529					}
530				});
531			});
532
533			form.dataset.newDentalFormReady = '1';
534		});
535
536		if (window.BX && typeof BX.addCustomEvent === 'function' && !window.newDentalAjaxFormsBound) {
537			BX.addCustomEvent('onAjaxSuccess', function() {
538				document.querySelectorAll(selector).forEach(function(form) {
539					newDentalRefreshRecaptchaToken(form);
540				});
541			});
542			window.newDentalAjaxFormsBound = true;
543		}
544	}
545
546	function newDentalInitWhoLikesModal() {
547		document.querySelectorAll('[data-who-likes-root="1"]').forEach(function(root) {
548			if (root.dataset.whoLikesReady === '1') {
549				return;
550			}
551
552			var modalId = root.getAttribute('id') ? root.getAttribute('id') + '-modal' : '';
553			var modal = modalId ? document.getElementById(modalId) : null;
554			if (!modal) {
555				return;
556			}
557
558			var modalImage = modal.querySelector('.who-likes-modal__image');
559			var closeModal = function() {
560				modal.classList.remove('is-open');
561				modal.setAttribute('aria-hidden', 'true');
562				document.body.classList.remove('who-likes-modal-open');
563				if (modalImage) {
564					modalImage.setAttribute('src', '');
565				}
566			};
567
568			root.addEventListener('click', function(event) {
569				var hotspot = event.target.closest('.who-likes-visual__hotspot');
570				if (!hotspot || !root.contains(hotspot) || !modalImage) {
571					return;
572				}
573
574				var imageSrc = hotspot.getAttribute('data-modal-image');
575				if (!imageSrc) {
576					return;
577				}
578
579				modalImage.setAttribute('src', imageSrc);
580				modal.classList.add('is-open');
581				modal.setAttribute('aria-hidden', 'false');
582				document.body.classList.add('who-likes-modal-open');
583			});
584
585			modal.addEventListener('click', function(event) {
586				if (event.target.closest('[data-who-likes-close="true"]')) {
587					closeModal();
588				}
589			});
590
591			document.addEventListener('keydown', function(event) {
592				if (event.key === 'Escape' && modal.classList.contains('is-open')) {
593					closeModal();
594				}
595			});
596
597			root.dataset.whoLikesReady = '1';
598		});
599	}
600
601	function newDentalInitFooterModal() {
602		var overlay = document.querySelector('.new-dental-overlay');
603		if (!overlay || overlay.dataset.modalReady === '1') {
604			return;
605		}
606
607		var body = document.body;
608		var formModal = overlay.querySelector('[data-modal="modal1"]');
609		var videoModal = overlay.querySelector('[data-modal="video"]');
610		var videoFrameBox = videoModal ? videoModal.querySelector('.modal__frame') : null;
611		var titleNode = formModal ? formModal.querySelector('.modal-title') : null;
612		var defaultTitle = titleNode ? (titleNode.getAttribute('data-title-standart') || titleNode.textContent) : '';
613
614		function closestNode(node, selector) {
615			while (node && node !== document) {
616				if (node.matches && node.matches(selector)) {
617					return node;
618				}
619				node = node.parentNode;
620			}
621			return null;
622		}
623
624		function closeModal() {
625			overlay.classList.remove('active');
626			if (formModal) {
627				formModal.classList.remove('active');
628			}
629			if (videoModal) {
630				videoModal.classList.remove('active');
631			}
632			if (videoFrameBox) {
633				videoFrameBox.innerHTML = '';
634			}
635			body.classList.remove('lock');
636			if (titleNode) {
637				titleNode.innerHTML = defaultTitle;
638			}
639		}
640
641		function openFormModal(trigger) {
642			if (!formModal) {
643				return;
644			}
645			if (titleNode) {
646				titleNode.innerHTML = trigger && trigger.getAttribute('data-modal-title') ? trigger.getAttribute('data-modal-title') : defaultTitle;
647			}
648			overlay.classList.add('active');
649			formModal.classList.add('active');
650			if (videoModal) {
651				videoModal.classList.remove('active');
652			}
653			body.classList.add('lock');
654			var modalForm = formModal.querySelector('.modal-form');
655			if (modalForm) {
656				modalForm.setAttribute('data-recaptcha-site-key', overlay.getAttribute('data-recaptcha-site-key') || '');
657				newDentalRefreshRecaptchaToken(modalForm);
658			}
659		}
660
661		function buildVideoFrame(trigger) {
662			if (!trigger || !trigger.dataset || !trigger.dataset.video) {
663				return null;
664			}
665			if (trigger.dataset.video.includes('vk.com')) {
666				var videoParts = trigger.dataset.video.split('video');
667				if (!videoParts[1]) {
668					return null;
669				}
670				var idVideo = videoParts[1].split('_');
671				var vkFrame = document.createElement('iframe');
672				vkFrame.setAttribute('title', 'Vk video player');
673				vkFrame.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share');
674				vkFrame.setAttribute('allowfullscreen', '');
675				vkFrame.setAttribute('src', 'https://vk.com/video_ext.php?oid=' + idVideo[0] + '&id=' + idVideo[1] + '&hd=2&autoplay=1');
676				return vkFrame;
677			}
678			if (trigger.dataset.video.includes('rutube.ru')) {
679				var rutubeParts = trigger.dataset.video.split('video');
680				if (!rutubeParts[1]) {
681					return null;
682				}
683				var rutubeFrame = document.createElement('iframe');
684				rutubeFrame.setAttribute('title', 'Rutube video player');
685				rutubeFrame.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share');
686				rutubeFrame.setAttribute('allowfullscreen', '');
687				rutubeFrame.setAttribute('src', 'https://rutube.ru/play/embed' + rutubeParts[1]);
688				return rutubeFrame;
689			}
690			var re = /(?:embed\/|v=|youtu\.be\/|youtube\.com\/user\/\S+#\S+\/\S+\/\S+\/\S+)([^"&?\/\s]{11})/i;
691			var match = trigger.dataset.video.match(re);
692			var youtubeId = match && match[1] ? match[1] : (trigger.dataset.video.length === 11 ? trigger.dataset.video : null);
693			if (!youtubeId) {
694				return null;
695			}
696			var youtubeFrame = document.createElement('iframe');
697			youtubeFrame.setAttribute('title', 'YouTube video player');
698			youtubeFrame.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share');
699			youtubeFrame.setAttribute('allowfullscreen', '');
700			youtubeFrame.setAttribute('src', 'https://www.youtube.com/embed/' + youtubeId);
701			return youtubeFrame;
702		}
703
704		function openVideoModal(trigger) {
705			if (!videoModal || !videoFrameBox) {
706				return;
707			}
708			var frame = buildVideoFrame(trigger);
709			if (!frame) {
710				return;
711			}
712			videoFrameBox.innerHTML = '';
713			videoFrameBox.appendChild(frame);
714			overlay.classList.add('active');
715			videoModal.classList.add('active');
716			if (formModal) {
717				formModal.classList.remove('active');
718			}
719			body.classList.add('lock');
720		}
721
722		var modalForm = formModal ? formModal.querySelector('.modal-form') : null;
723		if (modalForm) {
724			modalForm.setAttribute('data-recaptcha-site-key', overlay.getAttribute('data-recaptcha-site-key') || '');
725			newDentalRefreshRecaptchaToken(modalForm);
726		}
727
728		document.addEventListener('click', function(event) {
729			var formTrigger = closestNode(event.target, '[data-btn="modal1"]');
730			if (formTrigger) {
731				event.preventDefault();
732				openFormModal(formTrigger);
733				return;
734			}
735			var videoTrigger = closestNode(event.target, '[data-btn="video"]');
736			if (videoTrigger) {
737				event.preventDefault();
738				openVideoModal(videoTrigger);
739				return;
740			}
741			if (!overlay.classList.contains('active')) {
742				return;
743			}
744			if (closestNode(event.target, '[data-close]')) {
745				event.preventDefault();
746				closeModal();
747				return;
748			}
749			if (!closestNode(event.target, '.new-dental-overlay .modal')) {
750				closeModal();
751			}
752		});
753
754		document.addEventListener('keydown', function(event) {
755			if (event.key === 'Escape' && overlay.classList.contains('active')) {
756				closeModal();
757			}
758		});
759
760		if (overlay.getAttribute('data-reopen-after-post') === '1' || overlay.querySelector('.new-dental-form-errors') || overlay.querySelector('.form-note') || overlay.querySelector('.errortext')) {
761			openFormModal();
762		}
763
764		overlay.dataset.modalReady = '1';
765	}
766
767	newDentalInitManagedForms();
768	newDentalInitWhoLikesModal();
769	newDentalInitFooterModal();
770
771	var pricingMatrixRaw = $('.pricing').first().attr('data-pricing-matrix');
772	var pricingMatrix = {};
773
774	if (pricingMatrixRaw) {
775		try {
776			pricingMatrix = JSON.parse(pricingMatrixRaw);
777		} catch (e) {
778			pricingMatrix = {};
779		}
780	}
781
782	pricingMatrix = pricingMatrix && Object.keys(pricingMatrix).length ? pricingMatrix : {
783		basic: {
784			"1-2": { "default": 9880, "6": 9386, "12": 8892, "60": 8892 },
785			"3-4": { "default": 13180, "6": 12521, "12": 11862, "60": 11862 },
786			"5+": { "default": 15380, "6": 14611, "12": 13842, "60": 13842 }
787		},
788		pro: {
789			"1-2": { "default": 10980, "6": 10980, "12": 10980, "60": 10980 },
790			"3-4": { "default": 22600, "6": 21470, "12": 18080, "60": 15820 },
791			"5+": { "default": 33200, "6": 31540, "12": 26560, "60": 23240 }
792		}
793	};
794
795	var pricingState = {
796		size: '1-2',
797		term: '12'
798	};
799	var pricingAddonState = {};
800
801	function normalizePricingValue(value) {
802		if (typeof value === 'number') {
803			return value;
804		}
805
806		var parsedValue = parseInt(String(value).replace(/[^\d-]/g, ''), 10);
807		return isNaN(parsedValue) ? 0 : parsedValue;
808	}
809
810	function formatPricingValue(value) {
811		return normalizePricingValue(value).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
812	}
813
814	function setAddonState(addonKey, isActive) {
815		addonKey = String(addonKey);
816
817		pricingAddonState[addonKey] = !!isActive;
818
819		$('[data-pricing-addon-toggle][data-addon-key="' + addonKey + '"]').each(function() {
820			var $button = $(this);
821			$button.toggleClass('is-active', !!isActive);
822			$button.attr('aria-pressed', isActive ? 'true' : 'false');
823			$button.find('.tariff-addon__icon').text(isActive ? '−' : '+');
824		});
825
826		$('[data-pricing-addon-item][data-addon-key="' + addonKey + '"]').toggleClass('is-active', !!isActive);
827
828		$('[data-pricing-mobile-addon-toggle][data-addon-key="' + addonKey + '"]').each(function() {
829			var $button = $(this);
830			$button.toggleClass('is-active', !!isActive);
831			$button.attr('aria-pressed', isActive ? 'true' : 'false');
832			$button.find('.pricing-mobile-addon__icon').text(isActive ? '−' : '+');
833		});
834
835		$('[data-pricing-mobile-addon-item][data-addon-key="' + addonKey + '"]').toggleClass('is-active', !!isActive);
836	}
837
838	function getBasicAddonsTotal() {
839		var total = 0;
840
841		$.each(pricingAddonState, function(addonKey, isActive) {
842			if (!isActive) {
843				return;
844			}
845
846			var $control = $('[data-pricing-addon-toggle][data-addon-key="' + addonKey + '"], [data-pricing-mobile-addon-toggle][data-addon-key="' + addonKey + '"]').first();
847			total += normalizePricingValue($control.data('addon-price'));
848		});
849
850		return total;
851	}
852
853	function getPricingValue(tariffCode) {
854		if (!pricingMatrix[tariffCode] || !pricingMatrix[tariffCode][pricingState.size]) {
855			return 0;
856		}
857
858		var sizeData = pricingMatrix[tariffCode][pricingState.size];
859		var baseValue = 0;
860
861		if (typeof sizeData[pricingState.term] !== 'undefined') {
862			baseValue = normalizePricingValue(sizeData[pricingState.term]);
863		} else if (typeof sizeData['default'] !== 'undefined') {
864			baseValue = normalizePricingValue(sizeData['default']);
865		}
866
867		if (tariffCode === 'basic') {
868			baseValue += getBasicAddonsTotal();
869		}
870
871		return baseValue;
872	}
873
874	function updatePricing() {
875		var basicValue = getPricingValue('basic');
876		var proValue = getPricingValue('pro');
877
878		$('[data-pricing-basic-mobile]').text('от ' + formatPricingValue(basicValue) + ' ₽/мес');
879		$('[data-pricing-pro-mobile]').text('от ' + formatPricingValue(proValue) + ' ₽/мес');
880		$('[data-pricing-basic-mobile-bottom]').text('от ' + formatPricingValue(basicValue) + ' ₽ в мес');
881		$('[data-pricing-basic-desktop]').text('от ' + formatPricingValue(basicValue) + ' ₽ в мес');
882		$('[data-pricing-pro-desktop]').text('от ' + formatPricingValue(proValue) + ' ₽ в мес');
883	}
884
885	$('[data-pricing-term]').on('click', function() {
886		var $button = $(this);
887		var isActive = $button.hasClass('active');
888
889		$('[data-pricing-term]').removeClass('active');
890
891		if (isActive) {
892			$button.addClass('active');
893			pricingState.term = $button.data('pricing-term').toString();
894			updatePricing();
895			return;
896		}
897
898		$button.addClass('active');
899		pricingState.term = $button.data('pricing-term').toString();
900		updatePricing();
901	});
902
903	$('[data-pricing-size]').on('click', function() {
904		var $button = $(this);
905
906		$('[data-pricing-size]').removeClass('active');
907		$button.addClass('active');
908
909		pricingState.size = $button.data('pricing-size').toString();
910		updatePricing();
911	});
912
913	$('[data-pricing-addon-toggle], [data-pricing-mobile-addon-toggle]').each(function() {
914		var addonKey = String($(this).data('addon-key'));
915		if (typeof pricingAddonState[addonKey] === 'undefined') {
916			pricingAddonState[addonKey] = $(this).hasClass('is-active');
917		}
918	});
919
920	$('[data-pricing-addon-toggle]').on('click', function() {
921		var $button = $(this);
922		setAddonState($button.data('addon-key'), !$button.hasClass('is-active'));
923		updatePricing();
924	});
925
926	$('[data-pricing-mobile-addon-toggle]').on('click', function(e) {
927		e.preventDefault();
928		e.stopPropagation();
929
930		var $button = $(this);
931		setAddonState($button.data('addon-key'), !$button.hasClass('is-active'));
932		updatePricing();
933	});
934
935	$('[data-pricing-mobile-addons-toggle]').on('click', function() {
936		var $button = $(this);
937		var $panel = $('#' + $button.attr('aria-controls'));
938		var isOpen = $button.hasClass('is-open');
939
940		$button.toggleClass('is-open', !isOpen);
941		$button.attr('aria-expanded', isOpen ? 'false' : 'true');
942
943		if (isOpen) {
944			$panel.stop(true, true).slideUp(200, function() {
945				$panel.prop('hidden', true);
946			});
947			return;
948		}
949
950		$panel.prop('hidden', false).hide().stop(true, true).slideDown(200);
951	});
952
953	$.each(pricingAddonState, function(addonKey, isActive) {
954		setAddonState(addonKey, isActive);
955	});
956
957	updatePricing();
958
959	$('.faq-item__head').on('click', function() {
960		var $item = $(this).closest('.faq-item');
961		if ($item.hasClass('active')) {
962			$item.removeClass('active');
963			$item.find('.faq-item__body').slideUp(200);
964			$(this).attr('aria-expanded', 'false');
965			return;
966		}
967		$('.faq-item').removeClass('active').find('.faq-item__body').slideUp(200);
968		$('.faq-item__head').attr('aria-expanded', 'false');
969		$item.addClass('active');
970		$item.find('.faq-item__body').slideDown(200);
971		$(this).attr('aria-expanded', 'true');
972	});
973
974	var $topBannerModal = $('.top-banner-modal');
975	var $topBannerModalImage = $('.top-banner-modal__image');
976
977	function closeTopBannerModal() {
978		$topBannerModal.removeClass('is-open').attr('aria-hidden', 'true');
979		$('body').removeClass('top-banner-modal-open');
980		$topBannerModalImage.attr('src', '');
981	}
982
983	$('.top-banner__hotspot').on('click', function() {
984		var imageSrc = $(this).data('modal-image');
985		if (!imageSrc) {
986			return;
987		}
988
989		$topBannerModalImage.attr('src', imageSrc);
990		$topBannerModal.addClass('is-open').attr('aria-hidden', 'false');
991		$('body').addClass('top-banner-modal-open');
992	});
993
994	$('.top-banner-modal__close, .top-banner-modal__overlay').on('click', function() {
995		closeTopBannerModal();
996	});
997
998	$(document).on('keydown', function(e) {
999		if (e.key === 'Escape' && $topBannerModal.hasClass('is-open')) {
1000			closeTopBannerModal();
1001		}
1002	});
1003
1004	function initStickyHeaderBottom() {
1005		var $headerBottom = $('.js-header-bottom').first();
1006		var $placeholder = $('.header__bottom-placeholder').first();
1007
1008		if (!$headerBottom.length || !$placeholder.length) {
1009			return;
1010		}
1011
1012		var stickyTop = 0;
1013		var stickyStart = 0;
1014
1015		function getAdminOffset() {
1016			var $adminPanel = $('#bx-panel');
1017			if ($adminPanel.length && $adminPanel.is(':visible')) {
1018				return $adminPanel.outerHeight();
1019			}
1020			return 0;
1021		}
1022
1023		function disableSticky() {
1024			$headerBottom.removeClass('header__bottom--fixed').css('top', '');
1025			$placeholder.hide().height(0);
1026		}
1027
1028		function recalcSticky() {
1029			if ($(window).width() <= 767) {
1030				disableSticky();
1031				return;
1032			}
1033
1034			stickyTop = getAdminOffset();
1035
1036			var wasFixed = $headerBottom.hasClass('header__bottom--fixed');
1037			if (wasFixed) {
1038				$headerBottom.removeClass('header__bottom--fixed').css('top', '');
1039			}
1040
1041			$placeholder.hide().height(0);
1042			stickyStart = $headerBottom.offset().top - stickyTop;
1043
1044			if (wasFixed) {
1045				updateSticky();
1046			}
1047		}
1048
1049		function updateSticky() {
1050			if ($(window).width() <= 767) {
1051				disableSticky();
1052				return;
1053			}
1054
1055			var shouldFix = $(window).scrollTop() >= stickyStart;
1056
1057			if (shouldFix) {
1058				$placeholder.show().height($headerBottom.outerHeight());
1059				$headerBottom.addClass('header__bottom--fixed').css('top', stickyTop + 'px');
1060			} else {
1061				disableSticky();
1062			}
1063		}
1064
1065		recalcSticky();
1066		updateSticky();
1067
1068		$(window).on('scroll.stickyHeaderBottom', updateSticky);
1069		$(window).on('resize.stickyHeaderBottom orientationchange.stickyHeaderBottom', function() {
1070			recalcSticky();
1071			updateSticky();
1072		});
1073	}
1074
1075	initStickyHeaderBottom();
1076
1077	function initMetrikaRecordKeys() {
1078		var selector = [
1079			'.dp-form input:not([type="hidden"]):not([type="password"]):not([type="file"])',
1080			'.dp-form textarea',
1081			'.dp-form select',
1082			'.investor-form--bitrix input:not([type="hidden"]):not([type="password"]):not([type="file"])',
1083			'.investor-form--bitrix textarea',
1084			'.investor-form--bitrix select'
1085		].join(',');
1086
1087		document.querySelectorAll(selector).forEach(function(field) {
1088			field.classList.add('ym-record-keys');
1089		});
1090	}
1091
1092	initMetrikaRecordKeys();
1093	//calltouch
1094	(function(w,d,n,c){w.CalltouchDataObject=n;w[n]=function(){w[n]["callbacks"].push(arguments)};if(!w[n]["callbacks"]){w[n]["callbacks"]=[]}w[n]["loaded"]=false;if(typeof c!=="object"){c=[c]}w[n]["counters"]=c;for(var i=0;i<c.length;i+=1){p(c[i])}function p(cId){var a=d.getElementsByTagName("script")[0],s=d.createElement("script"),i=function(){a.parentNode.insertBefore(s,a)},m=typeof Array.prototype.find === 'function',n=m?"init-min.js":"init.js";s.async=true;s.src="https://mod.calltouch.ru/"+n+"?id="+cId;if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",i,false)}else{i()}}})(window,document,"ct","x5ca8qhp");
1095
1096	Element.prototype.matches || (Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector), Element.prototype.closest || (Element.prototype.closest = function (e) { for (var t = this; t;) { if (t.matches(e)) return t; t = t.parentElement } return null });
1097	var ct_get_val = function (form, selector) { if (!!form.querySelector(selector)) { return form.querySelector(selector).value; console.log(form.querySelector(selector)) } else { return ''; } };
1098	function SendCalltouch(t_el) {
1099		if (t_el.closest('form [type="submit"]')) {
1100			try {
1101				var form = t_el.closest('form');
1102				var fio = ct_get_val(form, 'input[name="form_text_1"], input[name="form_text_7"], input[placeholder*="имя"]');
1103				var phoneNumber = ct_get_val(form, 'input[type="tel"]');
1104				var email = ct_get_val(form, 'input[name*="email"]');
1105				var subject = 'Заявка с ' + location.hostname;
1106				var ct_site_id = 51456;
1107				var ct_data = {
1108					fio: fio,
1109					phoneNumber: phoneNumber,
1110					email: email,
1111					subject: subject,
1112					requestUrl: location.href,
1113					sessionId: window.call_value
1114				};
1115				var post_data = Object.keys(ct_data).reduce(function (a, k) { if (!!ct_data[k]) { a.push(k + '=' + encodeURIComponent(ct_data[k])); } return a }, []).join('&');
1116				var CT_URL = 'https://api.calltouch.ru/calls-service/RestAPI/requests/' + ct_site_id + '/register/';
1117				var ct_valid = !!phoneNumber && phoneNumber.replace(/[^0-9]/gim, '').length > 9;
1118				if (ct_valid && !window.ct_snd_flag) {
1119					console.log('Отправлено в Calltouch', ct_data);
1120					window.ct_snd_flag = 1; setTimeout(function () { window.ct_snd_flag = 0; }, 15000);
1121					var request = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
1122					request.open("POST", CT_URL, true); request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1123					request.send(post_data);
1124				}
1125			} catch (e) { console.log(e); }
1126		}
1127	}
1128	document.addEventListener('click', function (e) { SendCalltouch(e.target) });
1129	//calltouch
1130});

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.