PageContainer.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import { Container } from 'unstated';
  2. import loggerFactory from '@alias/logger';
  3. import * as entities from 'entities';
  4. const logger = loggerFactory('growi:services:PageContainer');
  5. /**
  6. * Service container related to Page
  7. * @extends {Container} unstated Container
  8. */
  9. export default class PageContainer extends Container {
  10. constructor(appContainer) {
  11. super();
  12. this.appContainer = appContainer;
  13. this.appContainer.registerContainer(this);
  14. const mainContent = document.querySelector('#content-main');
  15. if (mainContent == null) {
  16. logger.debug('#content-main element is not exists');
  17. return;
  18. }
  19. const revisionId = mainContent.getAttribute('data-page-revision-id');
  20. this.state = {
  21. // local page data
  22. markdown: null, // will be initialized after initStateMarkdown()
  23. pageId: mainContent.getAttribute('data-page-id'),
  24. revisionId,
  25. revisionCreatedAt: +mainContent.getAttribute('data-page-revision-created'),
  26. path: mainContent.getAttribute('data-path'),
  27. templateTagData: mainContent.getAttribute('data-template-tags') || '',
  28. isSlackEnabled: false,
  29. slackChannels: mainContent.getAttribute('data-slack-channels') || '',
  30. grant: 1, // default: public
  31. grantGroupId: null,
  32. grantGroupName: null,
  33. // latest(on remote) information
  34. remoteRevisionId: revisionId,
  35. revisionIdHackmdSynced: mainContent.getAttribute('data-page-revision-id-hackmd-synced'),
  36. lastUpdateUsername: undefined,
  37. pageIdOnHackmd: mainContent.getAttribute('data-page-id-on-hackmd'),
  38. hasDraftOnHackmd: !!mainContent.getAttribute('data-page-has-draft-on-hackmd'),
  39. isHackmdDraftUpdatingInRealtime: false,
  40. };
  41. this.initStateMarkdown();
  42. this.initStateGrant();
  43. this.initDraft();
  44. this.addWebSocketEventHandlers = this.addWebSocketEventHandlers.bind(this);
  45. this.addWebSocketEventHandlers();
  46. }
  47. initStateMarkdown() {
  48. let pageContent = '';
  49. const rawText = document.getElementById('raw-text-original');
  50. if (rawText) {
  51. pageContent = rawText.innerHTML;
  52. }
  53. const markdown = entities.decodeHTML(pageContent);
  54. this.state.markdown = markdown;
  55. }
  56. initStateGrant() {
  57. const elem = document.getElementById('save-page-controls');
  58. if (elem) {
  59. this.state.grant = +elem.dataset.grant;
  60. const grantGroupId = elem.dataset.grantGroup;
  61. if (grantGroupId != null && grantGroupId.length > 0) {
  62. this.state.grantGroupId = grantGroupId;
  63. this.state.grantGroupName = elem.dataset.grantGroupName;
  64. }
  65. }
  66. }
  67. initDraft() {
  68. if (this.state.pageId == null) {
  69. const draft = this.appContainer.findDraft(this.state.path);
  70. if (draft != null) {
  71. this.state.markdown = draft;
  72. }
  73. }
  74. }
  75. getCurrentOptionsToSave() {
  76. const opt = {
  77. isSlackEnabled: this.state.isSlackEnabled,
  78. slackChannels: this.state.slackChannels,
  79. grant: this.state.grant,
  80. };
  81. if (this.state.grantGroupId != null) {
  82. opt.grantUserGroupId = this.state.grantGroupId;
  83. }
  84. return opt;
  85. }
  86. setLatestRemotePageData(page, user) {
  87. this.setState({
  88. remoteRevisionId: page.revision._id,
  89. revisionIdHackmdSynced: page.revisionHackmdSynced,
  90. lastUpdateUsername: user.name,
  91. });
  92. }
  93. addWebSocketEventHandlers() {
  94. const pageContainer = this;
  95. const websocketContainer = this.appContainer.getContainer('WebsocketContainer');
  96. const socket = websocketContainer.getWebSocket();
  97. socket.on('page:create', (data) => {
  98. // skip if triggered myself
  99. if (data.socketClientId != null && data.socketClientId === websocketContainer.getCocketClientId()) {
  100. return;
  101. }
  102. logger.debug({ obj: data }, `websocket on 'page:create'`); // eslint-disable-line quotes
  103. // update PageStatusAlert
  104. if (data.page.path === pageContainer.state.path) {
  105. this.setLatestRemotePageData(data.page, data.user);
  106. }
  107. });
  108. socket.on('page:update', (data) => {
  109. // skip if triggered myself
  110. if (data.socketClientId != null && data.socketClientId === websocketContainer.getCocketClientId()) {
  111. return;
  112. }
  113. logger.debug({ obj: data }, `websocket on 'page:update'`); // eslint-disable-line quotes
  114. if (data.page.path === pageContainer.state.path) {
  115. // update PageStatusAlert
  116. pageContainer.setLatestRemotePageData(data.page, data.user);
  117. // update remote data
  118. const page = data.page;
  119. pageContainer.setState({
  120. remoteRevisionId: page.revision._id,
  121. revisionIdHackmdSynced: page.revisionHackmdSynced,
  122. hasDraftOnHackmd: page.hasDraftOnHackmd,
  123. });
  124. }
  125. });
  126. socket.on('page:delete', (data) => {
  127. // skip if triggered myself
  128. if (data.socketClientId != null && data.socketClientId === websocketContainer.getCocketClientId()) {
  129. return;
  130. }
  131. logger.debug({ obj: data }, `websocket on 'page:delete'`); // eslint-disable-line quotes
  132. // update PageStatusAlert
  133. if (data.page.path === pageContainer.state.path) {
  134. pageContainer.setLatestRemotePageData(data.page, data.user);
  135. }
  136. });
  137. socket.on('page:editingWithHackmd', (data) => {
  138. // skip if triggered myself
  139. if (data.socketClientId != null && data.socketClientId === websocketContainer.getCocketClientId()) {
  140. return;
  141. }
  142. logger.debug({ obj: data }, `websocket on 'page:editingWithHackmd'`); // eslint-disable-line quotes
  143. if (data.page.path === pageContainer.state.path) {
  144. pageContainer.setState({ isHackmdDraftUpdatingInRealtime: true });
  145. }
  146. });
  147. }
  148. }