app-menu.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988
  1. /*=========================================================================================
  2. File Name: app-menu.js
  3. Description: Menu navigation, custom scrollbar, hover scroll bar, multilevel menu
  4. initialization and manipulations
  5. ----------------------------------------------------------------------------------------
  6. Item Name: Vusax - Vuejs, HTML & Laravel Admin Dashboard Template
  7. Author: Pixinvent
  8. Author URL: hhttp://www.themeforest.net/user/pixinvent
  9. ==========================================================================================*/
  10. (function (window, document, $) {
  11. 'use strict';
  12. let vh = window.innerHeight * 0.01;
  13. document.documentElement.style.setProperty('--vh', `${vh}px`);
  14. $.app = $.app || {};
  15. var $body = $('body');
  16. var $window = $(window);
  17. var menuWrapper_el = $('div[data-menu="menu-wrapper"]').html();
  18. var menuWrapperClasses = $('div[data-menu="menu-wrapper"]').attr('class');
  19. // Main menu
  20. $.app.menu = {
  21. expanded: null,
  22. collapsed: null,
  23. hidden: null,
  24. container: null,
  25. horizontalMenu: false,
  26. is_touch_device: function () {
  27. var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
  28. var mq = function (query) {
  29. return window.matchMedia(query).matches;
  30. }
  31. if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
  32. return true;
  33. }
  34. // include the 'heartz' as a way to have a non matching MQ to help terminate the join
  35. // https://git.io/vznFH
  36. var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
  37. return mq(query);
  38. },
  39. manualScroller: {
  40. obj: null,
  41. init: function () {
  42. var scroll_theme = ($('.main-menu').hasClass('menu-dark')) ? 'light' : 'dark';
  43. if (!$.app.menu.is_touch_device()) {
  44. this.obj = new PerfectScrollbar(".main-menu-content", {
  45. suppressScrollX: true,
  46. wheelPropagation: false
  47. });
  48. }
  49. else {
  50. $(".main-menu").addClass("menu-native-scroll")
  51. }
  52. },
  53. update: function () {
  54. if (this.obj) {
  55. // Scroll to currently active menu on page load if data-scroll-to-active is true
  56. if ($('.main-menu').data('scroll-to-active') === true) {
  57. var activeEl, menu, activeElHeight;
  58. activeEl = document.querySelector('.main-menu-content li.active');
  59. if ($body.hasClass('menu-collapsed')) {
  60. if ($('.main-menu-content li.sidebar-group-active').length) {
  61. activeEl = document.querySelector('.main-menu-content li.sidebar-group-active');
  62. }
  63. }
  64. else{
  65. menu = document.querySelector('.main-menu-content');
  66. if(activeEl){
  67. activeElHeight = activeEl.getBoundingClientRect().top + menu.scrollTop;
  68. }
  69. // If active element's top position is less than 2/3 (66%) of menu height than do not scroll
  70. if (activeElHeight > parseInt((menu.clientHeight * 2) / 3)) {
  71. var start = menu.scrollTop,
  72. change = activeElHeight - start - parseInt(menu.clientHeight / 2);
  73. }
  74. }
  75. setTimeout(function () {
  76. $.app.menu.container.stop().animate({ scrollTop: change }, 300);
  77. $('.main-menu').data('scroll-to-active', 'false');
  78. }, 300);
  79. }
  80. this.obj.update();
  81. }
  82. },
  83. enable: function () {
  84. if (!$('.main-menu-content').hasClass('ps')) {
  85. this.init();
  86. }
  87. },
  88. disable: function () {
  89. if (this.obj) {
  90. this.obj.destroy();
  91. }
  92. },
  93. updateHeight: function () {
  94. if (($body.data('menu') == 'vertical-menu' || $body.data('menu') == 'vertical-menu-modern' || $body.data('menu') == 'vertical-overlay-menu') && $('.main-menu').hasClass('menu-fixed')) {
  95. $('.main-menu-content').css('height', $(window).height() - $('.header-navbar').height() - $('.main-menu-header').outerHeight() - $('.main-menu-footer').outerHeight());
  96. this.update();
  97. }
  98. }
  99. },
  100. init: function (compactMenu) {
  101. if ($('.main-menu-content').length > 0) {
  102. this.container = $('.main-menu-content');
  103. var menuObj = this;
  104. var defMenu = '';
  105. if (compactMenu === true) {
  106. defMenu = 'collapsed';
  107. }
  108. if ($body.data('menu') == 'vertical-menu-modern') {
  109. var menuToggle = '';
  110. if (menuToggle === "false") {
  111. this.change('collapsed');
  112. }
  113. else {
  114. this.change(defMenu);
  115. }
  116. }
  117. else {
  118. this.change(defMenu);
  119. }
  120. }
  121. },
  122. drillDownMenu: function (screenSize) {
  123. if ($('.drilldown-menu').length) {
  124. if (screenSize == 'sm' || screenSize == 'xs') {
  125. if ($('#navbar-mobile').attr('aria-expanded') == 'true') {
  126. $('.drilldown-menu').slidingMenu({
  127. backLabel: true
  128. });
  129. }
  130. }
  131. else {
  132. $('.drilldown-menu').slidingMenu({
  133. backLabel: true
  134. });
  135. }
  136. }
  137. },
  138. change: function (defMenu) {
  139. var currentBreakpoint = Unison.fetch.now(); // Current Breakpoint
  140. this.reset();
  141. var menuType = $body.data('menu');
  142. if (currentBreakpoint) {
  143. switch (currentBreakpoint.name) {
  144. case 'xl':
  145. if (menuType === 'vertical-overlay-menu') {
  146. this.hide();
  147. }
  148. else {
  149. if (defMenu === 'collapsed')
  150. this.collapse(defMenu);
  151. else
  152. this.expand();
  153. }
  154. break;
  155. case 'lg':
  156. if (menuType === 'vertical-overlay-menu' || menuType === 'vertical-menu-modern' || menuType === 'horizontal-menu') {
  157. this.hide();
  158. }
  159. else {
  160. this.collapse();
  161. }
  162. break;
  163. case 'md':
  164. case 'sm':
  165. this.hide();
  166. break;
  167. case 'xs':
  168. this.hide();
  169. break;
  170. }
  171. }
  172. // On the small and extra small screen make them overlay menu
  173. if (menuType === 'vertical-menu' || menuType === 'vertical-menu-modern') {
  174. this.toOverlayMenu(currentBreakpoint.name, menuType);
  175. }
  176. if ($body.is('.horizontal-layout') && !$body.hasClass('.horizontal-menu-demo')) {
  177. this.changeMenu(currentBreakpoint.name);
  178. $('.menu-toggle').removeClass('is-active');
  179. }
  180. // Initialize drill down menu for vertical layouts, for horizontal layouts drilldown menu is intitialized in changemenu function
  181. if (menuType != 'horizontal-menu') {
  182. // Drill down menu
  183. // ------------------------------
  184. this.drillDownMenu(currentBreakpoint.name);
  185. }
  186. // Dropdown submenu on large screen on hover For Large screen only
  187. // ---------------------------------------------------------------
  188. if (currentBreakpoint.name == 'xl') {
  189. $('body[data-open="hover"] .header-navbar .dropdown').on('mouseenter', function () {
  190. if (!($(this).hasClass('show'))) {
  191. $(this).addClass('show');
  192. } else {
  193. $(this).removeClass('show');
  194. }
  195. }).on('mouseleave', function (event) {
  196. $(this).removeClass('show');
  197. });
  198. $('body[data-open="hover"] .dropdown a').on('click', function (e) {
  199. if (menuType == 'horizontal-menu') {
  200. var $this = $(this);
  201. if ($this.hasClass('dropdown-toggle')) {
  202. return false;
  203. }
  204. }
  205. });
  206. }
  207. // Added data attribute brand-center for navbar-brand-center
  208. // TODO:AJ: Shift this feature in JADE.
  209. if ($('.header-navbar').hasClass('navbar-brand-center')) {
  210. $('.header-navbar').attr('data-nav', 'brand-center');
  211. }
  212. if (currentBreakpoint.name == 'sm' || currentBreakpoint.name == 'xs') {
  213. $('.header-navbar[data-nav=brand-center]').removeClass('navbar-brand-center');
  214. } else {
  215. $('.header-navbar[data-nav=brand-center]').addClass('navbar-brand-center');
  216. }
  217. // On screen width change, current active menu in horizontal
  218. if(currentBreakpoint.name == 'xl' && menuType == 'horizontal-menu'){
  219. $(".main-menu-content").find('li.active').parents('li').addClass('sidebar-group-active active');
  220. }
  221. if(currentBreakpoint.name !== 'xl' && menuType == 'horizontal-menu'){
  222. $("#navbar-type").toggleClass('d-none d-xl-block');
  223. }
  224. // Dropdown submenu on small screen on click
  225. // --------------------------------------------------
  226. $('ul.dropdown-menu [data-toggle=dropdown]').on('click', function (event) {
  227. if ($(this).siblings('ul.dropdown-menu').length > 0) {
  228. event.preventDefault();
  229. }
  230. event.stopPropagation();
  231. $(this).parent().siblings().removeClass('show');
  232. $(this).parent().toggleClass('show');
  233. });
  234. // Horizontal layout submenu drawer scrollbar
  235. if (menuType == 'horizontal-menu') {
  236. $('li.dropdown-submenu').on('mouseenter', function(){
  237. if(!$(this).parent('.dropdown').hasClass('show')){
  238. $(this).removeClass('openLeft');
  239. }
  240. var dd = $(this).find('.dropdown-menu');
  241. if(dd.length>0){
  242. var pageHeight = $( window ).height(),
  243. ddTop = $(this).position().top,
  244. ddLeft = dd.offset().left,
  245. ddWidth = dd.width(),
  246. ddHeight = dd.height();
  247. if(((pageHeight - ddTop) - ddHeight - 28) < 1) {
  248. var maxHeight = (pageHeight - ddTop - 170);
  249. $(this).find('.dropdown-menu').css({'max-height': maxHeight+'px', 'overflow-y': 'auto','overflow-x': 'hidden'});
  250. var menu_content = new PerfectScrollbar('li.dropdown-submenu.show .dropdown-menu', {
  251. wheelPropagation: false
  252. });
  253. }
  254. // Add class to horizontal sub menu if screen width is small
  255. if(ddLeft + ddWidth - (window.innerWidth - 16) >= 0) {
  256. $(this).addClass('openLeft');
  257. }
  258. }
  259. });
  260. $('.theme-layouts').find('.semi-dark').hide();
  261. $('#customizer-navbar-colors').hide();
  262. }
  263. /********************************************
  264. * Searchable Menu *
  265. ********************************************/
  266. function searchMenu(list) {
  267. var input = $(".menu-search");
  268. $(input)
  269. .change(function () {
  270. var filter = $(this).val();
  271. if (filter) {
  272. // Hide Main Navigation Headers
  273. $('.navigation-header').hide();
  274. // this finds all links in a list that contain the input,
  275. // and hide the ones not containing the input while showing the ones that do
  276. $(list).find("li a:not(:Contains(" + filter + "))").hide().parent().hide();
  277. // $(list).find("li a:Contains(" + filter + ")").show().parents('li').show().addClass('open').closest('li').children('a').show();
  278. var searchFilter = $(list).find("li a:Contains(" + filter + ")");
  279. if (searchFilter.parent().hasClass('has-sub')) {
  280. searchFilter.show()
  281. .parents('li').show()
  282. .addClass('open')
  283. .closest('li')
  284. .children('a').show()
  285. .children('li').show();
  286. // searchFilter.parents('li').find('li').show().children('a').show();
  287. if (searchFilter.siblings('ul').length > 0) {
  288. searchFilter.siblings('ul').children('li').show().children('a').show();
  289. }
  290. }
  291. else {
  292. searchFilter.show().parents('li').show().addClass('open').closest('li').children('a').show();
  293. }
  294. } else {
  295. // return to default
  296. $('.navigation-header').show();
  297. $(list).find("li a").show().parent().show().removeClass('open');
  298. }
  299. $.app.menu.manualScroller.update();
  300. return false;
  301. })
  302. .keyup(function () {
  303. // fire the above change event after every letter
  304. $(this).change();
  305. });
  306. }
  307. if (menuType === 'vertical-menu' || menuType === 'vertical-overlay-menu') {
  308. // custom css expression for a case-insensitive contains()
  309. jQuery.expr[':'].Contains = function (a, i, m) {
  310. return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
  311. };
  312. searchMenu($("#main-menu-navigation"));
  313. }
  314. },
  315. transit: function (callback1, callback2) {
  316. var menuObj = this;
  317. $body.addClass('changing-menu');
  318. callback1.call(menuObj);
  319. if ($body.hasClass('vertical-layout')) {
  320. if ($body.hasClass('menu-open') || $body.hasClass('menu-expanded')) {
  321. $('.menu-toggle').addClass('is-active');
  322. // Show menu header search when menu is normally visible
  323. if ($body.data('menu') === 'vertical-menu') {
  324. if ($('.main-menu-header')) {
  325. $('.main-menu-header').show();
  326. }
  327. }
  328. }
  329. else {
  330. $('.menu-toggle').removeClass('is-active');
  331. // Hide menu header search when only menu icons are visible
  332. if ($body.data('menu') === 'vertical-menu') {
  333. if ($('.main-menu-header')) {
  334. $('.main-menu-header').hide();
  335. }
  336. }
  337. }
  338. }
  339. setTimeout(function () {
  340. callback2.call(menuObj);
  341. $body.removeClass('changing-menu');
  342. menuObj.update();
  343. }, 500);
  344. },
  345. open: function () {
  346. this.transit(function () {
  347. $body.removeClass('menu-hide menu-collapsed').addClass('menu-open');
  348. this.hidden = false;
  349. this.expanded = true;
  350. if ($body.hasClass('vertical-overlay-menu')) {
  351. $('.sidenav-overlay').removeClass('d-none').addClass('d-block');
  352. $('body').css('overflow', 'hidden');
  353. }
  354. }, function () {
  355. if (!$('.main-menu').hasClass('menu-native-scroll') && $('.main-menu').hasClass('menu-fixed')) {
  356. this.manualScroller.enable();
  357. $('.main-menu-content').css('height', $(window).height() - $('.header-navbar').height() - $('.main-menu-header').outerHeight() - $('.main-menu-footer').outerHeight());
  358. // this.manualScroller.update();
  359. }
  360. if (!$body.hasClass('vertical-overlay-menu')) {
  361. $('.sidenav-overlay').removeClass('d-block d-none');
  362. $('body').css('overflow', 'auto');
  363. }
  364. });
  365. },
  366. hide: function () {
  367. this.transit(function () {
  368. $body.removeClass('menu-open menu-expanded').addClass('menu-hide');
  369. this.hidden = true;
  370. this.expanded = false;
  371. if ($body.hasClass('vertical-overlay-menu')) {
  372. $('.sidenav-overlay').removeClass('d-block').addClass('d-none');
  373. $('body').css('overflow', 'auto');
  374. }
  375. }, function () {
  376. if (!$('.main-menu').hasClass('menu-native-scroll') && $('.main-menu').hasClass('menu-fixed')) {
  377. this.manualScroller.enable();
  378. }
  379. if (!$body.hasClass('vertical-overlay-menu')) {
  380. $('.sidenav-overlay').removeClass('d-block d-none');
  381. $('body').css('overflow', 'auto');
  382. }
  383. });
  384. },
  385. expand: function () {
  386. if (this.expanded === false) {
  387. if ($body.data('menu') == 'vertical-menu-modern') {
  388. $('.modern-nav-toggle').find('.toggle-icon')
  389. .removeClass('feather icon-circle').addClass('feather icon-disc');
  390. }
  391. this.transit(function () {
  392. $body.removeClass('menu-collapsed').addClass('menu-expanded');
  393. this.collapsed = false;
  394. this.expanded = true;
  395. $('.sidenav-overlay').removeClass('d-block d-none');
  396. }, function () {
  397. if (($('.main-menu').hasClass('menu-native-scroll') || $body.data('menu') == 'horizontal-menu')) {
  398. this.manualScroller.disable();
  399. }
  400. else {
  401. if ($('.main-menu').hasClass('menu-fixed'))
  402. this.manualScroller.enable();
  403. }
  404. if (($body.data('menu') == 'vertical-menu' || $body.data('menu') == 'vertical-menu-modern') && $('.main-menu').hasClass('menu-fixed')) {
  405. $('.main-menu-content').css('height', $(window).height() - $('.header-navbar').height() - $('.main-menu-header').outerHeight() - $('.main-menu-footer').outerHeight());
  406. // this.manualScroller.update();
  407. }
  408. });
  409. }
  410. },
  411. collapse: function (defMenu) {
  412. if (this.collapsed === false) {
  413. if ($body.data('menu') == 'vertical-menu-modern') {
  414. $('.modern-nav-toggle').find('.toggle-icon')
  415. .removeClass('feather icon-disc').addClass('feather icon-circle');
  416. }
  417. this.transit(function () {
  418. $body.removeClass('menu-expanded').addClass('menu-collapsed');
  419. this.collapsed = true;
  420. this.expanded = false;
  421. $('.content-overlay').removeClass('d-block d-none');
  422. }, function () {
  423. if (($body.data('menu') == 'horizontal-menu') && $body.hasClass('vertical-overlay-menu')) {
  424. if ($('.main-menu').hasClass('menu-fixed'))
  425. this.manualScroller.enable();
  426. }
  427. if (($body.data('menu') == 'vertical-menu' || $body.data('menu') == 'vertical-menu-modern') && $('.main-menu').hasClass('menu-fixed')) {
  428. $('.main-menu-content').css('height', $(window).height() - $('.header-navbar').height());
  429. // this.manualScroller.update();
  430. }
  431. if ($body.data('menu') == 'vertical-menu-modern') {
  432. if ($('.main-menu').hasClass('menu-fixed'))
  433. this.manualScroller.enable();
  434. }
  435. });
  436. }
  437. },
  438. toOverlayMenu: function (screen, menuType) {
  439. var menu = $body.data('menu');
  440. if (menuType == 'vertical-menu-modern') {
  441. if (screen == 'lg' || screen == 'md' || screen == 'sm' || screen == 'xs') {
  442. if ($body.hasClass(menu)) {
  443. $body.removeClass(menu).addClass('vertical-overlay-menu');
  444. }
  445. }
  446. else {
  447. if ($body.hasClass('vertical-overlay-menu')) {
  448. $body.removeClass('vertical-overlay-menu').addClass(menu);
  449. }
  450. }
  451. }
  452. else {
  453. if (screen == 'sm' || screen == 'xs') {
  454. if ($body.hasClass(menu)) {
  455. $body.removeClass(menu).addClass('vertical-overlay-menu');
  456. }
  457. }
  458. else {
  459. if ($body.hasClass('vertical-overlay-menu')) {
  460. $body.removeClass('vertical-overlay-menu').addClass(menu);
  461. }
  462. }
  463. }
  464. },
  465. changeMenu: function (screen) {
  466. // Replace menu html
  467. $('div[data-menu="menu-wrapper"]').html('');
  468. $('div[data-menu="menu-wrapper"]').html(menuWrapper_el);
  469. var menuWrapper = $('div[data-menu="menu-wrapper"]'),
  470. menuContainer = $('div[data-menu="menu-container"]'),
  471. menuNavigation = $('ul[data-menu="menu-navigation"]'),
  472. /*megaMenu = $('li[data-menu="megamenu"]'),
  473. megaMenuCol = $('li[data-mega-col]'),*/
  474. dropdownMenu = $('li[data-menu="dropdown"]'),
  475. dropdownSubMenu = $('li[data-menu="dropdown-submenu"]');
  476. if (screen === 'xl') {
  477. // Change body classes
  478. $body.removeClass('vertical-layout vertical-overlay-menu fixed-navbar').addClass($body.data('menu'));
  479. // Remove navbar-fix-top class on large screens
  480. $('nav.header-navbar').removeClass('fixed-top');
  481. // Change menu wrapper, menu container, menu navigation classes
  482. menuWrapper.removeClass().addClass(menuWrapperClasses);
  483. // Intitialize drill down menu for horizontal layouts
  484. // --------------------------------------------------
  485. this.drillDownMenu(screen);
  486. $('a.dropdown-item.nav-has-children').on('click', function () {
  487. event.preventDefault();
  488. event.stopPropagation();
  489. });
  490. $('a.dropdown-item.nav-has-parent').on('click', function () {
  491. event.preventDefault();
  492. event.stopPropagation();
  493. });
  494. }
  495. else {
  496. // Change body classes
  497. $body.removeClass($body.data('menu')).addClass('vertical-layout vertical-overlay-menu fixed-navbar');
  498. // Add navbar-fix-top class on small screens
  499. $('nav.header-navbar').addClass('fixed-top');
  500. // Change menu wrapper, menu container, menu navigation classes
  501. menuWrapper.removeClass().addClass('main-menu menu-light menu-fixed menu-shadow');
  502. // menuContainer.removeClass().addClass('main-menu-content');
  503. menuNavigation.removeClass().addClass('navigation navigation-main');
  504. // If Dropdown Menu
  505. dropdownMenu.removeClass('dropdown').addClass('has-sub');
  506. dropdownMenu.find('a').removeClass('dropdown-toggle nav-link');
  507. dropdownMenu.children('ul').find('a').removeClass('dropdown-item');
  508. dropdownMenu.find('ul').removeClass('dropdown-menu');
  509. dropdownSubMenu.removeClass().addClass('has-sub');
  510. $.app.nav.init();
  511. // Dropdown submenu on small screen on click
  512. // --------------------------------------------------
  513. $('ul.dropdown-menu [data-toggle=dropdown]').on('click', function (event) {
  514. event.preventDefault();
  515. event.stopPropagation();
  516. $(this).parent().siblings().removeClass('open');
  517. $(this).parent().toggleClass('open');
  518. });
  519. $(".main-menu-content").find('li.active').parents('li').addClass('sidebar-group-active');
  520. $(".main-menu-content").find("li.active").closest("li.nav-item").addClass("open");
  521. }
  522. },
  523. toggle: function () {
  524. var currentBreakpoint = Unison.fetch.now(); // Current Breakpoint
  525. var collapsed = this.collapsed;
  526. var expanded = this.expanded;
  527. var hidden = this.hidden;
  528. var menu = $body.data('menu');
  529. switch (currentBreakpoint.name) {
  530. case 'xl':
  531. if (expanded === true) {
  532. if (menu == 'vertical-overlay-menu') {
  533. this.hide();
  534. }
  535. else {
  536. this.collapse();
  537. }
  538. }
  539. else {
  540. if (menu == 'vertical-overlay-menu') {
  541. this.open();
  542. }
  543. else {
  544. this.expand();
  545. }
  546. }
  547. break;
  548. case 'lg':
  549. if (expanded === true) {
  550. if (menu == 'vertical-overlay-menu' || menu == 'vertical-menu-modern' || menu == 'horizontal-menu') {
  551. this.hide();
  552. }
  553. else {
  554. this.collapse();
  555. }
  556. }
  557. else {
  558. if (menu == 'vertical-overlay-menu' || menu == 'vertical-menu-modern' || menu == 'horizontal-menu') {
  559. this.open();
  560. }
  561. else {
  562. this.expand();
  563. }
  564. }
  565. break;
  566. case 'md':
  567. case 'sm':
  568. if (hidden === true) {
  569. this.open();
  570. } else {
  571. this.hide();
  572. }
  573. break;
  574. case 'xs':
  575. if (hidden === true) {
  576. this.open();
  577. } else {
  578. this.hide();
  579. }
  580. break;
  581. }
  582. // Re-init sliding menu to update width
  583. this.drillDownMenu(currentBreakpoint.name);
  584. },
  585. update: function () {
  586. this.manualScroller.update();
  587. },
  588. reset: function () {
  589. this.expanded = false;
  590. this.collapsed = false;
  591. this.hidden = false;
  592. $body.removeClass('menu-hide menu-open menu-collapsed menu-expanded');
  593. },
  594. };
  595. // Navigation Menu
  596. $.app.nav = {
  597. container: $('.navigation-main'),
  598. initialized: false,
  599. navItem: $('.navigation-main').find('li').not('.navigation-category'),
  600. config: {
  601. speed: 300,
  602. },
  603. init: function (config) {
  604. this.initialized = true; // Set to true when initialized
  605. $.extend(this.config, config);
  606. this.bind_events();
  607. },
  608. bind_events: function () {
  609. var menuObj = this;
  610. $('.navigation-main').on('mouseenter.app.menu', 'li', function () {
  611. var $this = $(this);
  612. $('.hover', '.navigation-main').removeClass('hover');
  613. if ($body.hasClass('menu-collapsed') && $body.data('menu') != 'vertical-menu-modern') {
  614. $('.main-menu-content').children('span.menu-title').remove();
  615. $('.main-menu-content').children('a.menu-title').remove();
  616. $('.main-menu-content').children('ul.menu-content').remove();
  617. // Title
  618. var menuTitle = $this.find('span.menu-title').clone(),
  619. tempTitle,
  620. tempLink;
  621. if (!$this.hasClass('has-sub')) {
  622. tempTitle = $this.find('span.menu-title').text();
  623. tempLink = $this.children('a').attr('href');
  624. if (tempTitle !== '') {
  625. menuTitle = $("<a>");
  626. menuTitle.attr("href", tempLink);
  627. menuTitle.attr("title", tempTitle);
  628. menuTitle.text(tempTitle);
  629. menuTitle.addClass("menu-title");
  630. }
  631. }
  632. // menu_header_height = ($('.main-menu-header').length) ? $('.main-menu-header').height() : 0,
  633. // fromTop = menu_header_height + $this.position().top + parseInt($this.css( "border-top" ),10);
  634. var fromTop;
  635. if ($this.css("border-top")) {
  636. fromTop = $this.position().top + parseInt($this.css("border-top"), 10);
  637. }
  638. else {
  639. fromTop = $this.position().top;
  640. }
  641. if ($body.data('menu') !== 'vertical-compact-menu') {
  642. menuTitle.appendTo('.main-menu-content').css({
  643. position: 'fixed',
  644. top: fromTop,
  645. });
  646. }
  647. // Content
  648. if ($this.hasClass('has-sub') && $this.hasClass('nav-item')) {
  649. var menuContent = $this.children('ul:first');
  650. menuObj.adjustSubmenu($this);
  651. }
  652. }
  653. $this.addClass('hover');
  654. }).on('mouseleave.app.menu', 'li', function () {
  655. // $(this).removeClass('hover');
  656. }).on('active.app.menu', 'li', function (e) {
  657. $(this).addClass('active');
  658. e.stopPropagation();
  659. }).on('deactive.app.menu', 'li.active', function (e) {
  660. $(this).removeClass('active');
  661. e.stopPropagation();
  662. }).on('open.app.menu', 'li', function (e) {
  663. var $listItem = $(this);
  664. $listItem.addClass('open');
  665. menuObj.expand($listItem);
  666. // If menu collapsible then do not take any action
  667. if ($('.main-menu').hasClass('menu-collapsible')) {
  668. return false;
  669. }
  670. // If menu accordion then close all except clicked once
  671. else {
  672. $listItem.siblings('.open').find('li.open').trigger('close.app.menu');
  673. $listItem.siblings('.open').trigger('close.app.menu');
  674. }
  675. e.stopPropagation();
  676. }).on('close.app.menu', 'li.open', function (e) {
  677. var $listItem = $(this);
  678. $listItem.removeClass('open');
  679. menuObj.collapse($listItem);
  680. e.stopPropagation();
  681. }).on('click.app.menu', 'li', function (e) {
  682. var $listItem = $(this);
  683. if ($listItem.is('.disabled')) {
  684. e.preventDefault();
  685. }
  686. else {
  687. if ($body.hasClass('menu-collapsed') && $body.data('menu') != 'vertical-menu-modern') {
  688. e.preventDefault();
  689. }
  690. else {
  691. if ($listItem.has('ul').length) {
  692. if ($listItem.is('.open')) {
  693. $listItem.trigger('close.app.menu');
  694. } else {
  695. $listItem.trigger('open.app.menu');
  696. }
  697. } else {
  698. if (!$listItem.is('.active')) {
  699. $listItem.siblings('.active').trigger('deactive.app.menu');
  700. $listItem.trigger('active.app.menu');
  701. }
  702. }
  703. }
  704. }
  705. e.stopPropagation();
  706. });
  707. $('.navbar-header, .main-menu').on('mouseenter', modernMenuExpand).on('mouseleave', modernMenuCollapse);
  708. function modernMenuExpand() {
  709. if ($body.data('menu') == 'vertical-menu-modern') {
  710. $('.main-menu, .navbar-header').addClass('expanded');
  711. if ($body.hasClass('menu-collapsed')) {
  712. if ($('.main-menu li.open').length === 0) {
  713. $(".main-menu-content").find('li.active').parents('li').addClass('open');
  714. }
  715. var $listItem = $('.main-menu li.menu-collapsed-open'),
  716. $subList = $listItem.children('ul');
  717. $subList.hide().slideDown(200, function () {
  718. $(this).css('display', '');
  719. });
  720. $listItem.addClass('open').removeClass('menu-collapsed-open');
  721. // $.app.menu.changeLogo('expand');
  722. }
  723. }
  724. }
  725. function modernMenuCollapse() {
  726. if ($body.hasClass('menu-collapsed') && $body.data('menu') == 'vertical-menu-modern') {
  727. setTimeout(function () {
  728. if ($('.main-menu:hover').length === 0 && $('.navbar-header:hover').length === 0) {
  729. $('.main-menu, .navbar-header').removeClass('expanded');
  730. if ($body.hasClass('menu-collapsed')) {
  731. var $listItem = $('.main-menu li.open'),
  732. $subList = $listItem.children('ul');
  733. $listItem.addClass('menu-collapsed-open');
  734. $subList.show().slideUp(200, function () {
  735. $(this).css('display', '');
  736. });
  737. $listItem.removeClass('open');
  738. // $.app.menu.changeLogo();
  739. }
  740. }
  741. }, 1);
  742. }
  743. }
  744. $('.main-menu-content').on('mouseleave', function () {
  745. if ($body.hasClass('menu-collapsed')) {
  746. $('.main-menu-content').children('span.menu-title').remove();
  747. $('.main-menu-content').children('a.menu-title').remove();
  748. $('.main-menu-content').children('ul.menu-content').remove();
  749. }
  750. $('.hover', '.navigation-main').removeClass('hover');
  751. });
  752. // If list item has sub menu items then prevent redirection.
  753. $('.navigation-main li.has-sub > a').on('click', function (e) {
  754. e.preventDefault();
  755. });
  756. $('ul.menu-content').on('click', 'li', function (e) {
  757. var $listItem = $(this);
  758. if ($listItem.is('.disabled')) {
  759. e.preventDefault();
  760. }
  761. else {
  762. if ($listItem.has('ul')) {
  763. if ($listItem.is('.open')) {
  764. $listItem.removeClass('open');
  765. menuObj.collapse($listItem);
  766. } else {
  767. $listItem.addClass('open');
  768. menuObj.expand($listItem);
  769. // If menu collapsible then do not take any action
  770. if ($('.main-menu').hasClass('menu-collapsible')) {
  771. return false;
  772. }
  773. // If menu accordion then close all except clicked once
  774. else {
  775. $listItem.siblings('.open').find('li.open').trigger('close.app.menu');
  776. $listItem.siblings('.open').trigger('close.app.menu');
  777. }
  778. e.stopPropagation();
  779. }
  780. } else {
  781. if (!$listItem.is('.active')) {
  782. $listItem.siblings('.active').trigger('deactive.app.menu');
  783. $listItem.trigger('active.app.menu');
  784. }
  785. }
  786. }
  787. e.stopPropagation();
  788. });
  789. },
  790. /**
  791. * Ensure an admin submenu is within the visual viewport.
  792. * @param {jQuery} $menuItem The parent menu item containing the submenu.
  793. */
  794. adjustSubmenu: function ($menuItem) {
  795. var menuHeaderHeight, menutop, topPos, winHeight,
  796. bottomOffset, subMenuHeight, popOutMenuHeight, borderWidth, scroll_theme,
  797. $submenu = $menuItem.children('ul:first'),
  798. ul = $submenu.clone(true);
  799. menuHeaderHeight = $('.main-menu-header').height();
  800. menutop = $menuItem.position().top;
  801. winHeight = $window.height() - $('.header-navbar').height();
  802. borderWidth = 0;
  803. subMenuHeight = $submenu.height();
  804. if (parseInt($menuItem.css("border-top"), 10) > 0) {
  805. borderWidth = parseInt($menuItem.css("border-top"), 10);
  806. }
  807. popOutMenuHeight = winHeight - menutop - $menuItem.height() - 30;
  808. scroll_theme = ($('.main-menu').hasClass('menu-dark')) ? 'light' : 'dark';
  809. topPos = menutop + $menuItem.height() + borderWidth;
  810. ul.addClass('menu-popout').appendTo('.main-menu-content').css({
  811. 'top': topPos,
  812. 'position': 'fixed',
  813. 'max-height': popOutMenuHeight,
  814. });
  815. var menu_content = new PerfectScrollbar('.main-menu-content > ul.menu-content', {
  816. wheelPropagation: false
  817. });
  818. },
  819. collapse: function ($listItem, callback) {
  820. var $subList = $listItem.children('ul');
  821. $subList.show().slideUp($.app.nav.config.speed, function () {
  822. $(this).css('display', '');
  823. $(this).find('> li').removeClass('is-shown');
  824. if (callback) {
  825. callback();
  826. }
  827. $.app.nav.container.trigger('collapsed.app.menu');
  828. });
  829. },
  830. expand: function ($listItem, callback) {
  831. var $subList = $listItem.children('ul');
  832. var $children = $subList.children('li').addClass('is-hidden');
  833. $subList.hide().slideDown($.app.nav.config.speed, function () {
  834. $(this).css('display', '');
  835. if (callback) {
  836. callback();
  837. }
  838. $.app.nav.container.trigger('expanded.app.menu');
  839. });
  840. setTimeout(function () {
  841. $children.addClass('is-shown');
  842. $children.removeClass('is-hidden');
  843. }, 0);
  844. },
  845. refresh: function () {
  846. $.app.nav.container.find('.open').removeClass('open');
  847. },
  848. };
  849. })(window, document, jQuery);
  850. // We listen to the resize event
  851. window.addEventListener('resize', () => {
  852. // We execute the same script as before
  853. let vh = window.innerHeight * 0.01;
  854. document.documentElement.style.setProperty('--vh', `${vh}px`);
  855. });