Przeglądaj źródła

WIP: apply unstated to PageEditorByHackmd and PageStatusAlert

Yuki Takei 6 lat temu
rodzic
commit
e3152cb88f

+ 41 - 34
src/client/js/app.js

@@ -95,7 +95,11 @@ if (mainContent !== null) {
 }
 }
 const isLoggedin = document.querySelector('.main-container.nologin') == null;
 const isLoggedin = document.querySelector('.main-container.nologin') == null;
 
 
+// create unstated container instance
 const appContainer = new AppContainer();
 const appContainer = new AppContainer();
+const pageContainer = new PageContainer(appContainer);
+const commentContainer = new CommentContainer(appContainer);
+const editorContainer = new EditorContainer(appContainer, defaultEditorOptions, defaultPreviewOptions);
 window.appContainer = appContainer;
 window.appContainer = appContainer;
 
 
 // backward compatibility
 // backward compatibility
@@ -116,11 +120,6 @@ const crowiRenderer = new GrowiRenderer(crowi, null, {
 });
 });
 window.crowiRenderer = crowiRenderer;
 window.crowiRenderer = crowiRenderer;
 
 
-// create unstated container instance
-const pageContainer = new PageContainer(appContainer);
-const commentContainer = new CommentContainer(appContainer);
-const editorContainer = new EditorContainer(appContainer, defaultEditorOptions, defaultPreviewOptions);
-
 // FIXME
 // FIXME
 const isEnabledPlugins = $('body').data('plugin-enabled');
 const isEnabledPlugins = $('body').data('plugin-enabled');
 if (isEnabledPlugins) {
 if (isEnabledPlugins) {
@@ -169,24 +168,26 @@ const saveWithShortcutSuccessHandler = function(page) {
   pageContainer.setState(newState);
   pageContainer.setState(newState);
 
 
   // PageEditor component
   // PageEditor component
-  if (componentInstances.pageEditor != null) {
+  const pageEditor = appContainer.getComponentInstance('PageEditor');
+  if (pageEditor != null) {
     if (editorMode !== 'builtin') {
     if (editorMode !== 'builtin') {
-      componentInstances.pageEditor.updateEditorValue(newState.markdown);
+      pageEditor.updateEditorValue(newState.markdown);
     }
     }
   }
   }
   // PageEditorByHackmd component
   // PageEditorByHackmd component
-  if (componentInstances.pageEditorByHackmd != null) {
+  const pageEditorByHackmd = appContainer.getComponentInstance('PageEditorByHackmd');
+  if (pageEditorByHackmd != null) {
     // clear state of PageEditorByHackmd
     // clear state of PageEditorByHackmd
-    componentInstances.pageEditorByHackmd.clearRevisionStatus(newState.revisionId);
+    pageEditorByHackmd.clearRevisionStatus(newState.revisionId);
     // reset
     // reset
     if (editorMode !== 'hackmd') {
     if (editorMode !== 'hackmd') {
-      componentInstances.pageEditorByHackmd.reset();
+      pageEditorByHackmd.reset();
     }
     }
   }
   }
   // PageStatusAlert component
   // PageStatusAlert component
-  const pageStatusAlert = componentInstances.pageStatusAlert;
+  const pageStatusAlert = appContainer.getComponentInstance('PageStatusAlert');
   // clear state of PageStatusAlert
   // clear state of PageStatusAlert
-  if (componentInstances.pageStatusAlert != null) {
+  if (pageStatusAlert != null) {
     pageStatusAlert.clearRevisionStatus(pageRevisionId, pageRevisionIdHackmdSynced);
     pageStatusAlert.clearRevisionStatus(pageRevisionId, pageRevisionIdHackmdSynced);
   }
   }
 
 
@@ -257,16 +258,18 @@ const saveWithSubmitButton = function(submitOpts) {
 
 
   let promise;
   let promise;
   if (editorMode === 'hackmd') {
   if (editorMode === 'hackmd') {
+    const pageEditorByHackmd = appContainer.getComponentInstance('PageEditorByHackmd');
     // get markdown
     // get markdown
-    promise = componentInstances.pageEditorByHackmd.getMarkdown();
+    promise = pageEditorByHackmd.getMarkdown();
     // use revisionId of PageEditorByHackmd
     // use revisionId of PageEditorByHackmd
     revisionId = componentInstances.pageEditorByHackmd.getRevisionIdHackmdSynced();
     revisionId = componentInstances.pageEditorByHackmd.getRevisionIdHackmdSynced();
     // set option to sync
     // set option to sync
     options.isSyncRevisionToHackmd = true;
     options.isSyncRevisionToHackmd = true;
   }
   }
   else {
   else {
+    const pageEditor = appContainer.getComponentInstance('PageEditor');
     // get markdown
     // get markdown
-    promise = Promise.resolve(componentInstances.pageEditor.getMarkdown());
+    promise = Promise.resolve(pageEditor.getMarkdown());
   }
   }
   // create or update
   // create or update
   if (pageId == null) {
   if (pageId == null) {
@@ -449,16 +452,18 @@ let pageEditorByHackmd = null;
 const pageEditorWithHackmdElem = document.getElementById('page-editor-with-hackmd');
 const pageEditorWithHackmdElem = document.getElementById('page-editor-with-hackmd');
 if (pageEditorWithHackmdElem) {
 if (pageEditorWithHackmdElem) {
   pageEditorByHackmd = ReactDOM.render(
   pageEditorByHackmd = ReactDOM.render(
-    <PageEditorByHackmd
-      crowi={crowi}
-      pageId={pageId}
-      revisionId={pageRevisionId}
-      pageIdOnHackmd={pageIdOnHackmd}
-      revisionIdHackmdSynced={pageRevisionIdHackmdSynced}
-      hasDraftOnHackmd={hasDraftOnHackmd}
-      markdown={markdown}
-      onSaveWithShortcut={saveWithShortcut}
-    />,
+    <Provider inject={[appContainer]}>
+      <PageEditorByHackmd
+        crowi={crowi}
+        pageId={pageId}
+        revisionId={pageRevisionId}
+        pageIdOnHackmd={pageIdOnHackmd}
+        revisionIdHackmdSynced={pageRevisionIdHackmdSynced}
+        hasDraftOnHackmd={hasDraftOnHackmd}
+        markdown={markdown}
+        onSaveWithShortcut={saveWithShortcut}
+      />,
+    </Provider>,
     pageEditorWithHackmdElem,
     pageEditorWithHackmdElem,
   );
   );
   componentInstances.pageEditorByHackmd = pageEditorByHackmd;
   componentInstances.pageEditorByHackmd = pageEditorByHackmd;
@@ -521,16 +526,18 @@ const pageStatusAlertElem = document.getElementById('page-status-alert');
 if (pageStatusAlertElem) {
 if (pageStatusAlertElem) {
   ReactDOM.render(
   ReactDOM.render(
     <I18nextProvider i18n={i18n}>
     <I18nextProvider i18n={i18n}>
-      <PageStatusAlert
-        ref={(elem) => {
-            if (pageStatusAlert == null) {
-              pageStatusAlert = elem;
-            }
-          }}
-        revisionId={pageRevisionId}
-        revisionIdHackmdSynced={pageRevisionIdHackmdSynced}
-        hasDraftOnHackmd={hasDraftOnHackmd}
-      />
+      <Provider inject={[appContainer, pageContainer]}>
+        <PageStatusAlert
+          ref={(elem) => {
+              if (pageStatusAlert == null) {
+                pageStatusAlert = elem;
+              }
+            }}
+          revisionId={pageRevisionId}
+          revisionIdHackmdSynced={pageRevisionIdHackmdSynced}
+          hasDraftOnHackmd={hasDraftOnHackmd}
+        />
+      </Provider>
     </I18nextProvider>,
     </I18nextProvider>,
     pageStatusAlertElem,
     pageStatusAlertElem,
   );
   );

+ 39 - 1
src/client/js/components/PageEditorByHackmd.jsx

@@ -1,14 +1,18 @@
+/* eslint-disable react/no-multi-comp */
 import React from 'react';
 import React from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
+import { Subscribe } from 'unstated';
 
 
 import SplitButton from 'react-bootstrap/es/SplitButton';
 import SplitButton from 'react-bootstrap/es/SplitButton';
 import MenuItem from 'react-bootstrap/es/MenuItem';
 import MenuItem from 'react-bootstrap/es/MenuItem';
 
 
 import * as toastr from 'toastr';
 import * as toastr from 'toastr';
 
 
+import AppContainer from '../services/AppContainer';
+
 import HackmdEditor from './PageEditorByHackmd/HackmdEditor';
 import HackmdEditor from './PageEditorByHackmd/HackmdEditor';
 
 
-export default class PageEditorByHackmd extends React.PureComponent {
+class PageEditorByHackmd extends React.PureComponent {
 
 
   constructor(props) {
   constructor(props) {
     super(props);
     super(props);
@@ -33,6 +37,7 @@ export default class PageEditorByHackmd extends React.PureComponent {
   }
   }
 
 
   componentWillMount() {
   componentWillMount() {
+    this.props.appContainer.registerComponentInstance(this);
   }
   }
 
 
   /**
   /**
@@ -311,7 +316,27 @@ export default class PageEditorByHackmd extends React.PureComponent {
 
 
 }
 }
 
 
+/**
+ * Wrapper component for using unstated
+ */
+class PageEditorByHackmdWrapper extends React.Component {
+
+  render() {
+    return (
+      <Subscribe to={[AppContainer]}>
+        { appContainer => (
+          // eslint-disable-next-line arrow-body-style
+          <PageEditorByHackmd appContainer={appContainer} {...this.props} />
+        )}
+      </Subscribe>
+    );
+  }
+
+}
+
 PageEditorByHackmd.propTypes = {
 PageEditorByHackmd.propTypes = {
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+
   crowi: PropTypes.object.isRequired,
   crowi: PropTypes.object.isRequired,
   markdown: PropTypes.string.isRequired,
   markdown: PropTypes.string.isRequired,
   onSaveWithShortcut: PropTypes.func.isRequired,
   onSaveWithShortcut: PropTypes.func.isRequired,
@@ -321,3 +346,16 @@ PageEditorByHackmd.propTypes = {
   revisionIdHackmdSynced: PropTypes.string,
   revisionIdHackmdSynced: PropTypes.string,
   hasDraftOnHackmd: PropTypes.bool,
   hasDraftOnHackmd: PropTypes.bool,
 };
 };
+
+PageEditorByHackmdWrapper.propTypes = {
+  crowi: PropTypes.object.isRequired,
+  markdown: PropTypes.string.isRequired,
+  onSaveWithShortcut: PropTypes.func.isRequired,
+  pageId: PropTypes.string,
+  revisionId: PropTypes.string,
+  pageIdOnHackmd: PropTypes.string,
+  revisionIdHackmdSynced: PropTypes.string,
+  hasDraftOnHackmd: PropTypes.bool,
+};
+
+export default PageEditorByHackmdWrapper;

+ 37 - 2
src/client/js/components/PageStatusAlert.jsx

@@ -1,6 +1,10 @@
+/* eslint-disable react/no-multi-comp */
 import React from 'react';
 import React from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
+import { Subscribe } from 'unstated';
+import AppContainer from '../services/AppContainer';
+import PageContainer from '../services/PageContainer';
 
 
 /**
 /**
  *
  *
@@ -30,6 +34,10 @@ class PageStatusAlert extends React.Component {
     this.renderUpdatedAlert = this.renderUpdatedAlert.bind(this);
     this.renderUpdatedAlert = this.renderUpdatedAlert.bind(this);
   }
   }
 
 
+  componentWillMount() {
+    this.props.appContainer.registerComponentInstance(this);
+  }
+
   /**
   /**
    * clear status (invoked when page is updated by myself)
    * clear status (invoked when page is updated by myself)
    */
    */
@@ -130,14 +138,41 @@ class PageStatusAlert extends React.Component {
 
 
 }
 }
 
 
+/**
+ * Wrapper component for using unstated
+ */
+class PageStatusAlertWrapper extends React.Component {
+
+  render() {
+    return (
+      <Subscribe to={[AppContainer, PageContainer]}>
+        { (appContainer, pageContainer) => (
+          // eslint-disable-next-line arrow-body-style
+          <PageStatusAlert appContainer={appContainer} pageContainer={pageContainer} {...this.props} />
+        )}
+      </Subscribe>
+    );
+  }
+
+}
+
 PageStatusAlert.propTypes = {
 PageStatusAlert.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   t: PropTypes.func.isRequired, // i18next
+
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
+
   hasDraftOnHackmd: PropTypes.bool.isRequired,
   hasDraftOnHackmd: PropTypes.bool.isRequired,
   revisionId: PropTypes.string,
   revisionId: PropTypes.string,
   revisionIdHackmdSynced: PropTypes.string,
   revisionIdHackmdSynced: PropTypes.string,
 };
 };
 
 
-PageStatusAlert.defaultProps = {
+PageStatusAlertWrapper.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+
+  hasDraftOnHackmd: PropTypes.bool.isRequired,
+  revisionId: PropTypes.string,
+  revisionIdHackmdSynced: PropTypes.string,
 };
 };
 
 
-export default withTranslation(null, { withRef: true })(PageStatusAlert);
+export default withTranslation(null, { withRef: true })(PageStatusAlertWrapper);