Corp/backend/static/js/navbar-mobile-search.js
Игорь Надеин ddf22c47da fix: автоматическое обновление JWT токенов
- ApiClient теперь обрабатывает 401 и 403 ошибки для обновления токена
- Добавлен JWTRefreshMiddleware для проактивного обновления токенов за 5 минут до истечения
- Добавлена настройка JWT_REFRESH_THRESHOLD_MINUTES (по умолчанию 5)
- Исправлена проблема с периодическими 403 ошибками после истечения access token
2025-11-20 18:52:29 +03:00

157 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* navbar-mobile-search.js
* Управление мобильным поиском в navbar
*/
(function() {
'use strict';
// Элементы
const searchToggle = document.querySelector('.mobile-search-toggle');
const searchInput = document.querySelector('.mobile-search-input');
const searchForm = document.querySelector('.mobile-search-form');
const navbarIcons = document.querySelectorAll('.navbar-icon');
const navbarBrand = document.querySelector('.navbar-brand-item');
const navbarRight = document.querySelector('.navbar-right');
if (!searchToggle || !searchInput) return;
let isSearchOpen = false;
let searchOverlay = null;
// Создать оверлей
function createOverlay() {
if (!searchOverlay) {
searchOverlay = document.createElement('div');
searchOverlay.className = 'mobile-search-overlay';
document.body.appendChild(searchOverlay);
}
}
// Показать оверлей
function showOverlay() {
createOverlay();
setTimeout(() => {
searchOverlay.classList.add('active');
}, 10);
}
// Скрыть оверлей
function hideOverlay() {
if (searchOverlay) {
searchOverlay.classList.remove('active');
}
}
// Открыть/закрыть поиск
function toggleMobileSearch() {
isSearchOpen = !isSearchOpen;
if (isSearchOpen) {
// Открыть поиск
searchToggle.classList.add('d-none');
searchInput.classList.remove('d-none');
searchInput.classList.add('d-flex');
// Показать оверлей
showOverlay();
// Скрыть остальные элементы на мобильном
navbarIcons.forEach(icon => {
if (window.innerWidth < 768) {
icon.classList.add('d-none');
}
});
if (window.innerWidth < 768) {
if (navbarBrand) navbarBrand.classList.add('d-none');
if (navbarRight) navbarRight.classList.add('d-none');
}
// Фокус на инпут
const input = searchInput.querySelector('input');
if (input) {
setTimeout(() => input.focus(), 100);
}
} else {
// Закрыть поиск
closeMobileSearch();
}
}
function closeMobileSearch() {
isSearchOpen = false;
searchToggle.classList.remove('d-none');
searchInput.classList.add('d-none');
searchInput.classList.remove('d-flex');
// Скрыть оверлей
hideOverlay();
// Показать остальные элементы
navbarIcons.forEach(icon => icon.classList.remove('d-none'));
if (navbarBrand) navbarBrand.classList.remove('d-none');
if (navbarRight) navbarRight.classList.remove('d-none');
}
// Клик на иконку поиска
searchToggle.addEventListener('click', toggleMobileSearch);
// Закрыть при клике вне поиска
document.addEventListener('click', (e) => {
if (!isSearchOpen) return;
// Проверяем, был ли клик вне формы поиска (или на оверлей)
if (!searchForm.contains(e.target) || e.target === searchOverlay) {
closeMobileSearch();
}
});
// Закрыть при нажатии Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && isSearchOpen) {
closeMobileSearch();
}
});
// Отправка формы - отключаем неактивный input
searchForm.addEventListener('submit', (e) => {
const mobileInput = document.getElementById('mobileSearchInput');
const desktopInput = document.getElementById('desktopSearchInput');
// Определяем какой input активен
const isMobile = window.innerWidth < 768;
if (isMobile) {
// На мобильном отключаем десктопный
if (desktopInput) desktopInput.disabled = true;
// Проверяем что мобильный не пустой
if (!mobileInput || !mobileInput.value.trim()) {
e.preventDefault();
if (desktopInput) desktopInput.disabled = false;
return;
}
} else {
// На десктопе отключаем мобильный
if (mobileInput) mobileInput.disabled = true;
// Проверяем что десктопный не пустой
if (!desktopInput || !desktopInput.value.trim()) {
e.preventDefault();
if (mobileInput) mobileInput.disabled = false;
return;
}
}
// Форма отправится с одним активным полем
});
// Закрыть при изменении размера окна на десктоп
window.addEventListener('resize', () => {
if (window.innerWidth >= 768 && isSearchOpen) {
closeMobileSearch();
}
});
})();