PageSourceSearch

https://severbrilliant.ru/bitrix/templates/severbrilliant/js/js/files/functions.js

js severbrilliant.ru collected 2026-10-08 08:24:45 UTC 15,144 bytes, 392 lines download raw bytes

1// Получение хэша
2export function getHash() {
3    return document.location.hash;
4}
5/* Проверка поддержки webp, добавление класса webp или no-webp для HTML */
6export function isWebp() {
7	// Проверка поддержки webp
8	function testWebP(callback) {
9		let webP = new Image();
10		webP.onload = webP.onerror = function () {
11			callback(webP.height == 2);
12		};
13		webP.src = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
14	}
15	// Добавление класса _webp или _no-webp для HTML
16	testWebP(function (support) {
17		let className = support === true ? 'webp' : 'no-webp';
18		document.documentElement.classList.add(className);
19	});
20}
21//  Вспомогательные модули плавного расскрытия и закрытия объекта
22// Вспомогательные модули плавного расскрытия и закрытия объекта
23export let _slideUp = (target, duration = 500, showmore = 0) => {
24	if (!target.classList.contains('_slide')) {
25		target.classList.add('_slide');
26		target.style.transitionProperty = 'height, margin, padding';
27		target.style.transitionDuration = duration + 'ms';
28		target.style.height = `${target.offsetHeight}px`;
29		target.offsetHeight;
30		target.style.overflow = 'hidden';
31		target.style.height = showmore ? `${showmore}px` : `0px`;
32		target.style.paddingTop = 0;
33		target.style.paddingBottom = 0;
34		target.style.marginTop = 0;
35		target.style.marginBottom = 0;
36		window.setTimeout(() => {
37			target.hidden = !showmore ? true : false;
38			!showmore ? target.style.removeProperty('height') : null;
39			target.style.removeProperty('padding-top');
40			target.style.removeProperty('padding-bottom');
41			target.style.removeProperty('margin-top');
42			target.style.removeProperty('margin-bottom');
43			!showmore ? target.style.removeProperty('overflow') : null;
44			target.style.removeProperty('transition-duration');
45			target.style.removeProperty('transition-property');
46			target.classList.remove('_slide');
47		}, duration);
48	}
49}
50export let _slideDown = (target, duration = 500, showmore = 0) => {
51	if (!target.classList.contains('_slide')) {
52		target.classList.add('_slide');
53		target.hidden = target.hidden ? false : null;
54		showmore ? target.style.removeProperty('height') : null;
55		let height = target.offsetHeight;
56		target.style.overflow = 'hidden';
57		target.style.height = showmore ? `${showmore}px` : `0px`;
58		target.style.paddingTop = 0;
59		target.style.paddingBottom = 0;
60		target.style.marginTop = 0;
61		target.style.marginBottom = 0;
62		target.offsetHeight;
63		target.style.transitionProperty = "height, margin, padding";
64		target.style.transitionDuration = duration + 'ms';
65		target.style.height = height + 'px';
66		target.style.removeProperty('padding-top');
67		target.style.removeProperty('padding-bottom');
68		target.style.removeProperty('margin-top');
69		target.style.removeProperty('margin-bottom');
70		window.setTimeout(() => {
71			target.style.removeProperty('height');
72			target.style.removeProperty('overflow');
73			target.style.removeProperty('transition-duration');
74			target.style.removeProperty('transition-property');
75			target.classList.remove('_slide');
76		}, duration);
77	}
78}
79export let _slideToggle = (target, duration = 500) => {
80	if (target.hidden) {
81		return _slideDown(target, duration);
82	} else {
83		return _slideUp(target, duration);
84	}
85}
86// Вспомогательные модули блокировки прокрутки и скочка
87export let bodyLockStatus = true;
88export let bodyLockToggle = (delay = 500) => {
89	if (document.documentElement.classList.contains('lock')) {
90		bodyUnlock(delay);
91	} else {
92		bodyLock(delay);
93	}
94}
95export let bodyUnlock = (delay = 500) => {
96	let body = document.querySelector("body");
97	if (bodyLockStatus) {
98		let lock_padding = document.querySelectorAll("[data-lp]");
99		setTimeout(() => {
100			for (let index = 0; index < lock_padding.length; index++) {
101				const el = lock_padding[index];
102				el.style.paddingRight = '';
103			}
104			body.style.paddingRight = '';
105			document.documentElement.classList.remove("lock");
106		}, delay);
107		bodyLockStatus = false;
108		setTimeout(function () {
109			bodyLockStatus = true;
110		}, delay);
111	}
112}
113export let bodyLock = (delay = 500) => {
114	let body = document.querySelector("body");
115	if (bodyLockStatus) {
116		let lock_padding = document.querySelectorAll("[data-lp]");
117		for (let index = 0; index < lock_padding.length; index++) {
118			const el = lock_padding[index];
119			// el.style.paddingRight = window.innerWidth - document.querySelector('.wrapper').offsetWidth + 'px';
120			el.style.paddingRight = window.innerWidth - document.body.offsetWidth + 'px';
121		}
122		// body.style.paddingRight = window.innerWidth - document.querySelector('.wrapper').offsetWidth + 'px';
123		body.style.paddingRight = window.innerWidth - document.body.offsetWidth + 'px';
124		document.documentElement.classList.add("lock");
125
126		bodyLockStatus = false;
127		setTimeout(function () {
128			bodyLockStatus = true;
129		}, delay);
130	}
131}
132// Табы
133export function tabs() {
134	const tabs = document.querySelectorAll('[data-tabs]');
135	let tabsActiveHash = [];
136	if (tabs.length > 0) {
137		const hash = getHash();
138		if (hash && hash.startsWith('tab-')) {
139			tabsActiveHash = hash.replace('tab-', '').split('-');
140		}
141		tabs.forEach((tabsBlock, index) => {
142			tabsBlock.classList.add('_tab-init');
143			tabsBlock.setAttribute('data-tabs-index', index);
144			tabsBlock.addEventListener("click", setTabsAction);
145			initTabs(tabsBlock);
146		});
147		// Получение слойлеров с медиа запросами
148		let mdQueriesArray = dataMediaQueries(tabs, "tabs");
149		if (mdQueriesArray && mdQueriesArray.length) {
150			mdQueriesArray.forEach(mdQueriesItem => {
151				// Событие
152				mdQueriesItem.matchMedia.addEventListener("change", function () {
153					setTitlePosition(mdQueriesItem.itemsArray, mdQueriesItem.matchMedia);
154				});
155				setTitlePosition(mdQueriesItem.itemsArray, mdQueriesItem.matchMedia);
156			});
157		}
158	}
159	// Установка позиций заголовков
160	function setTitlePosition(tabsMediaArray, matchMedia) {
161		tabsMediaArray.forEach(tabsMediaItem => {
162			tabsMediaItem = tabsMediaItem.item;
163			let tabsTitles = tabsMediaItem.querySelector('[data-tabs-titles]');
164			let tabsTitleItems = tabsMediaItem.querySelectorAll('[data-tabs-title]');
165			let tabsContent = tabsMediaItem.querySelector('[data-tabs-body]');
166			let tabsContentItems = tabsMediaItem.querySelectorAll('[data-tabs-item]');
167			tabsTitleItems = Array.from(tabsTitleItems).filter(item => item.closest('[data-tabs]') === tabsMediaItem);
168			tabsContentItems = Array.from(tabsContentItems).filter(item => item.closest('[data-tabs]') === tabsMediaItem);
169			tabsContentItems.forEach((tabsContentItem, index) => {
170				if (matchMedia.matches) {
171					tabsContent.append(tabsTitleItems[index]);
172					tabsContent.append(tabsContentItem);
173					tabsMediaItem.classList.add('_tab-spoller');
174				} else {
175					tabsTitles.append(tabsTitleItems[index]);
176					tabsMediaItem.classList.remove('_tab-spoller');
177				}
178			});
179		});
180	}
181	// Работа с контентом
182	function initTabs(tabsBlock) {
183		let tabsTitles = tabsBlock.querySelectorAll('[data-tabs-titles]>*');
184		let tabsContent = tabsBlock.querySelectorAll('[data-tabs-body]>*');
185		const tabsBlockIndex = tabsBlock.dataset.tabsIndex;
186		const tabsActiveHashBlock = tabsActiveHash[0] == tabsBlockIndex;
187
188		if (tabsActiveHashBlock) {
189			const tabsActiveTitle = tabsBlock.querySelector('[data-tabs-titles]>._tab-active');
190			tabsActiveTitle ? tabsActiveTitle.classList.remove('_tab-active') : null;
191		}
192		if (tabsContent.length) {
193			tabsContent = Array.from(tabsContent).filter(item => item.closest('[data-tabs]') === tabsBlock);
194			tabsTitles = Array.from(tabsTitles).filter(item => item.closest('[data-tabs]') === tabsBlock);
195			tabsContent.forEach((tabsContentItem, index) => {
196				tabsTitles[index].setAttribute('data-tabs-title', '');
197				tabsContentItem.setAttribute('data-tabs-item', '');
198
199				if (tabsActiveHashBlock && index == tabsActiveHash[1]) {
200					tabsTitles[index].classList.add('_tab-active');
201				}
202				tabsContentItem.hidden = !tabsTitles[index].classList.contains('_tab-active');
203			});
204		}
205	}
206	function setTabsStatus(tabsBlock) {
207		let tabsTitles = tabsBlock.querySelectorAll('[data-tabs-title]');
208		let tabsContent = tabsBlock.querySelectorAll('[data-tabs-item]');
209		const tabsBlockIndex = tabsBlock.dataset.tabsIndex;
210		function isTabsAnamate(tabsBlock) {
211			if (tabsBlock.hasAttribute('data-tabs-animate')) {
212				return tabsBlock.dataset.tabsAnimate > 0 ? Number(tabsBlock.dataset.tabsAnimate) : 500;
213			}
214		}
215		const tabsBlockAnimate = isTabsAnamate(tabsBlock);
216		if (tabsContent.length > 0) {
217			const isHash = tabsBlock.hasAttribute('data-tabs-hash');
218			tabsContent = Array.from(tabsContent).filter(item => item.closest('[data-tabs]') === tabsBlock);
219			tabsTitles = Array.from(tabsTitles).filter(item => item.closest('[data-tabs]') === tabsBlock);
220			tabsContent.forEach((tabsContentItem, index) => {
221				if (tabsTitles[index].classList.contains('_tab-active')) {
222					if (tabsBlockAnimate) {
223						_slideDown(tabsContentItem, tabsBlockAnimate);
224					} else {
225						tabsContentItem.hidden = false;
226					}
227					if (isHash && !tabsContentItem.closest('.popup')) {
228						setHash(`tab-${tabsBlockIndex}-${index}`);
229					}
230				} else {
231					if (tabsBlockAnimate) {
232						_slideUp(tabsContentItem, tabsBlockAnimate);
233					} else {
234						tabsContentItem.hidden = true;
235					}
236				}
237			});
238		}
239	}
240	function setTabsAction(e) {
241		const el = e.target;
242		if (el.closest('[data-tabs-title]')) {
243			const tabTitle = el.closest('[data-tabs-title]');
244			const tabsBlock = tabTitle.closest('[data-tabs]');
245			if (!tabTitle.classList.contains('_tab-active') && !tabsBlock.querySelector('._slide')) {
246				let tabActiveTitle = tabsBlock.querySelectorAll('[data-tabs-title]._tab-active');
247				tabActiveTitle.length ? tabActiveTitle = Array.from(tabActiveTitle).filter(item => item.closest('[data-tabs]') === tabsBlock) : null;
248				tabActiveTitle.length ? tabActiveTitle[0].classList.remove('_tab-active') : null;
249				tabTitle.classList.add('_tab-active');
250				setTabsStatus(tabsBlock);
251			}
252			e.preventDefault();
253		}
254	}
255}
256//==== Модуь работы с меню (бургер) =======================================================================================================================================================================================================================
257export function menuInit() {
258	const setMenuTop = () => {
259		const burger = document.querySelector('.burger-menu');
260		if (burger) {
261            const wrapperScale = parseFloat(
262                document.querySelector('.wrapper')
263                    .style.transform
264                    .replace(/.*scale\((.*)\).*/, '$1')
265            );
266            const topOffset = window.scrollY / (
267                (isNaN(wrapperScale) || wrapperScale == 0) ? 1 : wrapperScale
268            );
269
270			if (document.documentElement.clientWidth < 460) burger.style.transform = `translateY(${topOffset}px)`
271			else burger.style.transform = ''
272		}
273	}
274	const removeMenuTop = () => {
275		const burger = document.querySelector('.burger-menu');
276		if (burger) {
277			burger.style.transform = ``
278		}
279	}
280	let iconMenus = document.querySelectorAll("[data-burger]");
281	if (iconMenus) {
282		iconMenus.forEach(iconMenu => {
283			iconMenu.addEventListener("click", function (e) {
284				const state = iconMenu.dataset.burger ? iconMenu.dataset.burger : 'close';
285				if (state === 'open') {
286					bodyLock();
287					document.documentElement.classList.add("menu-open");
288					setMenuTop()
289				} else if (state === 'close') {
290					bodyUnlock();
291					document.documentElement.classList.remove("menu-open");
292					document.documentElement.classList.remove("catalog-menu-open");
293					document.documentElement.classList.remove("_only-catalog_")
294					removeMenuTop()
295					// Удалить все менюшки
296					const openedCatalogs = document.querySelectorAll('[data-open]');
297					if (openedCatalogs.length) {
298						openedCatalogs.forEach(catalog => {
299							if (catalog.hasAttribute('data-open')) catalog.removeAttribute('data-open')
300						});
301					}
302				}
303			});
304		});
305	};
306
307	const catalogBtns = document.querySelectorAll('[data-catalog]');
308	if (catalogBtns.length) {
309		catalogBtns.forEach(btn => {
310			btn.addEventListener('click', () => {
311				const catalogSelector = btn.dataset.catalog;
312				const catalog = document.querySelector(`#${catalogSelector}`);
313				if (catalog) {
314					if (!catalog.hasAttribute('data-open')) {
315						bodyLock();
316						if (!document.documentElement.classList.contains("menu-open")) {
317							document.documentElement.classList.add("menu-open")
318							document.documentElement.classList.add("_only-catalog_")
319							setMenuTop()
320						}
321						catalog.setAttribute('data-open', '')
322					} else {
323						catalog.removeAttribute('data-open')
324					}
325				}
326			});
327		});
328	}
329}
330export function menuOpen() {
331	bodyLock();
332	document.documentElement.classList.add("menu-open");
333}
334export function menuClose() {
335	bodyUnlock();
336	document.documentElement.classList.remove("menu-open");
337}
338// Уникализация массива
339export function uniqArray(array) {
340	return array.filter(function (item, index, self) {
341		return self.indexOf(item) === index;
342	});
343}
344// Обработа медиа запросов из атрибутов
345export function dataMediaQueries(array, dataSetValue) {
346	// Получение объектов с медиа запросами
347	const media = Array.from(array).filter(function (item, index, self) {
348		if (item.dataset[dataSetValue]) {
349			return item.dataset[dataSetValue].split(",")[0];
350		}
351	});
352	// Инициализация объектов с медиа запросами
353	if (media.length) {
354		const breakpointsArray = [];
355		media.forEach(item => {
356			const params = item.dataset[dataSetValue];
357			const breakpoint = {};
358			const paramsArray = params.split(",");
359			breakpoint.value = paramsArray[0];
360			breakpoint.type = paramsArray[1] ? paramsArray[1].trim() : "max";
361			breakpoint.item = item;
362			breakpointsArray.push(breakpoint);
363		});
364		// Получаем уникальные брейкпоинты
365		let mdQueries = breakpointsArray.map(function (item) {
366			return '(' + item.type + "-width: " + item.value + "px)," + item.value + ',' + item.type;
367		});
368		mdQueries = uniqArray(mdQueries);
369		const mdQueriesArray = []
370
371		if (mdQueries.length) {
372			// Работаем с каждым брейкпоинтом
373			mdQueries.forEach(breakpoint => {
374				const paramsArray = breakpoint.split(",");
375				const mediaBreakpoint = paramsArray[1];
376				const mediaType = paramsArray[2];
377				const matchMedia = window.matchMedia(paramsArray[0]);
378				// Объекты с нужными условиями
379				const itemsArray = breakpointsArray.filter(function (item) {
380					if (item.value === mediaBreakpoint && item.type === mediaType) {
381						return true;
382					}
383				});
384				mdQueriesArray.push({
385					itemsArray,
386					matchMedia
387				})
388			});
389			return mdQueriesArray;
390		}
391	}
392}

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.