AppContainer.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import { Container } from 'unstated';
  2. import InterceptorManager from '~/services/interceptor-manager';
  3. import GrowiRenderer from '../util/GrowiRenderer';
  4. import emojiStrategy from '../util/emojione/emoji_strategy_shrinked.json';
  5. import { i18nFactory } from '../util/i18n';
  6. /**
  7. * Service container related to options for Application
  8. * @extends {Container} unstated Container
  9. */
  10. export default class AppContainer extends Container {
  11. constructor() {
  12. super();
  13. // get csrf token from body element
  14. // DO NOT REMOVE: uploading attachment data requires appContainer.csrfToken
  15. const body = document.querySelector('body');
  16. this.csrfToken = body.dataset.csrftoken;
  17. this.config = JSON.parse(document.getElementById('growi-context-hydrate').textContent || '{}');
  18. const currentUserElem = document.getElementById('growi-current-user');
  19. if (currentUserElem != null) {
  20. this.currentUser = JSON.parse(currentUserElem.textContent);
  21. }
  22. const isSharedPageElem = document.getElementById('is-shared-page');
  23. // check what kind of user
  24. this.isGuestUser = this.currentUser == null;
  25. this.isSharedUser = isSharedPageElem != null && this.currentUser == null;
  26. const userLocaleId = this.currentUser?.lang;
  27. this.i18n = i18nFactory(userLocaleId);
  28. this.containerInstances = {};
  29. this.componentInstances = {};
  30. this.rendererInstances = {};
  31. }
  32. /**
  33. * Workaround for the mangling in production build to break constructor.name
  34. */
  35. static getClassName() {
  36. return 'AppContainer';
  37. }
  38. initApp() {
  39. this.injectToWindow();
  40. }
  41. initContents() {
  42. const body = document.querySelector('body');
  43. this.isAdmin = body.dataset.isAdmin === 'true';
  44. this.isDocSaved = true;
  45. this.originRenderer = new GrowiRenderer(this);
  46. this.interceptorManager = new InterceptorManager();
  47. const isPluginEnabled = body.dataset.pluginEnabled === 'true';
  48. if (isPluginEnabled) {
  49. this.initPlugins();
  50. }
  51. this.injectToWindow();
  52. }
  53. initPlugins() {
  54. const growiPlugin = window.growiPlugin;
  55. growiPlugin.installAll(this, this.originRenderer);
  56. }
  57. injectToWindow() {
  58. window.appContainer = this;
  59. const originRenderer = this.getOriginRenderer();
  60. window.growiRenderer = originRenderer;
  61. // backward compatibility
  62. window.crowi = this;
  63. window.crowiRenderer = originRenderer;
  64. window.crowiPlugin = window.growiPlugin;
  65. }
  66. get currentUserId() {
  67. if (this.currentUser == null) {
  68. return null;
  69. }
  70. return this.currentUser._id;
  71. }
  72. get currentUsername() {
  73. if (this.currentUser == null) {
  74. return null;
  75. }
  76. return this.currentUser.username;
  77. }
  78. /**
  79. * @return {Object} window.Crowi (js/legacy/crowi.js)
  80. */
  81. getCrowiForJquery() {
  82. return window.Crowi;
  83. }
  84. getConfig() {
  85. return this.config;
  86. }
  87. /**
  88. * Register unstated container instance
  89. * @param {object} instance unstated container instance
  90. */
  91. registerContainer(instance) {
  92. if (instance == null) {
  93. throw new Error('The specified instance must not be null');
  94. }
  95. const className = instance.constructor.getClassName();
  96. if (this.containerInstances[className] != null) {
  97. throw new Error('The specified instance couldn\'t register because the same type object has already been registered');
  98. }
  99. this.containerInstances[className] = instance;
  100. }
  101. /**
  102. * Get registered unstated container instance
  103. * !! THIS METHOD SHOULD ONLY BE USED FROM unstated CONTAINERS !!
  104. * !! From component instances, inject containers with `import { Subscribe } from 'unstated'` !!
  105. *
  106. * @param {string} className
  107. */
  108. getContainer(className) {
  109. return this.containerInstances[className];
  110. }
  111. /**
  112. * Register React component instance
  113. * @param {string} id
  114. * @param {object} instance React component instance
  115. */
  116. registerComponentInstance(id, instance) {
  117. if (instance == null) {
  118. throw new Error('The specified instance must not be null');
  119. }
  120. if (this.componentInstances[id] != null) {
  121. throw new Error('The specified instance couldn\'t register because the same id has already been registered');
  122. }
  123. this.componentInstances[id] = instance;
  124. }
  125. /**
  126. * Get registered React component instance
  127. * @param {string} id
  128. */
  129. getComponentInstance(id) {
  130. return this.componentInstances[id];
  131. }
  132. getOriginRenderer() {
  133. return this.originRenderer;
  134. }
  135. /**
  136. * factory method
  137. */
  138. getRenderer(mode) {
  139. if (this.rendererInstances[mode] != null) {
  140. return this.rendererInstances[mode];
  141. }
  142. const renderer = new GrowiRenderer(this, this.originRenderer);
  143. // setup
  144. renderer.initMarkdownItConfigurers(mode);
  145. renderer.setup(mode);
  146. // register
  147. this.rendererInstances[mode] = renderer;
  148. return renderer;
  149. }
  150. getEmojiStrategy() {
  151. return emojiStrategy;
  152. }
  153. launchHandsontableModal(componentKind, beginLineNumber, endLineNumber) {
  154. let targetComponent;
  155. switch (componentKind) {
  156. case 'page':
  157. targetComponent = this.getComponentInstance('Page');
  158. break;
  159. }
  160. targetComponent.launchHandsontableModal(beginLineNumber, endLineNumber);
  161. }
  162. launchDrawioModal(componentKind, beginLineNumber, endLineNumber) {
  163. let targetComponent;
  164. switch (componentKind) {
  165. case 'page':
  166. targetComponent = this.getComponentInstance('Page');
  167. break;
  168. }
  169. targetComponent.launchDrawioModal(beginLineNumber, endLineNumber);
  170. }
  171. }