/* ========================================================================== Шапка сайта по макету 2026 (tpl/blocks/header.tpl, styles/layout.css): выпадающие меню (наведение на десктопе, клик / Esc / клик вне — везде), поиск, бургер. Перенесено из вёрстки task3/script.js. Подключается на всех страницах. ========================================================================== */ (function () { 'use strict'; var mobileQuery = window.matchMedia('(max-width: 1240px)'); var hoverQuery = window.matchMedia('(hover: hover)'); /* ------------------------------------------------------------------------ Шапка ------------------------------------------------------------------------ */ var header = document.querySelector('[data-header]'); var menuToggle = document.querySelector('[data-menu-toggle]'); var searchToggle = document.querySelector('[data-search-toggle]'); var searchForm = document.getElementById('hp-header-search'); var dropdowns = Array.prototype.slice.call(document.querySelectorAll('[data-dropdown]')); function setDropdown(item, open) { item.classList.toggle('is-open', open); item.querySelector('[data-dropdown-toggle]').setAttribute('aria-expanded', String(open)); } function closeDropdowns(except) { dropdowns.forEach(function (item) { if (item !== except) setDropdown(item, false); }); } dropdowns.forEach(function (item) { var toggle = item.querySelector('[data-dropdown-toggle]'); toggle.addEventListener('click', function () { var open = !item.classList.contains('is-open'); closeDropdowns(item); setDropdown(item, open); }); // на десктопе список открывается при наведении (CSS) — синхронизируем aria item.addEventListener('mouseenter', function () { if (hoverQuery.matches && !mobileQuery.matches) toggle.setAttribute('aria-expanded', 'true'); }); item.addEventListener('mouseleave', function () { if (hoverQuery.matches && !mobileQuery.matches) setDropdown(item, false); }); }); function setMenu(open) { if (!header || !menuToggle) return; header.classList.toggle('is-menu-open', open); menuToggle.setAttribute('aria-expanded', String(open)); document.body.classList.toggle('is-locked', open && mobileQuery.matches); if (open) setSearch(false); } function setSearch(open) { if (!searchForm || !searchToggle) return; searchForm.hidden = !open; searchToggle.setAttribute('aria-expanded', String(open)); if (open) { setMenu(false); searchForm.querySelector('input').focus(); } } if (menuToggle) { menuToggle.addEventListener('click', function () { setMenu(!header.classList.contains('is-menu-open')); }); } if (searchToggle) { searchToggle.addEventListener('click', function () { setSearch(searchForm.hidden); }); } // пустой запрос не отправляем if (searchForm) { searchForm.addEventListener('submit', function (event) { var input = searchForm.querySelector('input'); if (!input.value.trim()) { event.preventDefault(); input.focus(); } }); } // клик вне меню закрывает выпадающие списки document.addEventListener('click', function (event) { if (!event.target.closest('[data-dropdown]')) closeDropdowns(); }); // Esc закрывает всё открытое document.addEventListener('keydown', function (event) { if (event.key !== 'Escape') return; var openItem = dropdowns.filter(function (item) { return item.classList.contains('is-open'); })[0]; if (openItem) { setDropdown(openItem, false); openItem.querySelector('[data-dropdown-toggle]').focus(); } else if (searchForm && !searchForm.hidden) { setSearch(false); searchToggle.focus(); } else if (header && header.classList.contains('is-menu-open')) { setMenu(false); menuToggle.focus(); } }); // переход по якорю из мобильного меню закрывает меню if (header) { header.addEventListener('click', function (event) { var link = event.target.closest('a[href^="#"]'); if (link) { closeDropdowns(); setMenu(false); } }); } // при переходе на десктоп сбрасываем мобильное состояние function onBreakpointChange() { if (!mobileQuery.matches) setMenu(false); closeDropdowns(); } if (mobileQuery.addEventListener) { mobileQuery.addEventListener('change', onBreakpointChange); } else if (mobileQuery.addListener) { mobileQuery.addListener(onBreakpointChange); } })();