PageSourceSearch

https://vektorvl.ru/local/templates/vector/assets/js/app.js

js vektorvl.ru collected 2026-10-08 14:11:02 UTC 21,194 bytes, 794 lines download raw bytes

1'use strict';
2
3if (app === undefined) {
4	var app = {};
5}
6
7app.swipers = (function() {
8	var mod = {},
9	cache = {
10		modal: null
11	},
12	checkSwiper = function() {
13		return window['Swiper'] !== undefined ? true : false; 
14	},
15	createFancybox = function(images, index) {
16		$.fancybox.open(images, {
17			index : index,
18			padding: 0,
19			margin: 0,
20			helpers: {
21				title: {
22					type: 'inside'
23				}
24			},
25			tpl: {
26				wrap: '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',
27				image: '<img class="fancybox-image" src="{href}" alt="" />',
28			//	iframe: '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0"' + ($.browser.msie ? ' allowtransparency="true"' : '') + '></iframe>',
29				error: '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
30				closeBtn: '<a title="Закрыть" class="fancybox-item fancybox-close" href="javascript:;"><button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></a>',
31				next: '<a title="Следующий" class="fancybox-nav fancybox-next" href="javascript:;"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path class="h-stroke-white" d="M4.172,12.657l5.656,-5.657l-5.656,-5.657" stroke="#1F2330" stroke-width="2"></path></svg></a>',
32				prev: '<a title="Предыдущий" class="fancybox-nav fancybox-prev" href="javascript:;"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M9.828,1.343l-5.656,5.657l5.656,5.657" stroke="#1F2330" stroke-width="2"></path></svg></a>'
33			}
34		}, 1);
35
36		let btn_close_mobile = '<a title="Закрыть" class="fancybox-item fancybox-close fancybox-close-mobile" href="javascript:;"><button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></a>';
37		document.querySelector('.fancybox-wrap').insertAdjacentHTML('afterend', btn_close_mobile);
38
39		document.querySelector('.fancybox-close-mobile').addEventListener('click', function(event) {
40			$.fancybox.close();
41		});
42
43		
44
45	};
46
47	mod.initPlaces = function() {
48		if (checkSwiper()) {
49			cache.swiper_places = new Swiper('#places-swiper', {
50				loop: true,
51				autoplay: {
52					delay: 7000,
53				},
54				navigation: {
55					nextEl: ".swiper-btn-next",
56					prevEl: ".swiper-btn-prev",
57				},
58				pagination: {
59					el: ".swiper-pagination",
60					clickable: true,
61					renderBullet: function (index, className) {
62						let slide = this.el.querySelector('.swiper-slide[data-swiper-slide-index="'+ index +'"]');
63						return '<span class="' + className + '"><span class="vek-bullet-title">'+ slide.getAttribute('data-bullet-title') +'</span></span>';
64					},
65				},
66			});
67
68			if (typeof cache.swiper_places.el === 'object') {
69				cache.swiper_places.pagination.el.classList.add('swiper-pagination-vertical');
70				cache.swiper_places.pagination.el.classList.remove('swiper-pagination-horizontal');
71			}
72		}
73	};
74
75	mod.initEquipments = function() {
76		if (checkSwiper()) {
77			cache.swiper_equipment = new Swiper('#equipment-swiper', {
78				loop: true,
79				slidesPerView: 2,
80				spaceBetween: 15,
81				navigation: {
82					nextEl: ".swiper-btn-next",
83					prevEl: ".swiper-btn-prev",
84				},
85				breakpoints: {
86					1200: {
87						slidesPerView: 6,
88						spaceBetween: 30,
89					},
90					992: {
91						slidesPerView: 5,
92						spaceBetween: 30,
93					},
94					768: {
95						slidesPerView: 4,
96						spaceBetween: 30,
97					},
98					576: {
99						slidesPerView: 3,
100						spaceBetween: 15,
101					}
102				}
103			});
104		}
105	};
106
107	mod.initObjects = function() {
108		if (checkSwiper()) {
109			cache.swiper_objects = new Swiper('#objects-swiper', {
110				loop: true,
111				slidesPerView: 1,
112				navigation: {
113					nextEl: ".swiper-btn-next",
114					prevEl: ".swiper-btn-prev",
115				},
116				breakpoints: {
117					1200: {
118						slidesPerView: 2,
119						spaceBetween: 30,
120					},
121				}
122			});
123		}
124	};
125
126	mod.initNews = function() {
127		if (checkSwiper()) {
128			cache.swiper_news = new Swiper('#news-swiper', {
129				loop: true,
130				slidesPerView: 1,
131				navigation: {
132					nextEl: ".swiper-btn-next",
133					prevEl: ".swiper-btn-prev",
134				},
135				breakpoints: {
136					768: {
137						slidesPerView: 3,
138						spaceBetween: 30,
139					},
140				}
141			});
142		}
143	};
144
145	mod.initAbout = function() {
146		if (checkSwiper()) {
147			cache.swiper_about = new Swiper('#about-company', {
148				loop: true,
149				autoplay: {
150					delay: 7000,
151				},
152				navigation: {
153					nextEl: ".swiper-btn-next",
154					prevEl: ".swiper-btn-prev",
155				},
156			});
157
158			if (typeof cache.swiper_about.el === 'object') {
159				setTimeout(function() {
160					cache.swiper_about.updateSize();
161					cache.swiper_about.update();
162				}, 1500);
163			}
164		}
165	}
166
167	mod.initProduct = function() {
168		if (checkSwiper()) {
169			let swiperElement = document.getElementById('product-swiper')
170			let autoplayProductSwiper 
171			if(swiperElement) {
172				autoplayProductSwiper = swiperElement.querySelectorAll('.swiper-zoom-container').length > 1;
173			}
174			cache.swiper_product = new Swiper('#product-swiper', {
175				loop: true,
176				autoplay: {
177					delay: 7000,
178				},
179				navigation: {
180					nextEl: ".swiper-btn-next",
181					prevEl: ".swiper-btn-prev",
182				},
183			});
184
185			if(swiperElement && !autoplayProductSwiper) {
186				if(cache.swiper_object)
187					cache.swiper_object.autoplay.stop()
188			}
189
190			if (typeof cache.swiper_product.el === 'object') {
191				let btn_fs = document.getElementById('product-swiper').querySelector('.swiper-btn-fullscreen');
192
193				if (btn_fs) {
194					btn_fs.addEventListener('click', function() {
195						let images = [],
196							obj = {};
197
198						for (let j = 0; j < cache.swiper_product.slides.length; j++) {
199							obj = cache.swiper_product.slides[j];
200							images[parseInt(obj.getAttribute('data-swiper-slide-index'))] = {
201								href: obj.querySelector('img').getAttribute('src'),
202								title: obj.getAttribute('aria-label')
203							};
204						}
205						let index = document.getElementById('product-swiper').querySelector('.swiper-slide-active').getAttribute('data-swiper-slide-index');
206						createFancybox(images, index);
207					});
208				}
209			}
210		}
211	};
212
213	mod.initObject = function() {
214		if (checkSwiper()) {
215			let swiperElement = document.getElementById('object-swiper')
216			let autoplayObjectSwiper 
217			if(swiperElement) {
218				autoplayObjectSwiper = swiperElement.querySelectorAll('.swiper-zoom-container').length > 1;
219			}
220
221			cache.swiper_object = new Swiper('#object-swiper', {
222				loop: true,
223				autoplay: {
224					delay: 7000,
225				},
226				navigation: {
227					nextEl: ".swiper-btn-next",
228					prevEl: ".swiper-btn-prev",
229				},
230			});
231			
232			if(swiperElement && !autoplayObjectSwiper) {
233				cache.swiper_object.autoplay.stop()
234			}
235			
236
237			if (typeof cache.swiper_object.el === 'object') {
238				let btn_fs = document.getElementById('object-swiper').querySelector('.swiper-btn-fullscreen');
239
240				if (btn_fs) {
241					btn_fs.addEventListener('click', function() {
242						let images = [],
243							obj = {};
244
245						for (let j = 0; j < cache.swiper_object.slides.length; j++) {
246							obj = cache.swiper_object.slides[j];
247							images[parseInt(obj.getAttribute('data-swiper-slide-index'))] = {
248								href: obj.querySelector('img').getAttribute('src'),
249								title: obj.getAttribute('aria-label')
250							};
251						}
252						console.log('images', images)
253						let index = document.getElementById('object-swiper').querySelector('.swiper-slide-active').getAttribute('data-swiper-slide-index');
254						createFancybox(images, index);
255					});
256				}
257			}
258
259		}
260	};
261
262	return mod;
263})();
264
265app.swipers.initPlaces();
266app.swipers.initEquipments();
267app.swipers.initNews();
268app.swipers.initObjects();
269app.swipers.initProduct();
270app.swipers.initObject();
271app.swipers.initAbout();
272
273
274app.modal_blur = (function() {
275	var mod = {},
276	cache = {
277		content_wrapper: null,
278	},
279	options = {
280		blur_class: 'blur-content'
281	},
282	shonModal = function(event) {
283		cache.content_wrapper.classList.add(options.blur_class);
284	},
285	hideModal = function(event) {
286		cache.content_wrapper.classList.remove(options.blur_class);
287	},
288	setBlurEffect = function(modal) {
289		modal.addEventListener('show.bs.modal', shonModal);
290		modal.addEventListener('hide.bs.modal', hideModal);
291	};
292
293	mod.initBlur = function(modal) {
294		let el_modal = document.querySelector(modal);
295		if (el_modal) {
296			setBlurEffect(el_modal);
297		}
298	};
299
300	mod.init = function() {
301		cache.content_wrapper = document.querySelector('.content-wrapper');
302	};
303
304	return mod;
305})();
306
307app.modal_blur.init();
308app.modal_blur.initBlur('#modal_download_price');
309app.modal_blur.initBlur('#modal_callback');
310app.modal_blur.initBlur('#modal_resume');
311app.modal_blur.initBlur('#modal_resume_reply');
312
313
314app.variant_slide = (function() {
315	var mod = {},
316	cache = {
317		variants: [],
318	},
319	hiddenOtherBlock = function(show_block) {
320		if (show_block) {
321			show_block.classList.remove('show');
322			show_block.classList.add('collapsing');
323		}
324	},
325	eventClickVariant = function(event) {
326		event.preventDefault();
327
328		let var_item = this.closest('.variant-item');
329		let col = parseInt(var_item.getAttribute('data-col'));
330		let wrapper = var_item.closest('.variant-wrapper');
331		let row = parseInt(wrapper.getAttribute('data-row'));
332
333		for (let col_item = 0; col_item < 3; col_item++) {
334
335			if (wrapper.classList.contains('view-col-'+ (col_item + 1))) {
336
337				if (window.screen.width >= 768 || (window.screen.width < 768 && col === col_item)) {
338	
339					var_item.querySelector('.variant-descr').classList.remove('show');
340	
341					setTimeout(function() {
342						var_item.querySelector('.variant-descr').classList.add('collapsing');
343						wrapper.classList.remove('view-col-'+ (col_item + 1));
344
345						if (window.screen.width >= 768) {
346							hiddenOtherBlock(wrapper.querySelector('.variant-descr.show'));
347						}
348	
349						setTimeout(function() {
350							var_item.querySelector('.variant-main').style.width = '';
351						}, 500);
352					}, 150);
353				}
354	
355				if (col === col_item) {
356					return false;
357				}
358			}
359		}
360
361		let el_width = parseFloat(getComputedStyle(var_item.querySelector('.variant-main'), null).width.replace('px', ''));
362
363		var_item.querySelector('.variant-main').style.width = el_width + 'px';
364
365		wrapper.classList.add('view-col-' + (col + 1));
366
367		setTimeout(function() {
368			var_item.querySelector('.variant-descr').classList.remove('collapsing');
369			setTimeout(function() {
370				var_item.querySelector('.variant-descr').classList.add('show');
371			}, 150);
372		}, 350);
373	};
374
375	mod.init = function(variant) {
376		let var_wrapper = document.querySelector(variant);
377		if (var_wrapper) {
378			cache.variants.push(var_wrapper);
379			var_wrapper.setAttribute('data-row', cache.variants.length - 1);
380
381			let var_items = var_wrapper.querySelectorAll('.variant-item');
382
383			for (let i = 0, cnt = var_items.length; i < cnt; i++) {
384				var_items[i].setAttribute('data-col', i);
385				var_items[i].addEventListener('click', eventClickVariant);
386			}
387		}
388		
389	};
390
391	return mod;
392})();
393
394app.variant_slide.init('.variant_1');
395app.variant_slide.init('.variant_2');
396app.variant_slide.init('.variant_3');
397app.variant_slide.init('.variant_4');
398
399
400app.vacancy = (function() {
401	var mod = {},
402	cache = {},
403	eventSwitch = function(event) {
404		event.preventDefault();
405
406		let item = this.closest('.vacancy');
407		let descr = item.querySelector('.vacancy-descr');
408
409		this.querySelector('.arrow-down').classList.toggle('arrow-down-up');
410
411		if (descr.classList.contains('show')) {
412			descr.classList.remove('show');
413			setTimeout(function() {
414				descr.classList.add('collapsing');
415			}, 150);
416		} else {
417			descr.classList.remove('collapsing');
418			setTimeout(function() {
419				descr.classList.add('show');
420			}, 350);
421		}
422	},
423	initSwitch = function(vacancy_block) {
424		let items = vacancy_block.querySelectorAll('.vek-btn-next');
425
426		for (let i = 0, cnt = items.length; i < cnt; i++) {
427			items[i].addEventListener('click', eventSwitch);
428		}
429	}
430
431	mod.init = function() {
432		let vacancy_block = document.querySelector('.vacancy-items');
433
434		if (vacancy_block) {
435			initSwitch(vacancy_block);
436		}
437	};
438
439	return mod;
440})();
441
442app.vacancy.init();
443
444
445app.drop_area = (function() {
446
447	let mod = {},
448	options = {
449		formats: {
450			docs: ['pdf','docx','doc']
451		},
452		error: {
453			docs: 'Не правильный формат файла, загрузите пожалуйста поддерживаемый фомат: PDF, DOCX, DOC'
454		}
455	},
456	preventDefault = function(event) {
457		event.preventDefault();
458		event.stopPropagation();
459	},
460	allowExtension = function(allow_format, ext) {
461		return allow_format.indexOf(ext) !== -1;
462	},
463	handleDrop = function(event) {
464		let dt = event.dataTransfer;
465		let files = dt.files;
466		checkFiles(this, files);
467	},
468	
469	checkFiles = function (drop_area, files) {
470		let file_name_list = drop_area.querySelector('ul');
471		file_name_list.innerHTML = '';
472
473		let file_parts = [],
474			ext = '';
475
476		for (let i = 0; i < files.length; i++) {
477			file_parts = files[i].name.split('.');
478		
479			if (file_parts.length > 1) {
480				ext = file_parts.pop();
481				ext = ext.toLocaleLowerCase();
482
483				if (!allowExtension(options.formats.docs, ext)) {
484					app.messages.error(options.error.docs);
485
486					return false;
487				} else {
488					let elem_file = document.createElement('li');
489					elem_file.innerHTML = '<svg width="11" height="9" class="me-1"><use xlink:href="#checked"></use></svg>'+
490					'<span class="text-decoration-underline">' + files[i].name + '</span>';
491
492					file_name_list.append(elem_file);
493				}
494			}
495		}
496	},
497	initDropAreas = function (areas) {
498		for (let i = 0; i < areas.length; i++) {
499			['dragenter', 'dragover', 'dragleave', 'drop'].forEach(function(eventName) {
500				areas[i].addEventListener(eventName, preventDefault, false);
501			});
502			
503			areas[i].addEventListener('drop', handleDrop, false);
504		}
505	};
506
507	mod.appendFiles = function(elem) {
508		let drop_area = elem.closest('.drop-area');
509		checkFiles(drop_area, elem.files);
510	};
511
512	mod.init = function() {
513		let areas = document.querySelectorAll('.drop-area');
514		if (areas.length) {
515			initDropAreas(areas);
516		}
517	};
518
519	return mod;
520})();
521
522app.drop_area.init();
523
524
525app.messages = (function() {
526	let mod = {},
527	options = {
528		id: 'toast-block'
529	},
530	cache = {
531		toast: null
532	},
533	createMainBlock = function() {
534		let elem = document.createElement('div');
535		elem.className = 'toast-container fixed-bottom start-50 translate-middle-x';
536		elem.id = options.id
537		document.body.appendChild(elem);
538		cache.toast = elem;
539	},
540	errorMsg = function(type, text) {
541		let toast_html = '<div class="toast toast-'+ type +' fade hide">'+
542						'<div class="toast-body">'+
543							text +
544						'</div>'+
545					'</div>';
546		
547		cache.toast.innerHTML = toast_html;
548
549		var toast = new bootstrap.Toast(cache.toast.querySelector('.toast'));
550		toast.show();
551	};
552
553	mod.success = function(text) {
554		errorMsg('success', text);
555	};
556
557	mod.error = function(text) {
558		errorMsg('error', text);
559	};
560
561	mod.init = function() {
562		cache.toast = document.getElementById(options.id);
563		if (cache.toast === null) {
564			createMainBlock();
565		}
566	}
567
568	return mod;
569})();
570
571app.messages.init();
572
573
574app.validate = (function() {
575	let mod = {},
576	options = {
577		errorMessage: {
578			required: 'Заполните все поля',
579			email: 'Некоректно заполнен email',
580			policy: 'Не подтверждена политика конфиденциальности',
581			captcha: 'Не удалось пройти проверку на робота. Обновите страницу и попробуйте ещё раз',
582			send: 'Не удалось отправить данные. Попробуйте позже или позвоните нам'
583		},
584	},
585	/**
586	 * Токен Яндекс SmartCaptcha. Если модуль капчи не подключён —
587	 * отправляем форму как раньше, без токена.
588	 */
589	requestCaptchaToken = function(form) {
590		if (app.smartcaptcha === undefined) {
591			return Promise.resolve('');
592		}
593
594		return app.smartcaptcha.getToken(form);
595	},
596	submitForm = function(event) {
597		let errors = {
598			required: false,
599			email: false,
600			policy: false
601		}
602		event.preventDefault();
603		event.stopPropagation();
604
605		let form = this.closest('form');
606
607
608        let page_info_value = document.title + ' (' + window.location.href.toString() + ')';
609		form.querySelector('[name="page"]').value = page_info_value;
610
611		let h_string = form.querySelector('[name="phone"]').value;
612		form.querySelector('[name="form_h"]').value = h_string.substr(0, 4);
613
614
615
616		let elems_required = form.querySelectorAll('.form-control[required]');
617
618		for (let i = 0; i < elems_required.length; i++) {
619			if (elems_required[i].value === '') {
620				elems_required[i].classList.add('is-invalid');
621				errors.required = true
622			} else {
623				elems_required[i].classList.remove('is-invalid');
624			}
625		}
626
627		let elems_email = form.querySelectorAll('.form-control[email]');
628		const reEmail = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
629		for (let i = 0; i < elems_email.length; i++) {
630			if (!reEmail.test(elems_email[i].value)) {
631				elems_email[i].classList.add('is-invalid');
632				errors.email = true
633			} else {
634				elems_email[i].classList.remove('is-invalid');
635			}
636		}
637
638		let elems_policy = form.querySelectorAll('.form-check-input[policy]');
639
640		for (let i = 0; i < elems_policy.length; i++) {
641			if (!elems_policy[i].checked) {
642				elems_policy[i].classList.add('is-invalid');
643				errors.policy = true
644			} else {
645				elems_policy[i].classList.remove('is-invalid');
646			}
647		}
648
649		if (errors.required) {
650			app.messages.error(options.errorMessage.required);
651			return false;
652		}
653
654		if (errors.email) {
655			app.messages.error(options.errorMessage.email);
656			return false;
657		}
658
659		if (errors.policy) {
660			app.messages.error(options.errorMessage.policy);
661			return false;
662		}
663
664		function closeAllModals() {
665			const modals = document.getElementsByClassName('modal');
666	
667			for(let i=0; i<modals.length; i++) {
668				modals[i].classList.remove('show');
669				modals[i].setAttribute('aria-hidden', 'true');
670				modals[i].setAttribute('style', 'display: none');
671			}
672	
673			 const modalsBackdrops = document.getElementsByClassName('modal-backdrop');
674	
675			 for(let i=0; i<modalsBackdrops.length; i++) {
676				 document.body.removeChild(modalsBackdrops[i]);
677			 }
678			 document.getElementsByClassName('content-wrapper')[0].classList.remove('blur-content');
679			 document.body.removeAttribute('style');
680		}
681
682		
683		
684		async function sendForm() {
685			let response = await fetch(form.action, {
686				method: 'POST',
687				body: new FormData(form)
688			});
689
690			let result = await response.json();
691
692			if(result.status === 'send_complete') {
693				app.messages.success('Данные успешно отправлены');
694				closeAllModals()
695				form.reset();
696				return true;
697			}
698
699			// Данные пользователя не стираем — пусть сможет отправить повторно
700			app.messages.error(
701				result.status === 'captcha_failed'
702					? options.errorMessage.captcha
703					: options.errorMessage.send
704			);
705
706			return false;
707		}
708
709		// Токен капчи запрашиваем в последний момент, когда все остальные
710		// проверки уже пройдены. Кнопку блокируем, чтобы не отправить дважды
711		let button = this;
712		button.disabled = true;
713
714		requestCaptchaToken(form).then(function(token) {
715			if (token === null) {
716				app.messages.error(options.errorMessage.captcha);
717				return false;
718			}
719
720			if (token !== '') {
721				app.smartcaptcha.applyToken(form, token);
722			}
723
724			return sendForm();
725		}).catch(function() {
726			app.messages.error(options.errorMessage.send);
727		}).then(function() {
728			button.disabled = false;
729		});
730
731	},
732	removeInvalid = function(event) {
733		event.currentTarget.classList.remove("is-invalid");
734	};
735
736	mod.init = function() {
737
738		let forms = document.querySelectorAll('form.needs-validation');
739
740		if (forms.length) {
741
742			for (let i = 0; i < forms.length; i++) {
743				forms[i].querySelector('button[type="submit"]').addEventListener('click', submitForm, false);
744			}
745		}
746
747		let inputs = document.querySelectorAll('form input');
748
749		if (inputs.length) {
750
751			for (let i = 0; i < inputs.length; i++) {
752				inputs[i].addEventListener('click', removeInvalid, false);
753			}
754		}
755	};
756
757	return mod;
758})();
759
760app.validate.init();
761
762
763app.navbar_menu = (function() {
764	let mod = {},
765	initMenuToggler = function(navbar_menu) {
766		navbar_menu.addEventListener('click', function(event) {
767			if (this.classList.contains('collapsed')) {
768				document.body.classList.remove('overflow-hidden');
769				document.getElementById('bg_for_menu').remove();
770			} else {
771				addBackdrop();
772				document.body.classList.add('overflow-hidden');
773			}
774		}, false);
775	},
776	addBackdrop = function() {
777		let bg = document.createElement('div');
778		bg.id = 'bg_for_menu';
779		bg.className = 'modal-backdrop modal-backdrop-white';
780		document.body.appendChild(bg);
781	}
782
783
784	mod.init = function() {
785		let navbar_menu = document.querySelector('.navbar-toggler');
786		if (navbar_menu) {
787			initMenuToggler(navbar_menu);
788		}
789	};
790
791	return mod;
792})();
793
794app.navbar_menu.init();

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.