sidebar.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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) {
  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. sidebar.css('display', 'block').animate({
  70. opacity: 1
  71. }, 200, () => { this.isOpen = true; });
  72. if (scrollbar) { scrollbar.update(); }
  73. }
  74. close(event) {
  75. if (event) { event.preventDefault(); }
  76. let overlay = $('#overlay');
  77. let sidebar = $('#admin-sidebar');
  78. let scrollbar = $('#admin-menu').data('scrollbar');
  79. this.body.removeClass('sidebar-mobile-open');
  80. overlay.css('display', 'none');
  81. sidebar.animate({
  82. opacity: 0
  83. }, 200, () => {
  84. sidebar.css('display', 'none');
  85. this.isOpen = false;
  86. });
  87. if (scrollbar) { scrollbar.update(); }
  88. }
  89. toggle(event) {
  90. if (event) { event.preventDefault(); }
  91. return this[this.isOpen ? 'close' : 'open'](event);
  92. }
  93. toggleSidebarState(event) {
  94. if (event) { event.preventDefault(); }
  95. clearTimeout(this.timeout);
  96. let isDesktop = global.matchMedia(DESKTOP_QUERY).matches;
  97. if (isDesktop) {
  98. this.body.removeClass('sidebar-open');
  99. }
  100. if (!isDesktop) {
  101. this.body.removeClass('sidebar-closed');
  102. this.body.removeClass('sidebar-mobile-open');
  103. }
  104. this.body.toggleClass(`sidebar-${isDesktop ? 'closed' : 'open'}`);
  105. $(global).trigger('sidebar_state._grav', isDesktop);
  106. }
  107. checkMatch(data) {
  108. let sidebar = $('#admin-sidebar');
  109. let overlay = $('#overlay');
  110. this.isOpen = false;
  111. overlay.css('display', 'none');
  112. sidebar.css({
  113. display: data.matches ? 'none' : 'inherit',
  114. opacity: data.matches ? 0 : 1
  115. });
  116. if (data.matches) {
  117. this.body.removeClass('sidebar-open sidebar-closed');
  118. }
  119. this[data.matches ? 'attach' : 'detach']();
  120. }
  121. _getBound(fn) {
  122. if (map.has(fn)) {
  123. return map.get(fn);
  124. }
  125. return map.set(fn, this[fn].bind(this)).get(fn);
  126. }
  127. }
  128. export let Instance = new Sidebar();