github.com/apremalal/vamps-core@v1.0.1-0.20161221121535-d430b56ec174/server/webapps/app/base/js/layout.js (about) 1 /** 2 Core script to handle the entire theme and core functions 3 **/ 4 var Layout = function () { 5 6 var layoutImgPath = 'admin/layout/img/'; 7 8 var layoutCssPath = 'admin/layout/css/'; 9 10 var resBreakpointMd = Metronic.getResponsiveBreakpoint('md'); 11 12 //* BEGIN:CORE HANDLERS *// 13 // this function handles responsive layout on screen size resize or mobile device rotate. 14 15 // Set proper height for sidebar and content. The content and sidebar height must be synced always. 16 var handleSidebarAndContentHeight = function () { 17 var content = $('.page-content'); 18 var sidebar = $('.page-sidebar'); 19 var body = $('body'); 20 var height; 21 22 if (body.hasClass("page-footer-fixed") === true && body.hasClass("page-sidebar-fixed") === false) { 23 var available_height = Metronic.getViewPort().height - $('.page-footer').outerHeight() - $('.page-header').outerHeight(); 24 if (content.height() < available_height) { 25 content.attr('style', 'min-height:' + available_height + 'px'); 26 } 27 } else { 28 if (body.hasClass('page-sidebar-fixed')) { 29 height = _calculateFixedSidebarViewportHeight(); 30 if (body.hasClass('page-footer-fixed') === false) { 31 height = height - $('.page-footer').outerHeight(); 32 } 33 } else { 34 var headerHeight = $('.page-header').outerHeight(); 35 var footerHeight = $('.page-footer').outerHeight(); 36 37 if (Metronic.getViewPort().width < resBreakpointMd) { 38 height = Metronic.getViewPort().height - headerHeight - footerHeight; 39 } else { 40 height = sidebar.height() + 20; 41 } 42 43 if ((height + headerHeight + footerHeight) <= Metronic.getViewPort().height) { 44 height = Metronic.getViewPort().height - headerHeight - footerHeight; 45 } 46 } 47 content.attr('style', 'min-height:' + height + 'px'); 48 } 49 }; 50 51 // Handle sidebar menu links 52 var handleSidebarMenuActiveLink = function(mode, el) { 53 var url = location.hash.toLowerCase(); 54 55 var menu = $('.page-sidebar-menu'); 56 57 if (mode === 'click' || mode === 'set') { 58 el = $(el); 59 } else if (mode === 'match') { 60 menu.find("li > a").each(function() { 61 var path = $(this).attr("href").toLowerCase(); 62 // url match condition 63 if (path.length > 1 && url.substr(1, path.length - 1) == path.substr(1)) { 64 el = $(this); 65 return; 66 } 67 }); 68 } 69 70 if (!el || el.size() == 0) { 71 return; 72 } 73 74 if (el.attr('href').toLowerCase() === 'javascript:;' || el.attr('href').toLowerCase() === '#') { 75 return; 76 } 77 78 var slideSpeed = parseInt(menu.data("slide-speed")); 79 var keepExpand = menu.data("keep-expanded"); 80 81 // disable active states 82 menu.find('li.active').removeClass('active'); 83 menu.find('li > a > .selected').remove(); 84 85 if (menu.hasClass('page-sidebar-menu-hover-submenu') === false) { 86 menu.find('li.open').each(function(){ 87 if ($(this).children('.sub-menu').size() === 0) { 88 $(this).removeClass('open'); 89 $(this).find('> a > .arrow.open').removeClass('open'); 90 } 91 }); 92 } else { 93 menu.find('li.open').removeClass('open'); 94 } 95 96 el.parents('li').each(function () { 97 $(this).addClass('active'); 98 $(this).find('> a > span.arrow').addClass('open'); 99 100 if ($(this).parent('ul.page-sidebar-menu').size() === 1) { 101 $(this).find('> a').append('<span class="selected"></span>'); 102 } 103 104 if ($(this).children('ul.sub-menu').size() === 1) { 105 $(this).addClass('open'); 106 } 107 }); 108 109 if (mode === 'click') { 110 if (Metronic.getViewPort().width < resBreakpointMd && $('.page-sidebar').hasClass("in")) { // close the menu on mobile view while laoding a page 111 $('.page-header .responsive-toggler').click(); 112 } 113 } 114 }; 115 116 // Handle sidebar menu 117 var handleSidebarMenu = function () { 118 // handle sidebar link click 119 $('.page-sidebar').on('click', 'li > a', function (e) { 120 var hasSubMenu = $(this).next().hasClass('sub-menu'); 121 122 if (Metronic.getViewPort().width >= resBreakpointMd && $(this).parents('.page-sidebar-menu-hover-submenu').size() === 1) { // exit of hover sidebar menu 123 return; 124 } 125 126 if (hasSubMenu === false) { 127 if (Metronic.getViewPort().width < resBreakpointMd && $('.page-sidebar').hasClass("in")) { // close the menu on mobile view while laoding a page 128 $('.page-header .responsive-toggler').click(); 129 } 130 return; 131 } 132 133 if ($(this).next().hasClass('sub-menu always-open')) { 134 return; 135 } 136 137 var parent = $(this).parent().parent(); 138 var the = $(this); 139 var menu = $('.page-sidebar-menu'); 140 var sub = $(this).next(); 141 142 var autoScroll = menu.data("auto-scroll"); 143 var slideSpeed = parseInt(menu.data("slide-speed")); 144 var keepExpand = menu.data("keep-expanded"); 145 146 if (keepExpand !== true) { 147 parent.children('li.open').children('a').children('.arrow').removeClass('open'); 148 parent.children('li.open').children('.sub-menu:not(.always-open)').slideUp(slideSpeed); 149 parent.children('li.open').removeClass('open'); 150 } 151 152 var slideOffeset = -200; 153 154 if (sub.is(":visible")) { 155 $('.arrow', $(this)).removeClass("open"); 156 $(this).parent().removeClass("open"); 157 sub.slideUp(slideSpeed, function () { 158 if (autoScroll === true && $('body').hasClass('page-sidebar-closed') === false) { 159 if ($('body').hasClass('page-sidebar-fixed')) { 160 menu.slimScroll({ 161 'scrollTo': (the.position()).top 162 }); 163 } else { 164 Metronic.scrollTo(the, slideOffeset); 165 } 166 } 167 handleSidebarAndContentHeight(); 168 }); 169 } else if (hasSubMenu) { 170 $('.arrow', $(this)).addClass("open"); 171 $(this).parent().addClass("open"); 172 sub.slideDown(slideSpeed, function () { 173 if (autoScroll === true && $('body').hasClass('page-sidebar-closed') === false) { 174 if ($('body').hasClass('page-sidebar-fixed')) { 175 menu.slimScroll({ 176 'scrollTo': (the.position()).top 177 }); 178 } else { 179 Metronic.scrollTo(the, slideOffeset); 180 } 181 } 182 handleSidebarAndContentHeight(); 183 }); 184 } 185 186 e.preventDefault(); 187 }); 188 189 // handle ajax links within sidebar menu 190 $('.page-sidebar').on('click', ' li > a.ajaxify', function (e) { 191 e.preventDefault(); 192 Metronic.scrollTop(); 193 194 var url = $(this).attr("href"); 195 var menuContainer = $('.page-sidebar ul'); 196 var pageContent = $('.page-content'); 197 var pageContentBody = $('.page-content .page-content-body'); 198 199 menuContainer.children('li.active').removeClass('active'); 200 menuContainer.children('arrow.open').removeClass('open'); 201 202 $(this).parents('li').each(function () { 203 $(this).addClass('active'); 204 $(this).children('a > span.arrow').addClass('open'); 205 }); 206 $(this).parents('li').addClass('active'); 207 208 if (Metronic.getViewPort().width < resBreakpointMd && $('.page-sidebar').hasClass("in")) { // close the menu on mobile view while laoding a page 209 $('.page-header .responsive-toggler').click(); 210 } 211 212 Metronic.startPageLoading(); 213 214 var the = $(this); 215 216 $.ajax({ 217 type: "GET", 218 cache: false, 219 url: url, 220 dataType: "html", 221 success: function (res) { 222 if (the.parents('li.open').size() === 0) { 223 $('.page-sidebar-menu > li.open > a').click(); 224 } 225 226 Metronic.stopPageLoading(); 227 pageContentBody.html(res); 228 Layout.fixContentHeight(); // fix content height 229 Metronic.initAjax(); // initialize core stuff 230 }, 231 error: function (xhr, ajaxOptions, thrownError) { 232 Metronic.stopPageLoading(); 233 pageContentBody.html('<h4>Could not load the requested content.</h4>'); 234 } 235 }); 236 }); 237 238 // handle ajax link within main content 239 $('.page-content').on('click', '.ajaxify', function (e) { 240 e.preventDefault(); 241 Metronic.scrollTop(); 242 243 var url = $(this).attr("href"); 244 var pageContent = $('.page-content'); 245 var pageContentBody = $('.page-content .page-content-body'); 246 247 Metronic.startPageLoading(); 248 249 if (Metronic.getViewPort().width < resBreakpointMd && $('.page-sidebar').hasClass("in")) { // close the menu on mobile view while laoding a page 250 $('.page-header .responsive-toggler').click(); 251 } 252 253 $.ajax({ 254 type: "GET", 255 cache: false, 256 url: url, 257 dataType: "html", 258 success: function (res) { 259 Metronic.stopPageLoading(); 260 pageContentBody.html(res); 261 Layout.fixContentHeight(); // fix content height 262 Metronic.initAjax(); // initialize core stuff 263 }, 264 error: function (xhr, ajaxOptions, thrownError) { 265 pageContentBody.html('<h4>Could not load the requested content.</h4>'); 266 Metronic.stopPageLoading(); 267 } 268 }); 269 }); 270 271 // handle scrolling to top on responsive menu toggler click when header is fixed for mobile view 272 $(document).on('click', '.page-header-fixed-mobile .page-header .responsive-toggler', function(){ 273 Metronic.scrollTop(); 274 }); 275 276 // handle sidebar hover effect 277 handleFixedSidebarHoverEffect(); 278 279 // handle the search bar close 280 $('.page-sidebar').on('click', '.sidebar-search .remove', function (e) { 281 e.preventDefault(); 282 $('.sidebar-search').removeClass("open"); 283 }); 284 285 // handle the search query submit on enter press 286 $('.page-sidebar .sidebar-search').on('keypress', 'input.form-control', function (e) { 287 if (e.which == 13) { 288 $('.sidebar-search').submit(); 289 return false; //<---- Add this line 290 } 291 }); 292 293 // handle the search submit(for sidebar search and responsive mode of the header search) 294 $('.sidebar-search .submit').on('click', function (e) { 295 e.preventDefault(); 296 if ($('body').hasClass("page-sidebar-closed")) { 297 if ($('.sidebar-search').hasClass('open') === false) { 298 if ($('.page-sidebar-fixed').size() === 1) { 299 $('.page-sidebar .sidebar-toggler').click(); //trigger sidebar toggle button 300 } 301 $('.sidebar-search').addClass("open"); 302 } else { 303 $('.sidebar-search').submit(); 304 } 305 } else { 306 $('.sidebar-search').submit(); 307 } 308 }); 309 310 // handle close on body click 311 if ($('.sidebar-search').size() !== 0) { 312 $('.sidebar-search .input-group').on('click', function(e){ 313 e.stopPropagation(); 314 }); 315 316 $('body').on('click', function() { 317 if ($('.sidebar-search').hasClass('open')) { 318 $('.sidebar-search').removeClass("open"); 319 } 320 }); 321 } 322 }; 323 324 // Helper function to calculate sidebar height for fixed sidebar layout. 325 var _calculateFixedSidebarViewportHeight = function () { 326 var sidebarHeight = Metronic.getViewPort().height - $('.page-header').outerHeight(); 327 if ($('body').hasClass("page-footer-fixed")) { 328 sidebarHeight = sidebarHeight - $('.page-footer').outerHeight(); 329 } 330 331 return sidebarHeight; 332 }; 333 334 // Handles fixed sidebar 335 var handleFixedSidebar = function () { 336 var menu = $('.page-sidebar-menu'); 337 338 Metronic.destroySlimScroll(menu); 339 340 if ($('.page-sidebar-fixed').size() === 0) { 341 handleSidebarAndContentHeight(); 342 return; 343 } 344 345 if (Metronic.getViewPort().width >= resBreakpointMd) { 346 menu.attr("data-height", _calculateFixedSidebarViewportHeight()); 347 Metronic.initSlimScroll(menu); 348 handleSidebarAndContentHeight(); 349 } 350 }; 351 352 // Handles sidebar toggler to close/hide the sidebar. 353 var handleFixedSidebarHoverEffect = function () { 354 var body = $('body'); 355 if (body.hasClass('page-sidebar-fixed')) { 356 $('.page-sidebar').on('mouseenter', function () { 357 if (body.hasClass('page-sidebar-closed')) { 358 $(this).find('.page-sidebar-menu').removeClass('page-sidebar-menu-closed'); 359 } 360 }).on('mouseleave', function () { 361 if (body.hasClass('page-sidebar-closed')) { 362 $(this).find('.page-sidebar-menu').addClass('page-sidebar-menu-closed'); 363 } 364 }); 365 } 366 }; 367 368 // Hanles sidebar toggler 369 var handleSidebarToggler = function () { 370 var body = $('body'); 371 if ($.cookie && $.cookie('sidebar_closed') === '1' && Metronic.getViewPort().width >= resBreakpointMd) { 372 $('body').addClass('page-sidebar-closed'); 373 $('.page-sidebar-menu').addClass('page-sidebar-menu-closed'); 374 } 375 376 // handle sidebar show/hide 377 $('body').on('click', '.sidebar-toggler', function (e) { 378 var sidebar = $('.page-sidebar'); 379 var sidebarMenu = $('.page-sidebar-menu'); 380 var pageSliderHeading = $('.page-slider-heading'); 381 382 $(".sidebar-search", sidebar).removeClass("open"); 383 384 if (body.hasClass("page-sidebar-closed")) { 385 body.removeClass("page-sidebar-closed"); 386 sidebarMenu.removeClass("page-sidebar-menu-closed"); 387 pageSliderHeading.removeClass("page-slider-heading-closed"); 388 if ($.cookie) { 389 $.cookie('sidebar_closed', '0'); 390 } 391 392 } else { 393 body.addClass("page-sidebar-closed"); 394 sidebarMenu.addClass("page-sidebar-menu-closed"); 395 pageSliderHeading.addClass("page-slider-heading-closed"); 396 if (body.hasClass("page-sidebar-fixed")) { 397 sidebarMenu.trigger("mouseleave"); 398 } 399 if ($.cookie) { 400 $.cookie('sidebar_closed', '1'); 401 } 402 } 403 404 $(window).trigger('resize'); 405 }); 406 }; 407 408 // Handles the horizontal menu 409 var handleHorizontalMenu = function () { 410 //handle tab click 411 $('.page-header').on('click', '.hor-menu a[data-toggle="tab"]', function (e) { 412 e.preventDefault(); 413 var nav = $(".hor-menu .nav"); 414 var active_link = nav.find('li.current'); 415 $('li.active', active_link).removeClass("active"); 416 $('.selected', active_link).remove(); 417 var new_link = $(this).parents('li').last(); 418 new_link.addClass("current"); 419 new_link.find("a:first").append('<span class="selected"></span>'); 420 }); 421 422 // handle search box expand/collapse 423 $('.page-header').on('click', '.search-form', function (e) { 424 $(this).addClass("open"); 425 $(this).find('.form-control').focus(); 426 427 $('.page-header .search-form .form-control').on('blur', function (e) { 428 $(this).closest('.search-form').removeClass("open"); 429 $(this).unbind("blur"); 430 }); 431 }); 432 433 // handle hor menu search form on enter press 434 $('.page-header').on('keypress', '.hor-menu .search-form .form-control', function (e) { 435 if (e.which == 13) { 436 $(this).closest('.search-form').submit(); 437 return false; 438 } 439 }); 440 441 // handle header search button click 442 $('.page-header').on('mousedown', '.search-form.open .submit', function (e) { 443 e.preventDefault(); 444 e.stopPropagation(); 445 $(this).closest('.search-form').submit(); 446 }); 447 448 // handle hover dropdown menu for desktop devices only 449 $('[data-hover="megamenu-dropdown"]').not('.hover-initialized').each(function() { 450 $(this).dropdownHover(); 451 $(this).addClass('hover-initialized'); 452 }); 453 454 $(document).on('click', '.mega-menu-dropdown .dropdown-menu', function (e) { 455 e.stopPropagation(); 456 }); 457 }; 458 459 // Handles Bootstrap Tabs. 460 var handleTabs = function () { 461 // fix content height on tab click 462 $('body').on('shown.bs.tab', 'a[data-toggle="tab"]', function () { 463 handleSidebarAndContentHeight(); 464 }); 465 }; 466 467 // Handles the go to top button at the footer 468 var handleGoTop = function () { 469 var offset = 300; 470 var duration = 500; 471 472 if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) { // ios supported 473 $(window).bind("touchend touchcancel touchleave", function(e){ 474 if ($(this).scrollTop() > offset) { 475 $('.scroll-to-top').fadeIn(duration); 476 } else { 477 $('.scroll-to-top').fadeOut(duration); 478 } 479 }); 480 } else { // general 481 $(window).scroll(function() { 482 if ($(this).scrollTop() > offset) { 483 $('.scroll-to-top').fadeIn(duration); 484 } else { 485 $('.scroll-to-top').fadeOut(duration); 486 } 487 }); 488 } 489 490 $('.scroll-to-top').click(function(e) { 491 e.preventDefault(); 492 $('html, body').animate({scrollTop: 0}, duration); 493 return false; 494 }); 495 }; 496 497 // Hanlde 100% height elements(block, portlet, etc) 498 var handle100HeightContent = function () { 499 500 var target = $('.full-height-content'); 501 var height; 502 503 height = Metronic.getViewPort().height - 504 $('.page-header').outerHeight(true) - 505 $('.page-footer').outerHeight(true) - 506 $('.page-title').outerHeight(true) - 507 $('.page-bar').outerHeight(true); 508 509 if (target.hasClass('portlet')) { 510 var portletBody = target.find('.portlet-body'); 511 512 if (Metronic.getViewPort().width < resBreakpointMd) { 513 Metronic.destroySlimScroll(portletBody.find('.full-height-content-body')); // destroy slimscroll 514 return; 515 } 516 517 height = height - 518 target.find('.portlet-title').outerHeight(true) - 519 parseInt(target.find('.portlet-body').css('padding-top')) - 520 parseInt(target.find('.portlet-body').css('padding-bottom')) - 2; 521 522 if (target.hasClass("full-height-content-scrollable")) { 523 height = height - 35; 524 portletBody.find('.full-height-content-body').css('height', height); 525 Metronic.initSlimScroll(portletBody.find('.full-height-content-body')); 526 } else { 527 portletBody.css('min-height', height); 528 } 529 } else { 530 if (Metronic.getViewPort().width < resBreakpointMd) { 531 Metronic.destroySlimScroll(target.find('.full-height-content-body')); // destroy slimscroll 532 return; 533 } 534 535 if (target.hasClass("full-height-content-scrollable")) { 536 height = height - 35; 537 target.find('.full-height-content-body').css('height', height); 538 Metronic.initSlimScroll(target.find('.full-height-content-body')); 539 } else { 540 target.css('min-height', height); 541 } 542 } 543 }; 544 //* END:CORE HANDLERS *// 545 546 return { 547 // Main init methods to initialize the layout 548 //IMPORTANT!!!: Do not modify the core handlers call order. 549 550 initHeader: function() { 551 handleHorizontalMenu(); // handles horizontal menu 552 }, 553 554 setSidebarMenuActiveLink: function(mode, el) { 555 handleSidebarMenuActiveLink(mode, el); 556 }, 557 558 initSidebar: function() { 559 //layout handlers 560 handleFixedSidebar(); // handles fixed sidebar menu 561 handleSidebarMenu(); // handles main menu 562 handleSidebarToggler(); // handles sidebar hide/show 563 564 if (Metronic.isAngularJsApp()) { 565 handleSidebarMenuActiveLink('match'); // init sidebar active links 566 } 567 568 Metronic.addResizeHandler(handleFixedSidebar); // reinitialize fixed sidebar on window resize 569 }, 570 571 initContent: function() { 572 handle100HeightContent(); // handles 100% height elements(block, portlet, etc) 573 handleTabs(); // handle bootstrah tabs 574 575 Metronic.addResizeHandler(handleSidebarAndContentHeight); // recalculate sidebar & content height on window resize 576 Metronic.addResizeHandler(handle100HeightContent); // reinitialize content height on window resize 577 }, 578 579 initFooter: function() { 580 handleGoTop(); //handles scroll to top functionality in the footer 581 }, 582 583 init: function () { 584 this.initHeader(); 585 this.initSidebar(); 586 this.initContent(); 587 this.initFooter(); 588 }, 589 590 //public function to fix the sidebar and content height accordingly 591 fixContentHeight: function () { 592 handleSidebarAndContentHeight(); 593 }, 594 595 initFixedSidebarHoverEffect: function() { 596 handleFixedSidebarHoverEffect(); 597 }, 598 599 initFixedSidebar: function() { 600 handleFixedSidebar(); 601 }, 602 603 getLayoutImgPath: function () { 604 return Metronic.getAssetsPath() + layoutImgPath; 605 }, 606 607 getLayoutCssPath: function () { 608 return Metronic.getAssetsPath() + layoutCssPath; 609 } 610 }; 611 612 }();