sidebar.component.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import { Component, OnInit, Injector, OnDestroy } from '@angular/core';
  2. import { Router } from '@angular/router';
  3. declare var $: any;
  4. import { MenuService } from '../../core/menu/menu.service';
  5. import { SettingsService } from '../../core/settings/settings.service';
  6. @Component({
  7. selector: 'app-sidebar',
  8. templateUrl: './sidebar.component.html',
  9. styleUrls: ['./sidebar.component.scss']
  10. })
  11. export class SidebarComponent implements OnInit, OnDestroy {
  12. menuItems: Array<any>;
  13. router: Router;
  14. sbclickEvent = 'click.sidebar-toggle';
  15. $doc: any = null;
  16. constructor(public menu: MenuService, public settings: SettingsService, public injector: Injector) {
  17. this.menuItems = menu.getMenu();
  18. }
  19. ngOnInit() {
  20. this.router = this.injector.get(Router);
  21. this.router.events.subscribe((val) => {
  22. // close any submenu opened when route changes
  23. this.removeFloatingNav();
  24. // scroll view to top
  25. window.scrollTo(0, 0);
  26. // close sidebar on route change
  27. this.settings.setLayoutSetting('asideToggled', false);
  28. });
  29. // enable sidebar autoclose from extenal clicks
  30. this.anyClickClose();
  31. }
  32. anyClickClose() {
  33. this.$doc = $(document).on(this.sbclickEvent, (e) => {
  34. if (!$(e.target).parents('.aside-container').length) {
  35. this.settings.setLayoutSetting('asideToggled', false);
  36. }
  37. });
  38. }
  39. ngOnDestroy() {
  40. if (this.$doc)
  41. this.$doc.off(this.sbclickEvent);
  42. }
  43. toggleSubmenuClick(event) {
  44. event.preventDefault();
  45. if (!this.isSidebarCollapsed() && !this.isSidebarCollapsedText() && !this.isEnabledHover()) {
  46. let ul = $(event.currentTarget.nextElementSibling);
  47. // hide other submenus
  48. let parentNav = ul.parents('.sidebar-subnav');
  49. $('.sidebar-subnav').each((idx, el) => {
  50. let $el = $(el);
  51. // if element is not a parent or self ul
  52. if (el !== parentNav[0] && el !== ul[0]) {
  53. this.closeMenu($el);
  54. }
  55. });
  56. // abort if not UL to process
  57. if (!ul.length) {
  58. return;
  59. }
  60. // any child menu should start closed
  61. ul.find('.sidebar-subnav').each((idx, el) => {
  62. this.closeMenu($(el));
  63. });
  64. // toggle UL height
  65. const ulHeight = ul.css('height')
  66. if (ulHeight === 'auto' || parseInt(ulHeight, 10)) {
  67. this.closeMenu(ul);
  68. }
  69. else {
  70. // expand menu
  71. ul.on('transitionend', () => {
  72. ul.css('height', 'auto').off('transitionend');
  73. }).css('height', ul[0].scrollHeight);
  74. // add class to manage animation
  75. ul.addClass('opening');
  76. }
  77. }
  78. }
  79. // Close menu collapsing height
  80. closeMenu(elem) {
  81. elem.css('height', elem[0].scrollHeight); // set height
  82. elem.css('height', 0); // and move to zero to collapse
  83. elem.removeClass('opening');
  84. }
  85. toggleSubmenuHover(event) {
  86. let self = this;
  87. if (this.isSidebarCollapsed() || this.isSidebarCollapsedText() || this.isEnabledHover()) {
  88. event.preventDefault();
  89. this.removeFloatingNav();
  90. let ul = $(event.currentTarget.nextElementSibling);
  91. let anchor = $(event.currentTarget);
  92. if (!ul.length) {
  93. return; // if not submenu return
  94. }
  95. let $aside = $('.aside-container');
  96. let $asideInner = $aside.children('.aside-inner'); // for top offset calculation
  97. let $sidebar = $asideInner.children('.sidebar');
  98. let mar = parseInt($asideInner.css('padding-top'), 0) + parseInt($aside.css('padding-top'), 0);
  99. let itemTop = ((anchor.parent().position().top) + mar) - $sidebar.scrollTop();
  100. let floatingNav = ul.clone().appendTo($aside);
  101. let vwHeight = document.body.clientHeight;
  102. // let itemTop = anchor.position().top || anchor.offset().top;
  103. floatingNav
  104. .addClass('nav-floating')
  105. // each item has ~40px height
  106. // multiply to force space for at least N items
  107. var safeOffsetValue = (40 * 5)
  108. var navHeight = floatingNav.outerHeight(true) + 2; // 2px border
  109. var safeOffset = navHeight < safeOffsetValue ? navHeight : safeOffsetValue;
  110. var displacement = 25; // displacement in px from bottom
  111. // if not enough space to show N items, use then calculated 'safeOffset'
  112. var menuTop = (vwHeight - itemTop > safeOffset) ? itemTop : (vwHeight - safeOffset - displacement);
  113. floatingNav
  114. .removeClass('opening') // necesary for demo if switched between normal//collapsed mode
  115. .css({
  116. position: this.settings.getLayoutSetting('isFixed') ? 'fixed' : 'absolute',
  117. top: menuTop,
  118. bottom: (floatingNav.outerHeight(true) + menuTop > vwHeight) ? (displacement+'px') : 'auto'
  119. });
  120. floatingNav
  121. .on('mouseleave', () => { floatingNav.remove(); })
  122. .find('a').on('click', function(e) {
  123. e.preventDefault(); // prevents page reload on click
  124. // get the exact route path to navigate
  125. let routeTo = $(this).attr('route');
  126. if (routeTo) self.router.navigate([routeTo]);
  127. });
  128. this.listenForExternalClicks();
  129. }
  130. }
  131. listenForExternalClicks() {
  132. let $doc = $(document).on('click.sidebar', (e) => {
  133. if (!$(e.target).parents('.aside-container').length) {
  134. this.removeFloatingNav();
  135. $doc.off('click.sidebar');
  136. }
  137. });
  138. }
  139. removeFloatingNav() {
  140. $('.nav-floating').remove();
  141. }
  142. isSidebarCollapsed() {
  143. return this.settings.getLayoutSetting('isCollapsed');
  144. }
  145. isSidebarCollapsedText() {
  146. return this.settings.getLayoutSetting('isCollapsedText');
  147. }
  148. isEnabledHover() {
  149. return this.settings.getLayoutSetting('asideHover');
  150. }
  151. }