app-menu.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  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: Robust - Responsive Admin Theme
  7. Version: 1.2
  8. Author: GeeksLabs
  9. Author URL: http://www.themeforest.net/user/geekslabs
  10. ==========================================================================================*/
  11. (function(window, document, $) {
  12. 'use strict';
  13. $.app = $.app || {};
  14. var $body = $('body');
  15. var $window = $( window );
  16. var menuWrapper_el = $('div[data-menu="menu-wrapper"]').html();
  17. var menuWrapperClasses = $('div[data-menu="menu-wrapper"]').attr('class');
  18. // Main menu
  19. $.app.menu = {
  20. expanded: null,
  21. collapsed: null,
  22. hidden : null,
  23. container: null,
  24. horizontalMenu: false,
  25. manualScroller: {
  26. obj: null,
  27. init: function() {
  28. var scroll_theme = ($('.main-menu').hasClass('menu-dark')) ? 'light' : 'dark';
  29. this.obj = $(".main-menu-content").perfectScrollbar({
  30. suppressScrollX: true,
  31. theme: scroll_theme
  32. });
  33. },
  34. update: function() {
  35. if (this.obj) {
  36. // Scroll to currently active menu on page load if data-scroll-to-active is true
  37. if($('.main-menu').data('scroll-to-active') === true){
  38. var position;
  39. if( $(".main-menu-content").find('li.active').parents('li').length > 0 ){
  40. position = $(".main-menu-content").find('li.active').parents('li').last().position();
  41. }
  42. else{
  43. position = $(".main-menu-content").find('li.active').position();
  44. }
  45. setTimeout(function(){
  46. // $.app.menu.container.scrollTop(position.top);
  47. $.app.menu.container.stop().animate({scrollTop:position.top}, 300);
  48. $('.main-menu').data('scroll-to-active', 'false');
  49. },300);
  50. }
  51. $(".main-menu-content").perfectScrollbar('update');
  52. }
  53. },
  54. enable: function() {
  55. this.init();
  56. },
  57. disable: function() {
  58. if (this.obj) {
  59. $('.main-menu-content').perfectScrollbar('destroy');
  60. }
  61. },
  62. updateHeight: function(){
  63. if( ($body.data('menu') == 'vertical-menu' || $body.data('menu') == 'vertical-overlay-menu' ) && $('.main-menu').hasClass('menu-fixed')){
  64. $('.main-menu-content').css('height', $(window).height() - $('.header-navbar').height() - $('.main-menu-header').outerHeight() - $('.main-menu-footer').outerHeight() );
  65. this.update();
  66. }
  67. }
  68. },
  69. init: function() {
  70. if($('.main-menu-content').length > 0){
  71. this.container = $('.main-menu-content');
  72. var menuObj = this;
  73. this.change();
  74. }
  75. else{
  76. // For 1 column layout menu won't be initialized so initiate drill down for mega menu
  77. // Drill down menu
  78. // ------------------------------
  79. this.drillDownMenu();
  80. }
  81. },
  82. drillDownMenu: function(screenSize){
  83. if($('.drilldown-menu').length){
  84. if(screenSize == 'sm' || screenSize == 'xs'){
  85. if($('#navbar-mobile').attr('aria-expanded') == 'true'){
  86. $('.drilldown-menu').slidingMenu({
  87. backLabel:true
  88. });
  89. }
  90. }
  91. else{
  92. $('.drilldown-menu').slidingMenu({
  93. backLabel:true
  94. });
  95. }
  96. }
  97. },
  98. change: function() {
  99. var currentBreakpoint = Unison.fetch.now(); // Current Breakpoint
  100. this.reset();
  101. var menuType = $body.data('menu');
  102. if (currentBreakpoint) {
  103. switch (currentBreakpoint.name) {
  104. case 'xl':
  105. case 'lg':
  106. if(menuType === 'vertical-overlay-menu'){
  107. this.hide();
  108. }
  109. else if(menuType === 'vertical-compact-menu'){
  110. this.open();
  111. }
  112. else{
  113. this.expand();
  114. }
  115. break;
  116. case 'md':
  117. if(menuType === 'vertical-overlay-menu' || menuType === 'vertical-mmenu'){
  118. this.hide();
  119. }
  120. else if(menuType === 'vertical-compact-menu'){
  121. this.open();
  122. }
  123. else{
  124. this.collapse();
  125. }
  126. break;
  127. case 'sm':
  128. this.hide();
  129. break;
  130. case 'xs':
  131. this.hide();
  132. break;
  133. }
  134. }
  135. // On the small and extra small screen make them overlay menu
  136. if(menuType === 'vertical-menu' || menuType === 'vertical-compact-menu' || menuType === 'vertical-content-menu'){
  137. this.toOverlayMenu(currentBreakpoint.name);
  138. }
  139. // Initialize drill down menu for vertical layouts, for horizontal layouts drilldown menu is intitialized in changemenu function
  140. if(menuType != 'horizontal-menu' && menuType != 'horizontal-top-icon-menu'){
  141. // Drill down menu
  142. // ------------------------------
  143. this.drillDownMenu(currentBreakpoint.name);
  144. }
  145. // Dropdown submenu on large screen on hover For Large screen only
  146. // ---------------------------------------------------------------
  147. if(currentBreakpoint.name == 'xl'){
  148. $('body[data-open="hover"] .dropdown').on('mouseenter', function(){
  149. if (!($(this).hasClass('open'))) {
  150. $(this).addClass('open');
  151. }else{
  152. $(this).removeClass('open');
  153. }
  154. }).on('mouseleave', function(event){
  155. $(this).removeClass('open');
  156. });
  157. $('body[data-open="hover"] .dropdown a').on('click', function(e){
  158. if(menuType == 'horizontal-menu' || menuType == 'horizontal-top-icon-menu'){
  159. var $this = $(this);
  160. if($this.hasClass('dropdown-toggle')){
  161. return false;
  162. }
  163. }
  164. });
  165. }
  166. // Added data attribute brand-center for navbar-brand-center
  167. // TODO:AJ: Shift this feature in JADE.
  168. if($('.header-navbar').hasClass('navbar-brand-center')){
  169. $('.header-navbar').attr('data-nav','brand-center');
  170. }
  171. if(currentBreakpoint.name == 'sm' || currentBreakpoint.name == 'xs'){
  172. $('.header-navbar[data-nav=brand-center]').removeClass('navbar-brand-center');
  173. }else{
  174. $('.header-navbar[data-nav=brand-center]').addClass('navbar-brand-center');
  175. }
  176. // Dropdown submenu on small screen on click
  177. // --------------------------------------------------
  178. $('ul.dropdown-menu [data-toggle=dropdown]').on('click', function(event) {
  179. if($(this).siblings('ul.dropdown-menu').length > 0){
  180. event.preventDefault();
  181. }
  182. event.stopPropagation();
  183. $(this).parent().siblings().removeClass('open');
  184. $(this).parent().toggleClass('open');
  185. });
  186. },
  187. changeLogo: function(menuType){
  188. var logo = $('.brand-logo');
  189. if(menuType == 'expand'){
  190. logo.attr('src',logo.data('expand'));
  191. }
  192. else{
  193. logo.attr('src',logo.data('collapse'));
  194. }
  195. },
  196. transit: function(callback1, callback2) {
  197. var menuObj = this;
  198. $body.addClass('changing-menu');
  199. callback1.call(menuObj);
  200. if($body.hasClass('vertical-layout')){
  201. if($body.hasClass('menu-open') || $body.hasClass('menu-expanded')){
  202. $('.menu-toggle').addClass('is-active');
  203. // Show menu header search when menu is normally visible
  204. if( $body.data('menu') === 'vertical-menu' || $body.data('menu') === 'vertical-content-menu'){
  205. if($('.main-menu-header')){
  206. $('.main-menu-header').show();
  207. }
  208. }
  209. }
  210. else{
  211. $('.menu-toggle').removeClass('is-active');
  212. // Hide menu header search when only menu icons are visible
  213. if( $body.data('menu') === 'vertical-menu' || $body.data('menu') === 'vertical-content-menu'){
  214. if($('.main-menu-header')){
  215. $('.main-menu-header').hide();
  216. }
  217. }
  218. }
  219. }
  220. setTimeout(function() {
  221. callback2.call(menuObj);
  222. $body.removeClass('changing-menu');
  223. menuObj.update();
  224. }, 500);
  225. },
  226. open: function() {
  227. if($body.is('.vertical-mmenu')){
  228. this.mMenu.enable();
  229. }
  230. this.transit(function() {
  231. $body.removeClass('menu-hide menu-collapsed').addClass('menu-open');
  232. this.hidden = false;
  233. this.expanded = true;
  234. }, function() {
  235. if(!$('.main-menu').hasClass('menu-native-scroll') && !$body.is('.vertical-mmenu') && $('.main-menu').hasClass('menu-fixed') ){
  236. this.manualScroller.enable();
  237. $('.main-menu-content').css('height', $(window).height() - $('.header-navbar').height() - $('.main-menu-header').outerHeight() - $('.main-menu-footer').outerHeight() );
  238. // this.manualScroller.update();
  239. }
  240. });
  241. },
  242. hide: function() {
  243. if($body.is('.vertical-mmenu')){
  244. this.mMenu.disable();
  245. }
  246. this.transit(function() {
  247. $body.removeClass('menu-open menu-expanded').addClass('menu-hide');
  248. this.hidden = true;
  249. this.expanded = false;
  250. }, function() {
  251. if(!$('.main-menu').hasClass('menu-native-scroll') && !$body.is('.vertical-mmenu') && $('.main-menu').hasClass('menu-fixed')){
  252. this.manualScroller.enable();
  253. }
  254. });
  255. },
  256. expand: function() {
  257. if (this.expanded === false) {
  258. if( $body.data('menu') == 'vertical-menu'){
  259. this.changeLogo('expand');
  260. }
  261. this.transit(function() {
  262. $body.removeClass('menu-collapsed').addClass('menu-expanded');
  263. this.collapsed = false;
  264. this.expanded = true;
  265. }, function() {
  266. if($body.is('.vertical-mmenu')){
  267. this.mMenu.enable();
  268. }
  269. else if( ($('.main-menu').hasClass('menu-native-scroll') || $body.data('menu') == 'vertical-mmenu' || $body.data('menu') == 'horizontal-menu' || $body.data('menu') == 'horizontal-top-icon-menu' )){
  270. this.manualScroller.disable();
  271. }
  272. else{
  273. if($('.main-menu').hasClass('menu-fixed'))
  274. this.manualScroller.enable();
  275. }
  276. if( $body.data('menu') == 'vertical-menu' && $('.main-menu').hasClass('menu-fixed')){
  277. $('.main-menu-content').css('height', $(window).height() - $('.header-navbar').height() - $('.main-menu-header').outerHeight() - $('.main-menu-footer').outerHeight() );
  278. // this.manualScroller.update();
  279. }
  280. });
  281. }
  282. },
  283. collapse: function() {
  284. if (this.collapsed === false) {
  285. if( ($body.data('menu') == 'vertical-menu' ) ){
  286. this.changeLogo('collapse');
  287. }
  288. this.transit(function() {
  289. $body.removeClass('menu-expanded').addClass('menu-collapsed');
  290. this.collapsed = true;
  291. this.expanded = false;
  292. }, function() {
  293. if($body.data('menu') == 'vertical-content-menu'){
  294. this.manualScroller.disable();
  295. }
  296. if( ($body.data('menu') == 'horizontal-menu' || $body.data('menu') == 'horizontal-top-icon-menu') && $body.hasClass('vertical-overlay-menu')){
  297. if($('.main-menu').hasClass('menu-fixed'))
  298. this.manualScroller.enable();
  299. }
  300. if( $body.data('menu') == 'vertical-menu' && $('.main-menu').hasClass('menu-fixed') ){
  301. $('.main-menu-content').css('height', $(window).height() - $('.header-navbar').height());
  302. // this.manualScroller.update();
  303. }
  304. });
  305. }
  306. },
  307. toOverlayMenu: function(screen){
  308. var menu = $body.data('menu');
  309. if(screen == 'sm' || screen == 'xs'){
  310. if($body.hasClass(menu)){
  311. $body.removeClass(menu).addClass('vertical-overlay-menu');
  312. }
  313. if(menu == 'vertical-content-menu'){
  314. $('.main-menu').addClass('menu-fixed');
  315. }
  316. }
  317. else{
  318. if($body.hasClass('vertical-overlay-menu')){
  319. $body.removeClass('vertical-overlay-menu').addClass(menu);
  320. }
  321. if(menu == 'vertical-content-menu'){
  322. $('.main-menu').removeClass('menu-fixed');
  323. }
  324. }
  325. },
  326. toggle: function() {
  327. var currentBreakpoint = Unison.fetch.now(); // Current Breakpoint
  328. var collapsed = this.collapsed;
  329. var expanded = this.expanded;
  330. var hidden = this.hidden;
  331. var menu = $body.data('menu');
  332. switch (currentBreakpoint.name) {
  333. case 'xl':
  334. case 'lg':
  335. case 'md':
  336. if(expanded === true){
  337. if(menu == 'vertical-compact-menu' || menu == 'vertical-mmenu' || menu == 'vertical-overlay-menu'){
  338. this.hide();
  339. }
  340. else{
  341. this.collapse();
  342. }
  343. }
  344. else{
  345. if(menu == 'vertical-compact-menu' || menu == 'vertical-mmenu' || menu == 'vertical-overlay-menu'){
  346. this.open();
  347. }
  348. else{
  349. this.expand();
  350. }
  351. }
  352. break;
  353. case 'sm':
  354. if (hidden === true) {
  355. this.open();
  356. } else {
  357. this.hide();
  358. }
  359. break;
  360. case 'xs':
  361. if (hidden === true) {
  362. this.open();
  363. } else {
  364. this.hide();
  365. }
  366. break;
  367. }
  368. // Re-init sliding menu to update width
  369. this.drillDownMenu(currentBreakpoint.name);
  370. },
  371. update: function() {
  372. this.manualScroller.update();
  373. },
  374. reset: function() {
  375. this.expanded = false;
  376. this.collapsed = false;
  377. this.hidden = false;
  378. $body.removeClass('menu-hide menu-open menu-collapsed menu-expanded');
  379. },
  380. };
  381. // Navigation Menu
  382. $.app.nav = {
  383. container: $('.navigation-main'),
  384. initialized : false,
  385. navItem: $('.navigation-main').find('li').not('.navigation-category'),
  386. config: {
  387. speed: 300,
  388. },
  389. init: function(config) {
  390. this.initialized = true; // Set to true when initialized
  391. $.extend(this.config, config);
  392. if(!$body.is('.vertical-mmenu')){
  393. this.bind_events();
  394. }
  395. },
  396. bind_events: function() {
  397. var menuObj = this;
  398. $('.navigation-main').on('mouseenter.app.menu', 'li', function() {
  399. var $this = $(this);
  400. $('.hover', '.navigation-main').removeClass('hover');
  401. if( $body.hasClass('menu-collapsed') || ($body.data('menu') == 'vertical-compact-menu' && !$body.hasClass('vertical-overlay-menu')) ){
  402. $('.main-menu-content').children('span.menu-title').remove();
  403. $('.main-menu-content').children('a.menu-title').remove();
  404. $('.main-menu-content').children('ul.menu-content').remove();
  405. // Title
  406. var menuTitle = $this.find('span.menu-title').clone(),
  407. tempTitle,
  408. tempLink;
  409. if(!$this.hasClass('has-sub') ){
  410. tempTitle = $this.find('span.menu-title').text();
  411. tempLink = $this.children('a').attr('href');
  412. if(tempTitle !== ''){
  413. menuTitle = $("<a>");
  414. menuTitle.attr("href", tempLink);
  415. menuTitle.attr("title", tempTitle);
  416. menuTitle.text(tempTitle);
  417. menuTitle.addClass("menu-title");
  418. }
  419. }
  420. // menu_header_height = ($('.main-menu-header').length) ? $('.main-menu-header').height() : 0,
  421. // fromTop = menu_header_height + $this.position().top + parseInt($this.css( "border-top" ),10);
  422. var fromTop;
  423. if($this.css( "border-top" )){
  424. fromTop = $this.position().top + parseInt($this.css( "border-top" ), 10);
  425. }
  426. else{
  427. fromTop = $this.position().top;
  428. }
  429. if($body.data('menu') !== 'vertical-compact-menu'){
  430. menuTitle.appendTo('.main-menu-content').css({
  431. position:'fixed',
  432. top : fromTop,
  433. });
  434. }
  435. // Content
  436. if($this.hasClass('has-sub') && $this.hasClass('nav-item')) {
  437. var menuContent = $this.children('ul:first');
  438. menuObj.adjustSubmenu($this);
  439. }
  440. }
  441. $this.addClass('hover');
  442. }).on('mouseleave.app.menu', 'li', function() {
  443. // $(this).removeClass('hover');
  444. }).on('active.app.menu', 'li', function(e) {
  445. $(this).addClass('active');
  446. e.stopPropagation();
  447. }).on('deactive.app.menu', 'li.active', function(e) {
  448. $(this).removeClass('active');
  449. e.stopPropagation();
  450. }).on('open.app.menu', 'li', function(e) {
  451. var $listItem = $(this);
  452. $listItem.addClass('open');
  453. menuObj.expand($listItem);
  454. // If menu collapsible then do not take any action
  455. if ($('.main-menu').hasClass('menu-collapsible')) {
  456. return false;
  457. }
  458. // If menu accordion then close all except clicked once
  459. else{
  460. $listItem.siblings('.open').find('li.open').trigger('close.app.menu');
  461. $listItem.siblings('.open').trigger('close.app.menu');
  462. }
  463. e.stopPropagation();
  464. }).on('close.app.menu', 'li.open', function(e) {
  465. var $listItem = $(this);
  466. $listItem.removeClass('open');
  467. menuObj.collapse($listItem);
  468. e.stopPropagation();
  469. }).on('click.app.menu', 'li', function(e) {
  470. var $listItem = $(this);
  471. if($listItem.is('.disabled')){
  472. e.preventDefault();
  473. }
  474. else{
  475. if( $body.hasClass('menu-collapsed') || ($body.data('menu') == 'vertical-compact-menu' && $listItem.is('.has-sub') && !$body.hasClass('vertical-overlay-menu')) ){
  476. e.preventDefault();
  477. }
  478. else{
  479. if ($listItem.has('ul')) {
  480. if ($listItem.is('.open')) {
  481. $listItem.trigger('close.app.menu');
  482. } else {
  483. $listItem.trigger('open.app.menu');
  484. }
  485. } else {
  486. if (!$listItem.is('.active')) {
  487. $listItem.siblings('.active').trigger('deactive.app.menu');
  488. $listItem.trigger('active.app.menu');
  489. }
  490. }
  491. }
  492. }
  493. e.stopPropagation();
  494. });
  495. $('.main-menu-content').on('mouseleave', function(){
  496. if( $body.hasClass('menu-collapsed') || $body.data('menu') == 'vertical-compact-menu' ){
  497. $('.main-menu-content').children('span.menu-title').remove();
  498. $('.main-menu-content').children('a.menu-title').remove();
  499. $('.main-menu-content').children('ul.menu-content').remove();
  500. }
  501. $('.hover', '.navigation-main').removeClass('hover');
  502. });
  503. // If list item has sub menu items then prevent redirection.
  504. $('.navigation-main li.has-sub > a').on('click',function(e){
  505. e.preventDefault();
  506. });
  507. $('ul.menu-content').on('click', 'li', function(e) {
  508. var $listItem = $(this);
  509. if($listItem.is('.disabled')){
  510. e.preventDefault();
  511. }
  512. else{
  513. if ($listItem.has('ul')) {
  514. if ($listItem.is('.open')) {
  515. $listItem.removeClass('open');
  516. menuObj.collapse($listItem);
  517. } else {
  518. $listItem.addClass('open');
  519. menuObj.expand($listItem);
  520. // If menu collapsible then do not take any action
  521. if ($('.main-menu').hasClass('menu-collapsible')) {
  522. return false;
  523. }
  524. // If menu accordion then close all except clicked once
  525. else{
  526. $listItem.siblings('.open').find('li.open').trigger('close.app.menu');
  527. $listItem.siblings('.open').trigger('close.app.menu');
  528. }
  529. e.stopPropagation();
  530. }
  531. } else {
  532. if (!$listItem.is('.active')) {
  533. $listItem.siblings('.active').trigger('deactive.app.menu');
  534. $listItem.trigger('active.app.menu');
  535. }
  536. }
  537. }
  538. e.stopPropagation();
  539. });
  540. },
  541. /**
  542. * Ensure an admin submenu is within the visual viewport.
  543. * @param {jQuery} $menuItem The parent menu item containing the submenu.
  544. */
  545. adjustSubmenu: function ( $menuItem ) {
  546. var menuHeaderHeight, menutop, topPos, winHeight,
  547. bottomOffset, subMenuHeight, popOutMenuHeight, borderWidth, scroll_theme,
  548. $submenu = $menuItem.children('ul:first'),
  549. ul = $submenu.clone(true);
  550. menuHeaderHeight = $('.main-menu-header').height();
  551. menutop = $menuItem.position().top;
  552. winHeight = $window.height() - $('.header-navbar').height();
  553. borderWidth = 0;
  554. subMenuHeight = $submenu.height();
  555. if(parseInt($menuItem.css( "border-top" ),10) > 0){
  556. borderWidth = parseInt($menuItem.css( "border-top" ),10);
  557. }
  558. popOutMenuHeight = winHeight - menutop - $menuItem.height() - 30;
  559. scroll_theme = ($('.main-menu').hasClass('menu-dark')) ? 'light' : 'dark';
  560. if($body.data('menu') === 'vertical-compact-menu'){
  561. topPos = menutop + borderWidth;
  562. popOutMenuHeight = winHeight - menutop - 30;
  563. }
  564. else if($body.data('menu') === 'vertical-content-menu'){
  565. topPos = menutop + $menuItem.height() + borderWidth;
  566. popOutMenuHeight = winHeight - $('.content-header').height() -$menuItem.height() - menutop - 60;
  567. }
  568. else{
  569. topPos = menutop + $menuItem.height() + borderWidth;
  570. }
  571. if($body.data('menu') == 'vertical-content-menu'){
  572. ul.addClass('menu-popout').appendTo('.main-menu-content').css({
  573. 'top' : topPos,
  574. 'position' : 'fixed',
  575. });
  576. }
  577. else{
  578. ul.addClass('menu-popout').appendTo('.main-menu-content').css({
  579. 'top' : topPos,
  580. 'position' : 'fixed',
  581. 'max-height': popOutMenuHeight,
  582. });
  583. $('.main-menu-content > ul.menu-content').perfectScrollbar({
  584. theme:scroll_theme,
  585. });
  586. }
  587. },
  588. collapse: function($listItem, callback) {
  589. var $subList = $listItem.children('ul');
  590. $subList.show().slideUp($.app.nav.config.speed, function() {
  591. $(this).css('display', '');
  592. $(this).find('> li').removeClass('is-shown');
  593. if (callback) {
  594. callback();
  595. }
  596. $.app.nav.container.trigger('collapsed.app.menu');
  597. });
  598. },
  599. expand: function($listItem, callback) {
  600. var $subList = $listItem.children('ul');
  601. var $children = $subList.children('li').addClass('is-hidden');
  602. $subList.hide().slideDown($.app.nav.config.speed, function() {
  603. $(this).css('display', '');
  604. if (callback) {
  605. callback();
  606. }
  607. $.app.nav.container.trigger('expanded.app.menu');
  608. });
  609. setTimeout(function() {
  610. $children.addClass('is-shown');
  611. $children.removeClass('is-hidden');
  612. }, 0);
  613. },
  614. refresh: function() {
  615. $.app.nav.container.find('.open').removeClass('open');
  616. },
  617. };
  618. })(window, document, jQuery);