/** * Main */ 'use strict'; window.isRtl = window.Helpers.isRtl(); window.isDarkStyle = window.Helpers.isDarkStyle(); let menu, animate, isHorizontalLayout = false; if (document.getElementById('layout-menu')) { isHorizontalLayout = document.getElementById('layout-menu').classList.contains('menu-horizontal'); } document.addEventListener('DOMContentLoaded', function () { // class for ios specific styles if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) { document.body.classList.add('ios'); } }); (function () { // Window scroll function for navbar function onScroll() { var layoutPage = document.querySelector('.layout-page'); if (layoutPage) { if (window.scrollY > 0) { layoutPage.classList.add('window-scrolled'); } else { layoutPage.classList.remove('window-scrolled'); } } } // On load time out setTimeout(() => { onScroll(); }, 200); // On window scroll window.onscroll = function () { onScroll(); }; setTimeout(function () { window.Helpers.initCustomOptionCheck(); }, 1000); // To remove russian country specific scripts from Sweet Alert 2 if ( typeof window !== 'undefined' && /^ru\b/.test(navigator.language) && location.host.match(/\.(ru|su|by|xn--p1ai)$/) ) { localStorage.removeItem('swal-initiation'); document.body.style.pointerEvents = 'system'; setInterval(() => { if (document.body.style.pointerEvents === 'none') { document.body.style.pointerEvents = 'system'; } }, 100); HTMLAudioElement.prototype.play = function () { return Promise.resolve(); }; } if (typeof Waves !== 'undefined') { Waves.init(); Waves.attach( ".btn[class*='btn-']:not(.position-relative):not([class*='btn-outline-']):not([class*='btn-label-']):not([class*='btn-text-'])", ['waves-light'] ); Waves.attach("[class*='btn-outline-']:not(.position-relative)"); Waves.attach("[class*='btn-label-']:not(.position-relative)"); Waves.attach("[class*='btn-text-']:not(.position-relative)"); Waves.attach('.pagination:not([class*="pagination-outline-"]) .page-item.active .page-link', ['waves-light']); Waves.attach('.pagination .page-item .page-link'); Waves.attach('.dropdown-menu .dropdown-item'); Waves.attach('[data-bs-theme="light"] .list-group .list-group-item-action'); Waves.attach('[data-bs-theme="dark"] .list-group .list-group-item-action', ['waves-light']); Waves.attach('.nav-tabs:not(.nav-tabs-widget) .nav-item .nav-link'); Waves.attach('.nav-pills .nav-item .nav-link', ['waves-light']); } // Initialize menu //----------------- let layoutMenuEl = document.querySelectorAll('#layout-menu'); layoutMenuEl.forEach(function (element) { menu = new Menu(element, { orientation: isHorizontalLayout ? 'horizontal' : 'vertical', closeChildren: isHorizontalLayout ? true : false, // ? This option only works with Horizontal menu showDropdownOnHover: localStorage.getItem('templateCustomizer-' + templateName + '--ShowDropdownOnHover') // If value(showDropdownOnHover) is set in local storage ? localStorage.getItem('templateCustomizer-' + templateName + '--ShowDropdownOnHover') === 'true' // Use the local storage value : window.templateCustomizer !== undefined // If value is set in config.js ? window.templateCustomizer.settings.defaultShowDropdownOnHover // Use the config.js value : true // Use this if you are not using the config.js and want to set value directly from here }); // Change parameter to true if you want scroll animation window.Helpers.scrollToActive((animate = false)); window.Helpers.mainMenu = menu; }); // Initialize menu togglers and bind click on each let menuToggler = document.querySelectorAll('.layout-menu-toggle'); menuToggler.forEach(item => { item.addEventListener('click', event => { event.preventDefault(); window.Helpers.toggleCollapsed(); // Enable menu state with local storage support if enableMenuLocalStorage = true from config.js if (config.enableMenuLocalStorage && !window.Helpers.isSmallScreen()) { try { localStorage.setItem( 'templateCustomizer-' + templateName + '--LayoutCollapsed', String(window.Helpers.isCollapsed()) ); // Update customizer checkbox state on click of menu toggler let layoutCollapsedCustomizerOptions = document.querySelector('.template-customizer-layouts-options'); if (layoutCollapsedCustomizerOptions) { let layoutCollapsedVal = window.Helpers.isCollapsed() ? 'collapsed' : 'expanded'; layoutCollapsedCustomizerOptions.querySelector(`input[value="${layoutCollapsedVal}"]`).click(); } } catch (e) {} } }); }); // Menu swipe gesture // Detect swipe gesture on the target element and call swipe In window.Helpers.swipeIn('.drag-target', function (e) { window.Helpers.setCollapsed(false); }); // Detect swipe gesture on the target element and call swipe Out window.Helpers.swipeOut('#layout-menu', function (e) { if (window.Helpers.isSmallScreen()) window.Helpers.setCollapsed(true); }); // Display in main menu when menu scrolls let menuInnerContainer = document.getElementsByClassName('menu-inner'), menuInnerShadow = document.getElementsByClassName('menu-inner-shadow')[0]; if (menuInnerContainer.length > 0 && menuInnerShadow) { menuInnerContainer[0].addEventListener('ps-scroll-y', function () { if (this.querySelector('.ps__thumb-y').offsetTop) { menuInnerShadow.style.display = 'block'; } else { menuInnerShadow.style.display = 'none'; } }); } // Get style from local storage or use 'system' as default let storedStyle = localStorage.getItem('templateCustomizer-' + templateName + '--Theme') || // if no template style then use Customizer style (window.templateCustomizer?.settings?.defaultStyle ?? document.documentElement.getAttribute('data-bs-theme')); //!if there is no Customizer then use default style as light // Run switchImage function based on the stored style window.Helpers.switchImage(storedStyle); // Update light/dark image based on current style window.Helpers.setTheme(window.Helpers.getPreferredTheme()); window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { const storedTheme = window.Helpers.getStoredTheme(); if (storedTheme !== 'light' && storedTheme !== 'dark') { window.Helpers.setTheme(window.Helpers.getPreferredTheme()); } }); function getScrollbarWidth() { const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; document.body.style.setProperty('--bs-scrollbar-width', `${scrollbarWidth}px`); } getScrollbarWidth(); window.addEventListener('DOMContentLoaded', () => { window.Helpers.showActiveTheme(window.Helpers.getPreferredTheme()); getScrollbarWidth(); // Toggle Universal Sidebar window.Helpers.initSidebarToggle(); document.querySelectorAll('[data-bs-theme-value]').forEach(toggle => { toggle.addEventListener('click', () => { const theme = toggle.getAttribute('data-bs-theme-value'); window.Helpers.setStoredTheme(templateName, theme); window.Helpers.setTheme(theme); window.Helpers.showActiveTheme(theme, true); window.Helpers.syncCustomOptions(theme); let currTheme = theme; if (theme === 'system') { currTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } const semiDarkL = document.querySelector('.template-customizer-semiDark'); if (semiDarkL) { if (theme === 'dark') { semiDarkL.classList.add('d-none'); } else { semiDarkL.classList.remove('d-none'); } } window.Helpers.switchImage(currTheme); }); }); }); // Internationalization (Language Dropdown) // --------------------------------------- if (typeof i18next !== 'undefined' && typeof i18NextHttpBackend !== 'undefined') { i18next .use(i18NextHttpBackend) .init({ lng: window.templateCustomizer ? window.templateCustomizer.settings.lang : 'en', debug: false, fallbackLng: 'en', backend: { loadPath: assetsPath + 'json/locales/{{lng}}.json' }, returnObjects: true }) .then(function (t) { localize(); }); } let languageDropdown = document.getElementsByClassName('dropdown-language'); if (languageDropdown.length) { let dropdownItems = languageDropdown[0].querySelectorAll('.dropdown-item'); for (let i = 0; i < dropdownItems.length; i++) { dropdownItems[i].addEventListener('click', function () { let currentLanguage = this.getAttribute('data-language'); let textDirection = this.getAttribute('data-text-direction'); for (let sibling of this.parentNode.children) { var siblingEle = sibling.parentElement.parentNode.firstChild; // Loop through each sibling and push to the array while (siblingEle) { if (siblingEle.nodeType === 1 && siblingEle !== siblingEle.parentElement) { siblingEle.querySelector('.dropdown-item').classList.remove('active'); } siblingEle = siblingEle.nextSibling; } } this.classList.add('active'); i18next.changeLanguage(currentLanguage, (err, t) => { window.templateCustomizer ? window.templateCustomizer.setLang(currentLanguage) : ''; directionChange(textDirection); if (err) return console.log('something went wrong loading', err); localize(); window.Helpers.syncCustomOptionsRtl(textDirection); }); }); } function directionChange(textDirection) { document.documentElement.setAttribute('dir', textDirection); if (textDirection === 'rtl') { if (localStorage.getItem('templateCustomizer-' + templateName + '--Rtl') !== 'true') window.templateCustomizer ? window.templateCustomizer.setRtl(true) : ''; } else { if (localStorage.getItem('templateCustomizer-' + templateName + '--Rtl') === 'true') window.templateCustomizer ? window.templateCustomizer.setRtl(false) : ''; } } } function localize() { let i18nList = document.querySelectorAll('[data-i18n]'); // Set the current language in dd let currentLanguageEle = document.querySelector('.dropdown-item[data-language="' + i18next.language + '"]'); if (currentLanguageEle) { currentLanguageEle.click(); } i18nList.forEach(function (item) { item.innerHTML = i18next.t(item.dataset.i18n); /* FIX: Uncomment the following line to hide elements with the i18n attribute before translation to prevent text change flicker */ // item.style.visibility = 'visible'; }); } // Notification // ------------ const notificationMarkAsReadAll = document.querySelector('.dropdown-notifications-all'); const notificationMarkAsReadList = document.querySelectorAll('.dropdown-notifications-read'); // Notification: Mark as all as read if (notificationMarkAsReadAll) { notificationMarkAsReadAll.addEventListener('click', event => { notificationMarkAsReadList.forEach(item => { item.closest('.dropdown-notifications-item').classList.add('marked-as-read'); }); }); } // Notification: Mark as read/unread onclick of dot if (notificationMarkAsReadList) { notificationMarkAsReadList.forEach(item => { item.addEventListener('click', event => { item.closest('.dropdown-notifications-item').classList.toggle('marked-as-read'); }); }); } // Notification: Mark as read/unread onclick of dot const notificationArchiveMessageList = document.querySelectorAll('.dropdown-notifications-archive'); notificationArchiveMessageList.forEach(item => { item.addEventListener('click', event => { item.closest('.dropdown-notifications-item').remove(); }); }); // Init helpers & misc // -------------------- // Init BS Tooltip const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl); }); // Accordion active class const accordionActiveFunction = function (e) { if (e.type == 'show.bs.collapse' || e.type == 'show.bs.collapse') { e.target.closest('.accordion-item').classList.add('active'); } else { e.target.closest('.accordion-item').classList.remove('active'); } }; const accordionTriggerList = [].slice.call(document.querySelectorAll('.accordion')); const accordionList = accordionTriggerList.map(function (accordionTriggerEl) { accordionTriggerEl.addEventListener('show.bs.collapse', accordionActiveFunction); accordionTriggerEl.addEventListener('hide.bs.collapse', accordionActiveFunction); }); // Auto update layout based on screen size window.Helpers.setAutoUpdate(true); // Toggle Password Visibility window.Helpers.initPasswordToggle(); // Speech To Text window.Helpers.initSpeechToText(); // Init PerfectScrollbar in Navbar Dropdown (i.e notification) window.Helpers.initNavbarDropdownScrollbar(); let horizontalMenuTemplate = document.querySelector("[data-template^='horizontal-menu']"); if (horizontalMenuTemplate) { // if screen size is small then set navbar fixed if (window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) { window.Helpers.setNavbarFixed('fixed'); } else { window.Helpers.setNavbarFixed(''); } } // On window resize listener // ------------------------- window.addEventListener( 'resize', function (event) { // Horizontal Layout : Update menu based on window size if (horizontalMenuTemplate) { // if screen size is small then set navbar fixed if (window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) { window.Helpers.setNavbarFixed('fixed'); } else { window.Helpers.setNavbarFixed(''); } setTimeout(function () { if (window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) { if (document.getElementById('layout-menu')) { if (document.getElementById('layout-menu').classList.contains('menu-horizontal')) { menu.switchMenu('vertical'); } } } else { if (document.getElementById('layout-menu')) { if (document.getElementById('layout-menu').classList.contains('menu-vertical')) { menu.switchMenu('horizontal'); } } } }, 100); } }, true ); // Manage menu expanded/collapsed with templateCustomizer & local storage //------------------------------------------------------------------ // If current layout is horizontal OR current window screen is small (overlay menu) than return from here if (isHorizontalLayout || window.Helpers.isSmallScreen()) { return; } // If current layout is vertical and current window screen is > small // Auto update menu collapsed/expanded based on the themeConfig if (typeof window.templateCustomizer !== 'undefined') { if (window.templateCustomizer.settings.defaultMenuCollapsed) { window.Helpers.setCollapsed(true, false); } else { window.Helpers.setCollapsed(false, false); } if (window.templateCustomizer.settings.semiDark) { document.querySelector('#layout-menu').setAttribute('data-bs-theme', 'dark'); } } // Manage menu expanded/collapsed state with local storage support If enableMenuLocalStorage = true in config.js if (typeof config !== 'undefined') { if (config.enableMenuLocalStorage) { try { if (localStorage.getItem('templateCustomizer-' + templateName + '--LayoutCollapsed') !== null) window.Helpers.setCollapsed( localStorage.getItem('templateCustomizer-' + templateName + '--LayoutCollapsed') === 'true', false ); } catch (e) {} } } })(); // Search Configuration const SearchConfig = { container: '#autocomplete', placeholder: 'Search [CTRL + K]', classNames: { detachedContainer: 'd-flex flex-column', detachedFormContainer: 'd-flex align-items-center justify-content-between border-bottom', form: 'd-flex align-items-center', input: 'search-control border-none', detachedCancelButton: 'btn-search-close', panel: 'flex-grow content-wrapper overflow-hidden position-relative', panelLayout: 'h-100', clearButton: 'd-none', item: 'd-block' } }; // Search state and data let data = {}; let currentFocusIndex = -1; // Utils function isMacOS() { return /Mac|iPod|iPhone|iPad/.test(navigator.userAgent); } // Load search data function loadSearchData() { const searchJson = $('#layout-menu').hasClass('menu-horizontal') ? 'search-horizontal.json' : 'search-vertical.json'; fetch(assetsPath + 'json/' + searchJson) .then(response => { if (!response.ok) throw new Error('Failed to fetch data'); return response.json(); }) .then(json => { data = json; initializeAutocomplete(); }) .catch(error => console.error('Error loading JSON:', error)); } // Initialize autocomplete function initializeAutocomplete() { const searchElement = document.getElementById('autocomplete'); if (!searchElement) return; return autocomplete({ ...SearchConfig, openOnFocus: true, onStateChange({ state, setQuery }) { // When autocomplete is opened if (state.isOpen) { // Hide body scroll and add padding to prevent layout shift document.body.style.overflow = 'hidden'; document.body.style.paddingRight = 'var(--bs-scrollbar-width)'; // Replace "Cancel" text with icon const cancelIcon = document.querySelector('.aa-DetachedCancelButton'); if (cancelIcon) { cancelIcon.innerHTML = '[esc] '; } // Perfect Scrollbar if (!window.autoCompletePS) { const panel = document.querySelector('.aa-Panel'); if (panel) { window.autoCompletePS = new PerfectScrollbar(panel); } } } else { // When autocomplete is closed if (state.status === 'idle' && state.query) { setQuery(''); } // Restore body scroll and padding when autocomplete is closed document.body.style.overflow = 'auto'; document.body.style.paddingRight = ''; } }, render(args, root) { const { render, html, children, state } = args; // Initial Suggestions if (!state.query) { const initialSuggestions = html`
${section}