bp/public/assets/js/base.js

190 lines
7.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.

// Скрипт тоггла сайдбара с улучшенной обработкой
document.addEventListener("DOMContentLoaded", function () {
const sidebarToggle = document.getElementById('sidebarToggle');
const sidebarWrapper = document.getElementById('sidebar-wrapper');
const body = document.body;
// Базовая функция для получения base URL (объявляем ДО использования)
const baseUrl = '{{ base_url("/") }}'.replace(/\/+$/, '');
if (sidebarToggle) {
// Обработчик клика
sidebarToggle.addEventListener('click', function (event) {
event.preventDefault();
event.stopPropagation();
// Переключаем класс
body.classList.toggle('sb-sidenav-toggled');
// Сохраняем состояние в localStorage
const isToggled = body.classList.contains('sb-sidenav-toggled');
localStorage.setItem('sidebar-toggled', isToggled);
});
// Закрытие сайдбара при клике вне его (для мобильных)
document.addEventListener('click', function (event) {
if (window.innerWidth <= 768 &&
body.classList.contains('sb-sidenav-toggled') &&
!sidebarWrapper.contains(event.target) &&
event.target !== sidebarToggle &&
!sidebarToggle.contains(event.target)) {
body.classList.remove('sb-sidenav-toggled');
localStorage.setItem('sidebar-toggled', false);
}
});
// Восстановление состояния из localStorage
const sidebarToggled = localStorage.getItem('sidebar-toggled');
if (sidebarToggled === 'true' && window.innerWidth > 768) {
body.classList.add('sb-sidenav-toggled');
}
}
// Адаптивное поведение при изменении размера окна
window.addEventListener('resize', function () {
if (window.innerWidth > 768) {
// На десктопе всегда показываем сайдбар
body.classList.remove('sb-sidenav-toggled');
}
});
// Подсветка активного пункта меню при загрузке
highlightActiveMenuItem();
function highlightActiveMenuItem() {
const currentPath = window.location.pathname;
const menuItems = document.querySelectorAll('.sidebar-link');
menuItems.forEach(item => {
const href = item.getAttribute('href');
if (href && href !== '#' && currentPath.includes(href.replace(baseUrl, ''))) {
item.classList.add('active');
}
});
}
});
(function () {
const cookieName = 'rl_token';
// Проверяем, есть ли кука
const hasCookie = document.cookie.split('; ').find(function (row) {
return row.indexOf(cookieName + '=') === 0;
});
if (!hasCookie) {
// Генерируем UUID v4 на клиенте
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
const token = generateUUID();
const date = new Date();
date.setTime(date.getTime() + (365 * 24 * 60 * 60 * 1000));
const cookieString = cookieName + '=' + token +
'; expires=' + date.toUTCString() +
'; path=/' +
'; SameSite=Lax' +
(location.protocol === 'https:' ? '; Secure' : '');
document.cookie = cookieString;
}
})();
(function() {
'use strict';
/**
* Получение CSRF токена из мета-тега
*/
function getCsrfToken() {
const meta = document.querySelector('meta[name="csrf-token"]');
return meta ? meta.getAttribute('content') : '';
}
/**
* Обновление CSRF токена в мета-теге
*/
function updateCsrfToken(token, hash) {
const tokenMeta = document.querySelector('meta[name="csrf-token"]');
const hashMeta = document.querySelector('meta[name="csrf-hash"]');
if (tokenMeta) tokenMeta.setAttribute('content', token);
if (hashMeta) hashMeta.setAttribute('content', hash);
}
// Перехват fetch()
const originalFetch = window.fetch;
window.fetch = function(url, options = {}) {
// Добавляем CSRF токен в заголовки
if (!options.headers) {
options.headers = {};
}
// Если headers это объект - добавляем токен
if (options.headers instanceof Headers) {
options.headers.set('X-CSRF-TOKEN', getCsrfToken());
} else if (typeof options.headers === 'object') {
options.headers['X-CSRF-TOKEN'] = getCsrfToken();
}
// Выполняем запрос
return originalFetch(url, options).then(response => {
// Проверяем, пришёл ли новый токен в ответе
const newToken = response.headers.get('X-CSRF-TOKEN');
const newHash = response.headers.get('X-CSRF-HASH');
if (newToken && newHash) {
updateCsrfToken(newToken, newHash);
}
return response;
});
};
// Перехват XMLHttpRequest (для jQuery и других библиотек)
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
this._csrfToken = getCsrfToken();
return originalOpen.apply(this, arguments);
};
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(body) {
// Добавляем CSRF токен в заголовки
this.setRequestHeader('X-CSRF-TOKEN', this._csrfToken || getCsrfToken());
// Слушаем ответ для обновления токена
this.addEventListener('load', function() {
const newToken = this.getResponseHeader('X-CSRF-TOKEN');
const newHash = this.getResponseHeader('X-CSRF-HASH');
if (newToken && newHash) {
updateCsrfToken(newToken, newHash);
}
});
return originalSend.apply(this, arguments);
};
// Автоматическое обновление CSRF токена в AJAX формах перед отправкой
document.addEventListener('submit', function(e) {
const form = e.target;
if (form.dataset.ajax === 'true') {
const tokenInput = form.querySelector('input[name="csrf_token"]');
if (tokenInput) {
tokenInput.value = getCsrfToken();
}
}
});
// Обновление CSRF токена в скрытых полях при загрузке страницы (только для AJAX форм)
document.addEventListener('DOMContentLoaded', function() {
const forms = document.querySelectorAll('form[data-ajax="true"]');
forms.forEach(function(form) {
const tokenInput = form.querySelector('input[name="csrf_token"]');
if (tokenInput) {
tokenInput.value = getCsrfToken();
}
});
});
})();