sidebar.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import $ from 'jquery';
  2. import Scrollbar from './scrollbar';
  3. import Map from 'es6-map';
  4. const MOBILE_BREAKPOINT = 48 - 0.062;
  5. const DESKTOP_BREAKPOINT = 75 + 0.063;
  6. const EVENTS = 'touchstart._grav click._grav';
  7. const TARGETS = '[data-sidebar-mobile-toggle], #overlay';
  8. const MOBILE_QUERY = `(max-width: ${MOBILE_BREAKPOINT}em)`;
  9. const DESKTOP_QUERY = `(min-width: ${DESKTOP_BREAKPOINT}em)`;
  10. let map = new Map();
  11. export default class Sidebar {
  12. constructor() {
  13. this.timeout = null;
  14. this.isOpen = false;
  15. this.body = $('body');
  16. this.matchMedia = global.matchMedia(MOBILE_QUERY);
  17. this.scroller = new Scrollbar('.admin-menu-wrapper', { autoshow: true });
  18. this.enable();
  19. }
  20. enable() {
  21. const sidebar = $('#admin-sidebar');
  22. this.matchMedia.addListener(this._getBound('checkMatch'));
  23. this.checkMatch(this.matchMedia);
  24. this.body.on(EVENTS, '[data-sidebar-toggle]', this._getBound('toggleSidebarState'));
  25. if (sidebar.data('quickopen')) {
  26. sidebar.hover(this._getBound('quickOpenIn'), this._getBound('quickOpenOut'));
  27. }
  28. }
  29. disable() {
  30. const sidebar = $('#admin-sidebar');
  31. this.close();
  32. this.matchMedia.removeListener(this._getBound('checkMatch'));
  33. this.body.off(EVENTS, '[data-sidebar-toggle]', this._getBound('toggleSidebarState'));
  34. if (sidebar.data('quickopen')) {
  35. sidebar.off('mouseenter mouseleave');
  36. }
  37. }
  38. attach() {
  39. this.body.on(EVENTS, TARGETS, this._getBound('toggle'));
  40. }
  41. detach() {
  42. this.body.off(EVENTS, TARGETS, this._getBound('toggle'));
  43. }
  44. quickOpenIn(/* event */) {
  45. let isDesktop = global.matchMedia(DESKTOP_QUERY).matches;
  46. let delay = $('#admin-sidebar').data('quickopen-delay') || 500;
  47. if (this.body.hasClass('sidebar-mobile-open')) { return; }
  48. let shouldQuickOpen = isDesktop ? this.body.hasClass('sidebar-closed') : !this.body.hasClass('sidebar-open');
  49. if (!shouldQuickOpen && !this.body.hasClass('sidebar-quickopen')) { return this.quickOpenOut(); }
  50. this.timeout = setTimeout(() => {
  51. this.body.addClass('sidebar-open sidebar-quickopen');
  52. $(global).trigger('sidebar_state._grav', isDesktop);
  53. }, delay);
  54. }
  55. quickOpenOut(/* event */) {
  56. clearTimeout(this.timeout);
  57. if (this.body.hasClass('sidebar-quickopen')) {
  58. this.body.removeClass('sidebar-open sidebar-quickopen');
  59. }
  60. return true;
  61. }
  62. open(event, quick = false) {
  63. if (event) { event.preventDefault(); }
  64. let overlay = $('#overlay');
  65. let sidebar = $('#admin-sidebar');
  66. let scrollbar = $('#admin-menu').data('scrollbar');
  67. this.body.addClass('sidebar-mobile-open');
  68. overlay.css('display', 'block');
  69. if (!quick) {
  70. sidebar.css('display', 'block').animate({
  71. opacity: 1
  72. }, 200, () => {
  73. this.isOpen = true;
  74. });
  75. } else {
  76. sidebar.css({ display: 'block', opacity: 1 });
  77. this.isOpen = true;
  78. }
  79. if (scrollbar) { scrollbar.update(); }
  80. }
  81. close(event, quick = false) {
  82. if (event) { event.preventDefault(); }
  83. let overlay = $('#overlay');
  84. let sidebar = $('#admin-sidebar');
  85. let scrollbar = $('#admin-menu').data('scrollbar');
  86. this.body.removeClass('sidebar-mobile-open');
  87. overlay.css('display', 'none');
  88. if (!quick) {
  89. sidebar.animate({
  90. opacity: 0
  91. }, 200, () => {
  92. sidebar.css('display', 'none');
  93. this.isOpen = false;
  94. });
  95. } else {
  96. sidebar.css({ opacity: 0, display: 'none' });
  97. this.isOpen = false;
  98. }
  99. if (scrollbar) { scrollbar.update(); }
  100. }
  101. toggle(event) {
  102. if (event) { event.preventDefault(); }
  103. return this[this.isOpen ? 'close' : 'open'](event);
  104. }
  105. toggleSidebarState(event) {
  106. if (event) { event.preventDefault(); }
  107. clearTimeout(this.timeout);
  108. let isDesktop = global.matchMedia(DESKTOP_QUERY).matches;
  109. if (isDesktop) {
  110. this.body.removeClass('sidebar-open');
  111. }
  112. if (!isDesktop) {
  113. this.body.removeClass('sidebar-closed');
  114. this.body.removeClass('sidebar-mobile-open');
  115. }
  116. this.body.toggleClass(`sidebar-${isDesktop ? 'closed' : 'open'}`);
  117. $(global).trigger('sidebar_state._grav', isDesktop);
  118. }
  119. checkMatch(data) {
  120. let sidebar = $('#admin-sidebar');
  121. let overlay = $('#overlay');
  122. this.isOpen = false;
  123. overlay.css('display', 'none');
  124. sidebar.css({
  125. display: data.matches ? 'none' : 'inherit',
  126. opacity: data.matches ? 0 : 1
  127. });
  128. if (data.matches) {
  129. this.body.removeClass('sidebar-open sidebar-closed');
  130. }
  131. this[data.matches ? 'attach' : 'detach']();
  132. }
  133. _resetMap() {
  134. return map.clear();
  135. }
  136. _getBound(fn) {
  137. if (map.has(fn)) {
  138. return map.get(fn);
  139. }
  140. return map.set(fn, this[fn].bind(this)).get(fn);
  141. }
  142. }
  143. export let Instance = new Sidebar();