/** * Document : layout.js * Author : redstar * Description: Core script to handle the entire theme and core functions * **/ var Layout = function () { var layoutImgPath = 'img/'; var layoutCssPath = 'css/'; var resBreakpointMd = App.getResponsiveBreakpoint('md'); var ajaxContentSuccessCallbacks = []; var ajaxContentErrorCallbacks = []; // this function handles responsive layout on screen size resize or mobile device rotate. // Set proper height for sidebar and content. The content and sidebar height must be synced always. var handleSidebarAndContentHeight = function () { var content = $('.page-content'); var sidebar = $('.sidemenu-container'); var body = $('body'); var height; if (body.hasClass("page-footer-fixed") === true && body.hasClass("sidemenu-container-fixed") === false) { var available_height = App.getViewPort().height - $('.page-footer').outerHeight() - $('.page-header').outerHeight(); var sidebar_height = sidebar.outerHeight(); if (sidebar_height > available_height) { available_height = sidebar_height + $('.page-footer').outerHeight(); } if (content.height() < available_height) { content.attr('style', 'min-height:' + available_height + 'px'); } } else { if (body.hasClass('sidemenu-container-fixed')) { height = _calculateFixedSidebarViewportHeight(); if (body.hasClass('page-footer-fixed') === false) { height = height - $('.page-footer').outerHeight(); } } else { var headerHeight = $('.page-header').outerHeight(); var footerHeight = $('.page-footer').outerHeight(); if (App.getViewPort().width < resBreakpointMd) { height = App.getViewPort().height - headerHeight - footerHeight; } else { height = sidebar.height() + 20; } if ((height + headerHeight + footerHeight) <= App.getViewPort().height) { height = App.getViewPort().height - headerHeight - footerHeight; } } content.attr('style', 'min-height:' + height + 'px'); } }; // Handle sidebar menu links var handleSidebarMenuActiveLink = function(mode, el) { var url = location.hash.toLowerCase(); var menu = $('.sidemenu'); if (mode === 'click' || mode === 'set') { el = $(el); } else if (mode === 'match') { menu.find("li > a").each(function() { var path = $(this).attr("href").toLowerCase(); // url match condition if (path.length > 1 && url.substr(1, path.length - 1) == path.substr(1)) { el = $(this); return; } }); } if (!el || el.length == 0) { return; } if (el.attr('href').toLowerCase() === 'javascript:;' || el.attr('href').toLowerCase() === '#') { return; } var slideSpeed = parseInt(menu.data("slide-speed"),10); var keepExpand = menu.data("keep-expanded"); // begin: handle active state if (menu.hasClass('sidemenu-hover-submenu') === false) { menu.find('li.nav-item.open').each(function() { var match = false; $(this).find('li').each(function(){ if ($(this).find(' > a').attr('href') === el.attr('href')) { match = true; return; } }); if (match === true) { return; } $(this).removeClass('open'); $(this).find('> a > .arrow.open').removeClass('open'); $(this).find('> .sub-menu').slideUp(); }); } else { menu.find('li.open').removeClass('open'); } menu.find('li.active').removeClass('active'); menu.find('li > a > .selected').remove(); // end: handle active state el.parents('li').each(function () { $(this).addClass('active'); $(this).find('> a > span.arrow').addClass('open'); if ($(this).parent('ul.sidemenu').length === 1) { $(this).find('> a').append(''); } if ($(this).children('ul.sub-menu').length === 1) { $(this).addClass('open'); } }); if (mode === 'click') { if (App.getViewPort().width < resBreakpointMd && $('.sidemenu-container').hasClass("in")) { // close the menu on mobile view while laoding a page $('.page-header .responsive-toggler').click(); } } }; // Handle sidebar menu var handleSidebarMenu = function () { // offcanvas mobile menu // handle sidebar link click $('.sidemenu').on('click', 'li > a.nav-toggle, li > a > span.nav-toggle', function (e) { var that = $(this).closest('.nav-item').children('.nav-link'); if (App.getViewPort().width >= resBreakpointMd && !$('.sidemenu').attr("data-initialized") && $('body').hasClass('sidemenu-closed') && that.parent('li').parent('.sidemenu').length === 1) { return; } var hasSubMenu = that.next().hasClass('sub-menu'); if (App.getViewPort().width >= resBreakpointMd && that.parents('.sidemenu-hover-submenu').length === 1) { // exit of hover sidebar menu return; } if (hasSubMenu === false) { if (App.getViewPort().width < resBreakpointMd && $('.sidemenu-container').hasClass("in")) { // close the menu on mobile view while laoding a page $('.page-header .responsive-toggler').click(); } return; } var parent =that.parent().parent(); var the = that; var menu = $('.sidemenu'); var sub = that.next(); var autoScroll = menu.data("auto-scroll"); var slideSpeed = parseInt(menu.data("slide-speed"),10); var keepExpand = menu.data("keep-expanded"); if (!keepExpand) { parent.children('li.open').children('a').children('.arrow').removeClass('open'); parent.children('li.open').children('.sub-menu:not(.always-open)').slideUp(slideSpeed); parent.children('li.open').removeClass('open'); } var slideOffeset = -200; if (sub.is(":visible")) { $('.arrow', the).removeClass("open"); the.parent().removeClass("open"); sub.slideUp(slideSpeed, function () { handleSidebarAndContentHeight(); }); } else if (hasSubMenu) { $('.arrow', the).addClass("open"); the.parent().addClass("open"); sub.slideDown(slideSpeed, function () { handleSidebarAndContentHeight(); }); } e.preventDefault(); }); // handle scrolling to top on responsive menu toggler click when header is fixed for mobile view $(document).on('click', '.page-header-fixed-mobile .page-header .responsive-toggler', function(){ App.scrollTop(); }); // handle sidebar hover effect handleFixedSidebarHoverEffect(); // handle the search bar close $('.sidemenu-container').on('click', '.sidebar-search .remove', function (e) { e.preventDefault(); $('.sidebar-search').removeClass("open"); }); // handle the search query submit on enter press $('.sidemenu-container .sidebar-search').on('keypress', 'input.form-control', function (e) { if (e.which == 13) { $('.sidebar-search').submit(); return false; //<---- Add this line } }); // handle the search submit(for sidebar search and responsive mode of the header search) $('.sidebar-search .submit').on('click', function (e) { e.preventDefault(); if ($('body').hasClass("sidemenu-closed")) { if ($('.sidebar-search').hasClass('open') === false) { if ($('.sidemenu-container-fixed').length === 1) { $('.sidemenu-container .sidebar-toggler').click(); //trigger sidebar toggle button } $('.sidebar-search').addClass("open"); } else { $('.sidebar-search').submit(); } } else { $('.sidebar-search').submit(); } }); // handle close on body click if ($('.sidebar-search').length !== 0) { $('.sidebar-search .input-group').on('click', function(e){ e.stopPropagation(); }); $('body').on('click', function() { if ($('.sidebar-search').hasClass('open')) { $('.sidebar-search').removeClass("open"); } }); } }; // Helper function to calculate sidebar height for fixed sidebar layout. var _calculateFixedSidebarViewportHeight = function () { var sidebarHeight = App.getViewPort().height - $('.page-header').outerHeight(true); if ($('body').hasClass("page-footer-fixed")) { sidebarHeight = sidebarHeight - $('.page-footer').outerHeight(); } return sidebarHeight; }; // Handles fixed sidebar var handleFixedSidebar = function () { var menu = $('.sidemenu'); handleSidebarAndContentHeight(); if ($('.sidemenu-container-fixed').length === 0) { return; } if (App.getViewPort().width >= resBreakpointMd && !$('body').hasClass('sidemenu-not-fixed')) { menu.attr("data-height", _calculateFixedSidebarViewportHeight()); App.destroySlimScroll(menu); App.initSlimScroll(menu); handleSidebarAndContentHeight(); } }; // Handles sidebar toggler to close/hide the sidebar. var handleFixedSidebarHoverEffect = function () { var body = $('body'); if (body.hasClass('sidemenu-container-fixed')) { $('.sidemenu-container').on('mouseenter', function () { if (body.hasClass('sidemenu-closed')) { $(this).find('.sidemenu').removeClass('sidemenu-closed'); } }).on('mouseleave', function () { if (body.hasClass('sidemenu-closed')) { $(this).find('.sidemenu').addClass('sidemenu-closed'); } }); } }; // Hanles sidebar toggler var handleSidebarToggler = function () { var body = $('body'); if ($.cookie && $.cookie('sidebar_closed') === '1' && App.getViewPort().width >= resBreakpointMd) { $('body').addClass('sidemenu-closed'); $('.sidemenu').addClass('sidemenu-closed'); } // handle sidebar show/hide $('body').on('click', '.sidebar-toggler', function (e) { var sidebar = $('.sidemenu-container'); var sidebarMenu = $('.sidemenu'); $(".sidebar-search", sidebar).removeClass("open"); if (body.hasClass("sidemenu-closed")) { body.removeClass("sidemenu-closed"); sidebarMenu.removeClass("sidemenu-closed"); if ($.cookie) { $.cookie('sidebar_closed', '0'); } } else { body.addClass("sidemenu-closed"); sidebarMenu.addClass("sidemenu-closed"); if (body.hasClass("sidemenu-container-fixed")) { sidebarMenu.trigger("mouseleave"); } if ($.cookie) { $.cookie('sidebar_closed', '1'); } } $(window).trigger('resize'); }); }; // Handles the horizontal menu var handleHorizontalMenu = function () { //handle tab click $('.page-header').on('click', '.hor-menu a[data-toggle="tab"]', function (e) { e.preventDefault(); var nav = $(".hor-menu .nav"); var active_link = nav.find('li.current'); $('li.active', active_link).removeClass("active"); $('.selected', active_link).remove(); var new_link = $(this).parents('li').last(); new_link.addClass("current"); new_link.find("a:first").append(''); }); // handle search box expand/collapse $('.page-header').on('click', '.search-form', function (e) { $(this).addClass("open"); $(this).find('.form-control').focus(); $('.page-header .search-form .form-control').on('blur', function (e) { $(this).closest('.search-form').removeClass("open"); $(this).unbind("blur"); }); }); // handle hor menu search form on enter press $('.page-header').on('keypress', '.hor-menu .search-form .form-control', function (e) { if (e.which == 13) { $(this).closest('.search-form').submit(); return false; } }); // handle header search button click $('.page-header').on('mousedown', '.search-form.open .submit', function (e) { e.preventDefault(); e.stopPropagation(); $(this).closest('.search-form').submit(); }); $(document).on('click', '.mega-menu-dropdown .dropdown-menu', function (e) { e.stopPropagation(); }); }; // Handles Bootstrap Tabs. var handleTabs = function () { // fix content height on tab click $('body').on('shown.bs.tab', 'a[data-toggle="tab"]', function () { handleSidebarAndContentHeight(); }); }; // Handles the go to top button at the footer var handleGoTop = function () { var offset = 300; var duration = 500; if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) { // ios supported $(window).bind("touchend touchcancel touchleave", function(e){ if ($(this).scrollTop() > offset) { $('.scroll-to-top').fadeIn(duration); } else { $('.scroll-to-top').fadeOut(duration); } }); } else { // general $(window).scroll(function() { if ($(this).scrollTop() > offset) { $('.scroll-to-top').fadeIn(duration); } else { $('.scroll-to-top').fadeOut(duration); } }); } $(document).on('click','.scroll-to-top',function(e) { e.preventDefault(); $('html, body').animate({scrollTop: 0}, duration); return false; }); }; // Hanlde 100% height elements(block, portlet, etc) var handle100HeightContent = function () { $('.full-height-content').each(function(){ var target = $(this); var height; height = App.getViewPort().height - $('.page-header').outerHeight(true) - $('.page-footer').outerHeight(true) - $('.page-title').outerHeight(true) - $('.page-bar').outerHeight(true); if (target.hasClass('portlet')) { var portletBody = target.find('.portlet-body'); App.destroySlimScroll(portletBody.find('.full-height-content-body')); // destroy slimscroll height = height - target.find('.portlet-title').outerHeight(true) - parseInt(target.find('.portlet-body').css('padding-top'),10) - parseInt(target.find('.portlet-body').css('padding-bottom'),10) - 5; if (App.getViewPort().width >= resBreakpointMd && target.hasClass("full-height-content-scrollable")) { height = height - 35; portletBody.find('.full-height-content-body').css('height', height); App.initSlimScroll(portletBody.find('.full-height-content-body')); } else { portletBody.css('min-height', height); } } else { App.destroySlimScroll(target.find('.full-height-content-body')); // destroy slimscroll if (App.getViewPort().width >= resBreakpointMd && target.hasClass("full-height-content-scrollable")) { height = height - 35; target.find('.full-height-content-body').css('height', height); App.initSlimScroll(target.find('.full-height-content-body')); } else { target.css('min-height', height); } } }); }; return { // Main init methods to initialize the layout initHeader: function() { handleHorizontalMenu(); // handles horizontal menu }, setSidebarMenuActiveLink: function(mode, el) { handleSidebarMenuActiveLink(mode, el); }, initSidebar: function() { //layout handlers handleFixedSidebar(); // handles fixed sidebar menu handleSidebarMenu(); // handles main menu handleSidebarToggler(); // handles sidebar hide/show App.addResizeHandler(handleFixedSidebar); // reinitialize fixed sidebar on window resize }, initContent: function() { handle100HeightContent(); // handles 100% height elements(block, portlet, etc) handleTabs(); // handle bootstrah tabs App.addResizeHandler(handleSidebarAndContentHeight); // recalculate sidebar & content height on window resize App.addResizeHandler(handle100HeightContent); // reinitialize content height on window resize }, initFooter: function() { handleGoTop(); //handles scroll to top functionality in the footer }, init: function () { this.initHeader(); this.initSidebar(); this.initContent(); this.initFooter(); }, loadAjaxContent: function(url, sidebarMenuLink) { var pageContent = $('.page-content .page-content-body'); App.startPageLoading({animate: true}); $.ajax({ type: "GET", cache: false, url: url, dataType: "html", success: function (res) { App.stopPageLoading(); for (var i = 0; i < ajaxContentSuccessCallbacks.length; i++) { ajaxContentSuccessCallbacks[i].call(res); } if (sidebarMenuLink.length > 0 && sidebarMenuLink.parents('li.open').length === 0) { $('.sidemenu > li.open > a').click(); } pageContent.html(res); Layout.fixContentHeight(); // fix content height App.initAjax(); // initialize core stuff }, error: function (res, ajaxOptions, thrownError) { App.stopPageLoading(); pageContent.html('