NavigationContainer.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import { Container } from 'unstated';
  2. import loggerFactory from '~/utils/logger';
  3. const logger = loggerFactory('growi:services:NavigationContainer');
  4. /**
  5. * Service container related to options for Application
  6. * @extends {Container} unstated Container
  7. */
  8. const SCROLL_THRES_SKIP = 200;
  9. const WIKI_HEADER_LINK = 120;
  10. export default class NavigationContainer extends Container {
  11. constructor(appContainer) {
  12. super();
  13. this.appContainer = appContainer;
  14. this.appContainer.registerContainer(this);
  15. const { localStorage } = window;
  16. this.state = {
  17. // editorMode: 'view',
  18. isScrollTop: true,
  19. };
  20. // this.setEditorMode = this.setEditorMode.bind(this);
  21. this.initScrollEvent();
  22. }
  23. /**
  24. * Workaround for the mangling in production build to break constructor.name
  25. */
  26. static getClassName() {
  27. return 'NavigationContainer';
  28. }
  29. getPageContainer() {
  30. return this.appContainer.getContainer('PageContainer');
  31. }
  32. initScrollEvent() {
  33. window.addEventListener('scroll', () => {
  34. const currentYOffset = window.pageYOffset;
  35. // original throttling
  36. if (SCROLL_THRES_SKIP < currentYOffset) {
  37. return;
  38. }
  39. this.setState({
  40. isScrollTop: currentYOffset === 0,
  41. });
  42. });
  43. }
  44. // setEditorMode(editorMode) {
  45. // const { isNotCreatable } = this.getPageContainer().state;
  46. // if (this.appContainer.currentUser == null) {
  47. // logger.warn('Please login or signup to edit the page or use hackmd.');
  48. // return;
  49. // }
  50. // if (isNotCreatable) {
  51. // logger.warn('This page could not edit.');
  52. // return;
  53. // }
  54. // this.setState({ editorMode });
  55. // if (editorMode === 'view') {
  56. // $('body').removeClass('on-edit');
  57. // $('body').removeClass('builtin-editor');
  58. // $('body').removeClass('hackmd');
  59. // $('body').removeClass('pathname-sidebar');
  60. // window.history.replaceState(null, '', window.location.pathname);
  61. // }
  62. // if (editorMode === 'edit') {
  63. // $('body').addClass('on-edit');
  64. // $('body').addClass('builtin-editor');
  65. // $('body').removeClass('hackmd');
  66. // // editing /Sidebar
  67. // if (window.location.pathname === '/Sidebar') {
  68. // $('body').addClass('pathname-sidebar');
  69. // }
  70. // window.location.hash = '#edit';
  71. // }
  72. // if (editorMode === 'hackmd') {
  73. // $('body').addClass('on-edit');
  74. // $('body').addClass('hackmd');
  75. // $('body').removeClass('builtin-editor');
  76. // $('body').removeClass('pathname-sidebar');
  77. // window.location.hash = '#hackmd';
  78. // }
  79. // this.updateDrawerMode({ ...this.state, editorMode }); // generate newest state object
  80. // }
  81. /**
  82. * Update drawer related state by specified 'newState' object
  83. * @param {object} newState A newest state object
  84. *
  85. * Specify 'newState' like following code:
  86. *
  87. * { ...this.state, overwriteParam: overwriteValue }
  88. *
  89. * because updating state of unstated container will be delayed unless you use await
  90. */
  91. // updateDrawerMode(newState) {
  92. // const {
  93. // editorMode, isDeviceSmallerThanMd, preferDrawerModeByUser, preferDrawerModeOnEditByUser,
  94. // } = newState;
  95. // // get preference on view or edit
  96. // const preferDrawerMode = editorMode !== 'view' ? preferDrawerModeOnEditByUser : preferDrawerModeByUser;
  97. // const isDrawerMode = isDeviceSmallerThanMd || preferDrawerMode;
  98. // const isDrawerOpened = false; // close Drawer anyway
  99. // this.setState({ isDrawerMode, isDrawerOpened });
  100. // }
  101. /**
  102. * Function that implements the click event for realizing smooth scroll
  103. * @param {array} elements
  104. */
  105. addSmoothScrollEvent(elements = {}) {
  106. elements.forEach(link => link.addEventListener('click', (e) => {
  107. e.preventDefault();
  108. const href = link.getAttribute('href').replace('#', '');
  109. window.location.hash = href;
  110. const targetDom = document.getElementById(href);
  111. this.smoothScrollIntoView(targetDom, WIKI_HEADER_LINK);
  112. }));
  113. }
  114. smoothScrollIntoView(element = null, offsetTop = 0) {
  115. const targetElement = element || window.document.body;
  116. // get the distance to the target element top
  117. const rectTop = targetElement.getBoundingClientRect().top;
  118. const top = window.pageYOffset + rectTop - offsetTop;
  119. window.scrollTo({
  120. top,
  121. behavior: 'smooth',
  122. });
  123. }
  124. }