PageSourceSearch

https://i2hard.ru/local/templates/i2hard2020/js/script.js

js i2hard.ru collected 2026-10-02 05:19:50 UTC 17,257 bytes, 554 lines download raw bytes

1// Burger
2// Тогглит класс кнопки бургера и меню
3// Запрещает скролл при открытом меню
4let burgerButton = document.getElementsByClassName("burger")[0];
5let headerMenu = document.getElementsByClassName("header__menu")[0];
6if (burgerButton != null) {
7	burgerButton.addEventListener("mousedown", function (e) {
8		e.preventDefault();
9		this.classList.toggle("burger_active");
10		headerMenu.classList.toggle("header__menu_open");
11		document.body.classList.toggle("no-scroll");
12	});
13}
14
15// Popup
16// Обработчики для открытия и закрытия попапов
17//
18const scrollBarOffset = window.innerWidth - document.querySelector(".wrapper").offsetWidth + "px";
19let popupToggles = Array.from(document.getElementsByClassName("popup__toggle"));
20let popupCloseButtons = Array.from(document.getElementsByClassName("popup__close"));
21let popupWrappers = Array.from(document.getElementsByClassName("popup__wrapper"));
22// Функция открытия попапа
23// Перед открытием нового попапа вызывает функцию закрытия всех попапов на странице
24function popupOpen(el) {
25	popupClose();
26	el.classList.add("popup_open");
27	document.body.classList.add("no-scroll");
28	document.body.style.paddingRight = scrollBarOffset;
29}
30// Функция закрытия попапа
31// Закрывает все попапы без разбора
32function popupClose() {
33	Array.from(document.getElementsByClassName("popup")).forEach(function (el) {
34		el.classList.remove("popup_open");
35	});
36	document.body.classList.remove("no-scroll");
37	document.body.style.paddingRight = 0;
38}
39// Обработчик открывающих попап ссылок с классом .popup__toggle
40// Класс открываемого попапа берется из data-target ссылки
41popupToggles.forEach(function (el) {
42	el.addEventListener("click", function (e) {
43		e.preventDefault();
44		let target = document.getElementsByClassName(this.dataset.target)[0];
45		if (target != null) {
46			popupOpen(target);
47		}
48	});
49});
50// Обработчик крестиков для закрытия попапа
51popupCloseButtons.forEach(function (el) {
52	el.addEventListener("click", function (e) {
53		e.preventDefault();
54		popupClose();
55	});
56});
57// Обработчик для закрытия попапа при клике на темную область
58popupWrappers.forEach(function (el) {
59	el.addEventListener("click", function (e) {
60		if (!e.target.closest(".popup__body")) {
61			popupClose();
62		}
63	});
64});
65// Обработчик нажатия на Esc для закрытия попапа
66document.addEventListener("keydown", function (e) {
67	if (e.key === "Escape") {
68		popupClose();
69		clearSearch();
70	}
71});
72
73// Scrolltop
74// Скроллит страницу вверх при нажатии на соответствующую ссылку
75//
76let scrollTopLink = document.getElementsByClassName("footer__scroll-top-link")[0];
77if (scrollTopLink != null) {
78	scrollTopLink.addEventListener("click", function (e) {
79		e.preventDefault();
80		window.scrollTo({
81			top: 0,
82			left: 0,
83			behavior: "smooth",
84		});
85	});
86}
87
88// Раскрытие списка подкатегорий в тегах
89const tagsSection = Array.from(document.getElementsByClassName("tags__section"));
90if (tagsSection != null) {
91	tagsSection.forEach((el) => {
92		el.addEventListener("mousedown", function (e) {
93			let childItems = this.nextElementSibling;
94
95			this.classList.toggle("tags__section_active");
96			childItems.classList.toggle("tags__child-items_open");
97		});
98	});
99}
100
101// При загрузке страницы css-анимации выключены благодаря классу preload
102window.onload = function () {
103	document.body.classList.remove("preload");
104	initNavLinks();
105	wrapVideoFrames();
106	initLazyLoad();
107	initLightbox();
108};
109
110// Дропдаун со ссылками на доп категории в обзорах
111let subcategoryToggles = Array.from(document.getElementsByClassName("info__subcategory-h
111andle"));
112let listenerDropdownClose = function (e) {
113	if (!e.target.closest(".info__subcategories-list") && !e.target.closest(".info__subcategory-handle")) {
114		dropdownClose();
115	}
116};
117subcategoryToggles.forEach(function (el) {
118	el.addEventListener("click", function (e) {
119		e.preventDefault();
120		if (this.classList.contains("info__subcategory-handle_active")) {
121			dropdownClose();
122			document.body.removeEventListener("mousedown", listenerDropdownClose, false);
123		} else {
124			dropdownOpen(this);
125			document.body.addEventListener("mousedown", listenerDropdownClose, false);
126		}
127	});
128});
129function dropdownOpen(el) {
130	dropdownClose();
131	el.classList.add("info__subcategory-handle_active");
132	el.nextElementSibling.classList.toggle("info__subcategories-list_shown");
133}
134function dropdownClose() {
135	Array.from(document.getElementsByClassName("info__subcategories-list")).forEach(function (el) {
136		el.classList.remove("info__subcategories-list_shown");
137	});
138	Array.from(document.getElementsByClassName("info__subcategory-handle")).forEach(function (el) {
139		el.classList.remove("info__subcategory-handle_active");
140	});
141}
142
143// Раскрытие списка топ 10 на мобилах
144let top10Handle = document.getElementsByClassName("top10-handle")[0];
145let contentColLeft = document.getElementsByClassName("content__col-left")[0];
146let contentColRight = document.getElementsByClassName("content__col-right")[0];
147if (top10Handle != null) {
148	top10Handle.addEventListener("click", function (e) {
149		e.preventDefault();
150		top10Handle.classList.toggle("top10-handle_active");
151		if (contentColLeft) contentColLeft.classList.toggle("content__col-left_open");
152		if (contentColRight) contentColRight.classList.toggle("content__col-right_open");
153	});
154}
155
156// Скрывает хедер при скролле вниз
157const header = document.querySelector(".header");
158let lastScroll = 0;
159function headerVisibility(action) {
160	if (action == "hide") {
161		if (header != null) header.classList.add("header_hidden");
162		if (top10Handle != null) top10Handle.classList.add("top10-handle_offset");
163		searchInput.blur();
164	} else if (action == "show") {
165		if (header != null) header.classList.remove("header_hidden");
166		if (top10Handle != null) top10Handle.classList.remove("top10-handle_offset");
167	}
168}
169window.addEventListener("scroll", () => {
170	const currentScroll = window.pageYOffset;
171	if (currentScroll <= 0) {
172		headerVisibility("show");
173		return;
174	}
175	// 60 - размер хедера
176	if (currentScroll > 60 && currentScroll > lastScroll && !header.classList.contains("header_hidden")) {
177		// вниз
178		headerVisibility("hide");
179	} else if (currentScroll < lastScroll && header.classList.contains("header_hidden")) {
180		// вверх
181		headerVisibility("show");
182	}
183	lastScroll = currentScroll;
184});
185
186
187// Search
188// При нажатии на иконку добавляет полю поиска .search__input_focus и ставит фокус
189// Если у поля поиска есть этот модификатор и значение, то отправляет форму
190let search = document.querySelector(".search");
191
192let searchInput = document.querySelector(".search__input");
193
194let searchIcon = document.querySelector(".search__icon");
195let searchClear = document.querySelector(".search__clear");
196
197let searchWrapper = document.querySelector(".search__wrapper");
198
199let searchSection = document.querySelector(".search__section");
200let searchSectionCurrent = document.querySelector(".search__section .select__current");
201let searchSectionOptions = Array.from(document.querySelectorAll(".search__section .select__option"));
202
203let searchSorting = document.querySelector("#search-sorting");
204
205let searchOptionsButton = document.querySelector(".search__options-button");
206let searchOptions = document.querySelector(".search__options");
207
208let searchInTitleCheckbox = document.querySelector("#search-only-title");
209
210let fetchTimer;
211let preventFold = true;
212
213search.addEventListener("mousedown", function (e) {
214	// Тут все что повлечет за собой blur
215	e.stopPropagation();
216	preventFold = true;
217
218	//console.log("MouseDown: " + e.target.classList[0]);
219
220	if (e.target == searchSection || e.target == searchSectionCurrent) {
221		toggleSection();
222	} else if (e.target == searchOptionsButton) {
223		toggleOptions();
224	} else {
225		// неведомо куда ткнул
226	}
227});
228
229search.addEventListener("click", function (e) {
230	e.stopPropagation();
231	// console.log("Click: " + e.target.classList[0]);
232	preventFold = false;
233
234	if (e.target == searchIcon) {
235		searchUnfold();
236	} else if (e.target == searchClear) {
237		clearSearch();
238	}
239});
240
241searchInput.addEventListener("blur", function () {
242	searchFold();
243});
244
245searchInput.addEventListener("focus", function () {
246	searchSection.classList.remove("select_active");
247	searchOptions.classList.remove("search__options_active");
248});
249
250//searchSectionOptions.
251
252searchSectionOptions.forEach(function (el) {
253	el.addEventListener("click", function (e) {
254		e.preventDefault();
255
256		searchSectionOptions.forEach(function (el) {
257			el.classList.remove("select__selected");
258		});
259
260		searchSection.dataset.value = this.dataset.value;
261		searchSectionCurrent.innerHTML = this.innerHTML;
262		this.classList.add("select__selected");
263		toggleSection();
264		reFetchSuggestions();
265		searchInput.focus();
266	});
267});
268
269// TODO: resetstate() ?
270// Разворачивает поле поиска и фокусит
271function searchUnfold() {
272	search.classList.add("search_open");
273	searchInput.focus();
274}
275// Сворачивает поле поиска (только когда нет фокуса в поле ввода, не открыты настройки и не используется селект раздела)
276function searchFold() {
277	if (!preventFold) {
278		search.classList.remove("search_open");
279	}
280}
281function toggleSection() {
282	// TODO: если ничего нового не появится то запилить .toggle
283	if (searchSection.classList.contains("select_active")) {
284		// close
285		searchSection.classList.remove("select_active");
286	} else {
287		// open
288		searchOptions.classList.remove("search__options_active");
289		searchSection.classList.add("select_active");
290		window.addEventListener(
291			"click",
292			function (e) {
293				if (!e.target.closest(".search__section")) {
294					searchInput.focus();
295					// TODO: не закрывается когда тыкаешь search
296					// TODO: esc
297				}
298			},
299			{
300				once: true,
301			}
302		);
303	}
304}
305// Открывает всплывающее окошко с настройками поиска
306function toggleOptions() {
307	if (searchOptions.classList.contains("search__options_active")) {
308		searchOptions.classList.remove("search__options_active");
309	} else {
310		searchSection.classList.remove("select_active");
311		searchOptions.classList.add("search__options_active");
312		window.addEventListener(
313			"click",
314			function (e) {
315				if (!e.target.closest(".search__options")) {
316					searchInput.focus();
317					// TODO: не закрывается когда тыкаешь search
318					// TODO: esc
319				}
320			},
321			{
322				once: true,
323			}
324		);
325	}
326}
327// Очищает поле ввода
328function clearSearch() {
329	searchInput.value = "";
330	search.classList.remove("search_has-value");
331	reFetchSuggestions();
332	searchInput.focus();
333}
334
335searchInput.addEventListener("keyup", function () {
336	query = this.value;
337	if (query != "") {
338		search.classList.add("search_has-value");
339	} else {
340		search.classList.remove("search_has-value");
341	}
342
343	if (query.length > 1) {
344		if (fetchTimer != null) {
345			clearTimeout(fetchTimer);
346		}
347
348		fetchTimer = setTimeout(function () {
349			fetchSuggestions(query);
350		}, 500);
351	} else {
352		reFetchSuggestions();
353	}
354});
355
356searchInTitleCheckbox.addEventListener("change", function () {
357	reFetchSuggestions();
358});
359
360searchSorting.addEventListener("change", function () {
361	reFetchSuggestions();
362});
363
364function reFetchSuggestions() {
365	if(searchInput.value.length > 1) {
366		fetchSuggestions(query);
367	} else {
368		document.querySelector(".search-preview").remove();
369	}
370}
371
372function showSearchResult(result) {
373	if (result.length > 1) {
374		let oldResults = document.querySelector(".search-preview");
375		if (oldResults != null) oldResults.remove();
376
377		let results = document.createElement("div");
378		results.innerHTML = result;
379		searchWrapper.append(results.querySelector(".search-preview"));
380	}
381}
382
383async function fetchSuggestions(query) {
384	query = query.split(" ").join("+");
385	let section = searchSection.dataset.value;
386	let order = searchSorting.value;
387	let searchInBody;
388	searchInTitleCheckbox.checked ? searchInBody = 0 : searchInBody = 1;
389
390	let url = "/local/templates/i2hard2020/ajax/suggestions.php?QUERY=" + query + "&IBLOCK_ID=" + section + "&ORDER=" + order + "&SEARCH_IN_BODY=" + searchInBody;
391
392	await fetch(url)
393		.then((res) => {
394			return res.text();
395		})
396		.then((data) => {
397			data = data.trim();
398			if (data.length > 1) showSearchResult(data);
399		});
400}
401
402// Таблица сравнения
403let isDown = false;
404let startX;
405let scrollLeft;
406var compareBoxes = Array.from(document.getElementsByClassName('compare__overflow'));
407// Инициализирует таблицу сравнения, вешает эвентлистнеры
408function initCompare() {
409	compareBoxes.forEach(function (el) {
410		el.addEventListener("scroll", () => {
411			checkScrollArrows(el);
412		});
413
414		el.querySelector('.compare__controls-left').addEventListener("click", (e) => {
415			e.preventDefault();
416			el.scrollTo({
417				left: el.scrollLeft - el.clientWidth,
418				behavior: 'smooth'
419			});
420		});
421
422		el.querySelector('.compare__controls-right').addEventListener("click", (e) => {
423			e.preventDefault();
424			el.scrollTo({
425				left: el.scrollLeft + el.clientWidth,
426				behavior: 'smooth'
427			});
428		});
429
430		el.addEventListener('mousedown', (e) => {
431			isDown = true;
432			startX = e.pageX - el.offsetLeft;
433			scrollLeft = el.scrollLeft;
434		});
435
436		el.addEventListener('mouseleave', () => {
437			isDown = false;
438			el.classList.remove('active');
439		});
440
441		el.addEventListener('mouseup', () => {
442			isDown = false;
443		});
444
445		el.addEventListener('mousemove', (e) => {
446			if(!isDown) return;
447			e.preventDefault();
448			const x = e.pageX - el.offsetLeft;
449			const walk = (x - startX);
450			el.scrollLeft = scrollLeft - walk;
451		});
452
453		checkCompareScrollable(el);
454	});
455}
456// Показывает и скрывает стрелки
457function checkCompareScrollable(el) {
458	let compareControls = el.querySelector('.compare__controls');
459	if(el.scrollWidth > el.clientWidth) {
460		checkScrollArrows(el);
461		compareControls.classList.add('compare__controls_open');
462	} else {
463		compareControls.classList.remove('compare__controls_open');
464	}
465}
466// Делает стрелки серыми если скролл в крайнем положении
467function checkScrollArrows(el) {
468	if(el.scrollLeft <= 0) {
469		el.querySelector('.compare__controls-left').classList.add('compare__controls-left_disabled');
470	} else {
471		el.querySelector('.compare__controls-left').classList.remove('compare__controls-left_disabled');
472	}
473
474	if(el.scrollLeft >= (el.scrollWidth - el.clientWidth)) {
475		el.querySelector('.compare__controls-right').classList.add('compare__controls-left_disabled');
476	} else {
477		el.querySelector('.compare__controls-right').classList.remove('compare__controls-left_disabled');
478	}
479}
480
481initCompare();
482window.addEventListener("resize", () => {
483	compareBoxes.forEach(function (el) {
484		checkCompareScrollable(el);
485	});
486});
487
488var lightbox;
489function initLightbox(){
490	let addToLightboxImgs = Array.from(document.querySelectorAll('.article__text a>img'));
491	if(addToLightboxImgs.length > 0){
492		addToLightboxImgs.forEach(function (el) {
493			el.parentElement.classList.add('lightbox');
494		});
495	}
496
497	lightbox = GLightbox({
498		selector: '.lightbox',
499	});
500}
501
502var lazyLoadInstance;
503function initLazyLoad(){
504	lazyLoadInstance = new LazyLoad({
505		class_loaded: "lazy_loaded",
506	});
507}
508
509
510// Навигация внутри статьи (старая и новая)
511function initNavLinks() {
512	const jsGotos = Array.from(document.getElementsByClassName('js-goto'));
513	const spContentElements = Array.from(document.querySelectorAll('.sp-contents_link'));
514
515	if(jsGotos.length > 0){
516		jsGotos.forEach(function (el) {
517			el.addEventListener("click", function (e) {
518				e.preventDefault();
519				el.dataset.to ? navScroll('#' + el.dataset.to) : navScroll(el.getAttribute("href"));
520			});
521		});
522	}
523
524	if(spContentElements.length > 0){
525		spContentElements.forEach(function (el) {
526			el.addEventListener("click", function (e) {
527				e.preventDefault();
528				target = el.getAttribute("href").replace('#','');
529				navScroll('a[name="'+target+'"]');
530			});
531		});
532	}
533
534}
535
536function navScroll(target) {
537	element = document.querySelector(target);
538	if(element){
539		element.scrollIntoView({block: "start", behavior: "smooth"});
540	}
541}
542
543function wrapVideoFrames(){
544	const videoIframes = Array.from(document.querySelectorAll('.news-detail iframe[src*="youtube"]'));
545	if(videoIframes.length > 0){
546		videoIframes.forEach(function (el) {
547			wrapper = document.createElement('div');
548			wrapper.setAttribute('class', 'aspect-ratio-iframe');
549
550			el.parentNode.insertBefore(wrapper, el);
551			wrapper.appendChild(el);
552		});
553	}
554}

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.