/* ------------------------------------------------------------------------------ * * # Template JS core * * Includes minimum required JS code for proper template functioning * * ---------------------------------------------------------------------------- */ // Setup module // ------------------------------ const App = function () { // Utils // ------------------------- // // Transitions // // Disable all transitions const transitionsDisabled = function() { $('body').addClass('no-transitions'); }; // Enable all transitions const transitionsEnabled = function() { $('body').removeClass('no-transitions'); }; // // Detect OS to apply custom scrollbars // // Custom scrollbar style is controlled by CSS. This function is needed to keep default // scrollbars on MacOS and avoid usage of extra JS libraries const detectOS = function() { const platform = window.navigator.platform, windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'], customScrollbarsClass = 'custom-scrollbars'; // Add class if OS is windows windowsPlatforms.indexOf(platform) != -1 && $('body').addClass(customScrollbarsClass); }; // Sidebars // ------------------------- // // On desktop // // Resize main sidebar const sidebarMainResize = function() { // Elements const sidebarMainElement = $('.sidebar-main'), sidebarMainToggler = $('.sidebar-main-resize'), resizeClass = 'sidebar-main-resized', unfoldClass = 'sidebar-main-unfold'; // Define variables const unfoldDelay = 150; let timerStart, timerFinish; // Toggle classes on click sidebarMainToggler.on('click', function(e) { sidebarMainElement.toggleClass(resizeClass); !sidebarMainElement.hasClass(resizeClass) && sidebarMainElement.removeClass(unfoldClass); }); // Add class on mouse enter sidebarMainElement.on('mouseenter', function() { clearTimeout(timerFinish); timerStart = setTimeout(function() { sidebarMainElement.hasClass(resizeClass) && sidebarMainElement.addClass(unfoldClass); }, unfoldDelay); }); // Remove class on mouse leave sidebarMainElement.on('mouseleave', function() { clearTimeout(timerStart); timerFinish = setTimeout(function() { sidebarMainElement.removeClass(unfoldClass); }, unfoldDelay); }); }; // Toggle main sidebar const sidebarMainToggle = function() { // Elements const sidebarMainElement = $('.sidebar-main'), sidebarMainRestElements = $('.sidebar:not(.sidebar-main):not(.sidebar-component)'), sidebarMainDesktopToggler = $('.sidebar-main-toggle'), sidebarMainMobileToggler = $('.sidebar-mobile-main-toggle'), sidebarCollapsedClass = 'sidebar-collapsed', sidebarMobileExpandedClass = 'sidebar-mobile-expanded'; $('#sidebar-main').on('click', function(e) { e.preventDefault(); if (matchMedia('screen and (max-width: 1200px)').matches) { sidebarMainElement.toggleClass(sidebarMobileExpandedClass); sidebarMainRestElements.removeClass(sidebarMobileExpandedClass); } else { sidebarMainElement.toggleClass(sidebarCollapsedClass); } }) // // On desktop // sidebarMainDesktopToggler.on('click', function(e) { // e.preventDefault(); // sidebarMainElement.toggleClass(sidebarCollapsedClass); // }); // On mobile sidebarMainMobileToggler.on('click', function(e) { e.preventDefault(); sidebarMainElement.toggleClass(sidebarMobileExpandedClass); sidebarMainRestElements.removeClass(sidebarMobileExpandedClass); }); }; // Toggle secondary sidebar const sidebarSecondaryToggle = function() { // Elements const sidebarSecondaryElement = $('.sidebar-secondary'), sidebarSecondaryRestElements = $('.sidebar:not(.sidebar-secondary):not(.sidebar-component)'), sidebarSecondaryDesktopToggler = $('.sidebar-secondary-toggle'), sidebarSecondaryMobileToggler = $('.sidebar-mobile-secondary-toggle'), sidebarCollapsedClass = 'sidebar-collapsed', sidebarMobileExpandedClass = 'sidebar-mobile-expanded'; // On desktop sidebarSecondaryDesktopToggler.on('click', function(e) { e.preventDefault(); sidebarSecondaryElement.toggleClass(sidebarCollapsedClass); }); // On mobile sidebarSecondaryMobileToggler.on('click', function(e) { e.preventDefault(); sidebarSecondaryElement.toggleClass(sidebarMobileExpandedClass); sidebarSecondaryRestElements.removeClass(sidebarMobileExpandedClass); }); }; // Toggle right sidebar const sidebarRightToggle = function() { // Elements const sidebarRightElement = $('.sidebar-right'), sidebarRightRestElements = $('.sidebar:not(.sidebar-right):not(.sidebar-component)'), sidebarRightDesktopToggler = $('.sidebar-right-toggle'), sidebarRightMobileToggler = $('.sidebar-mobile-right-toggle'), sidebarCollapsedClass = 'sidebar-collapsed', sidebarMobileExpandedClass = 'sidebar-mobile-expanded'; $(sidebarRightDesktopToggler).on('click', function(e) { e.preventDefault(); if (matchMedia('screen and (max-width: 1200px)').matches) { sidebarRightElement.toggleClass(sidebarMobileExpandedClass); sidebarRightRestElements.removeClass(sidebarMobileExpandedClass); } else { sidebarRightElement.toggleClass(sidebarCollapsedClass); } }); // // On desktop // sidebarRightDesktopToggler.on('click', function(e) { // e.preventDefault(); // sidebarRightElement.toggleClass(sidebarCollapsedClass); // }); // // On mobile // sidebarRightMobileToggler.on('click', function(e) { // e.preventDefault(); // sidebarRightElement.toggleClass(sidebarMobileExpandedClass); // sidebarRightRestElements.removeClass(sidebarMobileExpandedClass); // }); }; // Toggle component sidebar const sidebarComponentToggle = function() { // Elements const sidebarComponentElement = $('.sidebar-component'), sidebarComponentMobileToggler = $('.sidebar-mobile-component-toggle'), sidebarMobileExpandedClass = 'sidebar-mobile-expanded'; // Toggle classes sidebarComponentMobileToggler.on('click', function(e) { e.preventDefault(); sidebarComponentElement.toggleClass(sidebarMobileExpandedClass); }); }; // Navigations // ------------------------- // Sidebar navigation const navigationSidebar = function() { // Define default class names and options var navClass = 'nav-sidebar', navItemClass = 'nav-item', navItemOpenClass = 'nav-item-open', navLinkClass = 'nav-link', navSubmenuClass = 'nav-group-sub', navScrollSpyClass = 'nav-scrollspy', navSlidingSpeed = 250; // Configure collapsible functionality $('.' + navClass + ':not(.' + navScrollSpyClass + ')').each(function() { $(this).find('.' + navItemClass).has('.' + navSubmenuClass).children('.' + navItemClass + ' > ' + '.' + navLinkClass).not('.disabled').on('click', function (e) { e.preventDefault(); // Simplify stuff var $target = $(this); // Collapsible if($target.parent('.' + navItemClass).hasClass(navItemOpenClass)) { $target.parent('.' + navItemClass).removeClass(navItemOpenClass).children('.' + navSubmenuClass).slideUp(navSlidingSpeed); } else { $target.parent('.' + navItemClass).addClass(navItemOpenClass).children('.' + navSubmenuClass).slideDown(navSlidingSpeed); } // Accordion if ($target.parents('.' + navClass).data('nav-type') == 'accordion') { $target.parent('.' + navItemClass).siblings(':has(.' + navSubmenuClass + ')').removeClass(navItemOpenClass).children('.' + navSubmenuClass).slideUp(navSlidingSpeed); } }); }); // Disable click in disabled navigation items $(document).on('click', '.' + navClass + ' .disabled', function(e) { e.preventDefault(); }); }; // Navbar navigation const navigationNavbar = function() { // Prevent dropdown from closing on click $(document).on('click', '.dropdown-content', function(e) { e.stopPropagation(); }); // Disabled links $('.navbar-nav .disabled a, .nav-item-levels .disabled').on('click', function(e) { e.preventDefault(); e.stopPropagation(); }); // Show tabs inside dropdowns $('.dropdown-content a[data-toggle="tab"]').on('click', function() { $(this).tab('show'); }); }; // Components // ------------------------- // Tooltip const componentTooltip = function() { $('[data-popup="tooltip"]').tooltip({ boundary: '.page-content' }); }; // Popover const componentPopover = function() { $('[data-popup="popover"]').popover({ boundary: '.page-content' }); }; // "Go to top" button const componentToTopButton = function() { // Elements const toTopContainer = $('.content-wrapper'), scrollableContainer = $('.content-inner'), scrollableDistance = 250; // Append only if container exists if (scrollableContainer) { // Create button toTopContainer.append($('
')); // Show and hide on scroll const to_top_button = $('.btn-to-top'), add_class_on_scroll = function() { to_top_button.addClass('btn-to-top-visible'); }, remove_class_on_scroll = function() { to_top_button.removeClass('btn-to-top-visible'); }; scrollableContainer.on('scroll', function() { const scrollpos = scrollableContainer.scrollTop(); if (scrollpos >= scrollableDistance) { add_class_on_scroll(); } else { remove_class_on_scroll(); } }); // Scroll to top on click $('.btn-to-top .btn').on('click', function() { scrollableContainer.scrollTop(0); }); } }; // Card actions // ------------------------- // Reload card (uses BlockUI extension) const cardActionReload = function() { // Elements const buttonElement = $('[data-action=reload]'), overlayContainer = '.card', overlayClass = 'card-overlay', spinnerClass = 'icon-spinner9 spinner text-body', overlayAnimationClass = 'card-overlay-fadeout'; // Configure buttonElement.on('click', function(e) { e.preventDefault(); // Create overlay with spinner $(this).parents(overlayContainer).append($('
')); // Remove overlay after 2.5s, for demo only setTimeout(function() { $('.' + overlayClass).addClass(overlayAnimationClass).on('animationend animationcancel', function() { $(this).remove(); }); }, 2500); }); }; // Collapse card const cardActionCollapse = function() { // Elements const buttonElement = $('[data-action=collapse]'), cardContainer = '.card', cardCollapsedClass = 'card-collapsed'; // Configure buttonElement.on('click', function(e) { e.preventDefault(); const parentContainer = $(this).parents('.card'), collapsibleContainer = parentContainer.find('> .collapse'); if (parentContainer.hasClass(cardCollapsedClass)) { parentContainer.removeClass(cardCollapsedClass); collapsibleContainer.collapse('show'); } else { parentContainer.addClass(cardCollapsedClass); collapsibleContainer.collapse('hide'); } }); }; // Remove card const cardActionRemove = function() { // Elements const buttonElement = $('[data-action=remove]'), cardContainer = '.card'; // Configure buttonElement.on('click', function(e) { e.preventDefault(); $(this).parents(cardContainer).slideUp(150); }); }; // Card fullscreen mode const cardActionFullscreen = function() { // Elements const buttonElement = '[data-action=fullscreen]', buttonClass = 'list-icons-item', buttonContainerClass = 'list-icons', cardFullscreenClass = 'card-fullscreen', collapsedClass = 'collapsed-in-fullscreen', scrollableContainerClass = 'content-inner', fullscreenAttr = 'data-fullscreen'; // Configure $(buttonElement).on('click', function(e) { e.preventDefault(); const button = $(this); // Get closest card container const cardFullscreen = button.parents('.card'); // Toggle required classes cardFullscreen.toggleClass(cardFullscreenClass); // Toggle classes depending on state if (!cardFullscreen.hasClass(cardFullscreenClass)) { button.removeAttr(fullscreenAttr); cardFullscreen.find('.' + collapsedClass).removeClass('show'); $('.' + scrollableContainerClass).removeClass('overflow-hidden'); button.parents('.' + buttonContainerClass).find('.' + buttonClass + ':not(' + buttonElement + ')').removeClass('d-none'); } else { button.attr(fullscreenAttr, 'active'); cardFullscreen.removeAttr('style'); cardFullscreen.find('.collapse:not(.show)').addClass('show ' + collapsedClass); $('.' + scrollableContainerClass).addClass('overflow-hidden'); button.parents('.' + buttonContainerClass).find('.' + buttonClass + ':not(' + buttonElement + ')').addClass('d-none'); } }); }; // Misc // ------------------------- // Re-declare dropdown boundary for app container const dropdownMenus = function() { $.fn.dropdown.Constructor.Default.boundary = '.page-content'; }; // Dropdown submenus. Trigger on click const dropdownSubmenu = function() { // All parent levels require .dropdown-toggle class $('.dropdown-menu').find('.dropdown-submenu').not('.disabled').find('.dropdown-toggle').on('click', function(e) { e.stopPropagation(); e.preventDefault(); const button = $(this); // Remove "show" class in all siblings button.parent().siblings().removeClass('show').find('.show').removeClass('show'); // Toggle submenu button.parent().toggleClass('show').children('.dropdown-menu').toggleClass('show'); // Hide all levels when parent dropdown is closed button.parents('.show').on('hidden.bs.dropdown', function(e) { $('.dropdown-submenu .show, .dropdown-submenu.show').removeClass('show'); }); }); }; // Header elements toggler const componentHeaderElements = function() { // Toggle visible state of header elements $('.header-elements-toggle').on('click', function(e) { e.preventDefault(); $(this).parents('[class*=header-elements-]:not(.header-elements-toggle)').find('.header-elements').toggleClass('d-none'); }); // Toggle visible state of footer elements $('.footer-elements-toggle').on('click', function(e) { e.preventDefault(); $(this).parents('.card-footer').find('.footer-elements').toggleClass('d-none'); }); }; // // Return objects assigned to module // return { // Disable transitions before page is fully loaded initBeforeLoad: function() { detectOS(); transitionsDisabled(); }, // Enable transitions when page is fully loaded initAfterLoad: function() { transitionsEnabled(); }, // Initialize all components initComponents: function() { componentTooltip(); componentPopover(); componentToTopButton(); componentHeaderElements(); }, // Initialize all sidebars initSidebars: function() { sidebarMainResize(); sidebarMainToggle(); sidebarSecondaryToggle(); sidebarRightToggle(); sidebarComponentToggle(); }, // Initialize all navigations initNavigations: function() { navigationSidebar(); navigationNavbar(); }, // Initialize all card actions initCardActions: function() { cardActionReload(); cardActionCollapse(); cardActionRemove(); cardActionFullscreen(); }, // Dropdown submenu initDropdowns: function() { dropdownMenus(); dropdownSubmenu(); }, // Initialize core initCore: function() { App.initBeforeLoad(); App.initSidebars(); App.initNavigations(); App.initComponents(); App.initCardActions(); App.initDropdowns(); } } }(); // Initialize module // ------------------------------ // When content is loaded document.addEventListener('DOMContentLoaded', function() { App.initCore(); }); // When page is fully loaded window.addEventListener('load', function() { App.initAfterLoad(); });