PageEditorByHackmd.jsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import * as toastr from 'toastr';
  4. import HackmdEditor from './PageEditorByHackmd/HackmdEditor';
  5. export default class PageEditorByHackmd extends React.PureComponent {
  6. constructor(props) {
  7. super(props);
  8. this.state = {
  9. isInitialized: false,
  10. isInitializing: false,
  11. pageIdOnHackmd: this.props.pageIdOnHackmd,
  12. };
  13. this.getHackmdUri = this.getHackmdUri.bind(this);
  14. this.startToEdit = this.startToEdit.bind(this);
  15. this.resumeToEdit = this.resumeToEdit.bind(this);
  16. this.apiErrorHandler = this.apiErrorHandler.bind(this);
  17. }
  18. componentWillMount() {
  19. }
  20. getHackmdUri() {
  21. const envVars = this.props.crowi.config.env;
  22. return envVars.HACKMD_URI;
  23. }
  24. /**
  25. * Start integration with HackMD
  26. */
  27. startToEdit() {
  28. const hackmdUri = this.getHackmdUri();
  29. if (hackmdUri == null) {
  30. // do nothing
  31. return;
  32. }
  33. this.setState({
  34. isInitialized: false,
  35. isInitializing: true,
  36. });
  37. const params = {
  38. pageId: this.props.pageId,
  39. };
  40. this.props.crowi.apiPost('/hackmd.integrate', params)
  41. .then(res => {
  42. if (!res.ok) {
  43. throw new Error(res.error);
  44. }
  45. this.setState({
  46. isInitialized: true,
  47. pageIdOnHackmd: res.pageIdOnHackmd,
  48. revisionIdHackmdSynced: res.revisionIdHackmdSynced,
  49. });
  50. })
  51. .catch(this.apiErrorHandler)
  52. .then(() => {
  53. this.setState({isInitializing: false});
  54. });
  55. }
  56. /**
  57. * Start to edit w/o any api request
  58. */
  59. resumeToEdit() {
  60. this.setState({isInitialized: true});
  61. }
  62. apiErrorHandler(error) {
  63. toastr.error(error.message, 'Error occured', {
  64. closeButton: true,
  65. progressBar: true,
  66. newestOnTop: false,
  67. showDuration: '100',
  68. hideDuration: '100',
  69. timeOut: '3000',
  70. });
  71. }
  72. render() {
  73. const hackmdUri = this.getHackmdUri();
  74. if (this.state.isInitialized) {
  75. return (
  76. <HackmdEditor
  77. markdown={this.props.markdown}
  78. hackmdUri={hackmdUri}
  79. pageIdOnHackmd={this.state.pageIdOnHackmd}
  80. >
  81. </HackmdEditor>
  82. );
  83. }
  84. let content = undefined;
  85. const isPageExistsOnHackmd = (this.state.pageIdOnHackmd != null);
  86. const isRevisionMatch = (this.props.revisionId === this.props.revisionIdHackmdSynced);
  87. // HackMD is not setup
  88. if (hackmdUri == null) {
  89. content = (
  90. <div>
  91. <p className="text-center hackmd-status-label"><i className="fa fa-file-text"></i> HackMD is not set up.</p>
  92. </div>
  93. );
  94. }
  95. // page is exists, revisions are match, hasDraftOnHackmd is true
  96. else if (isPageExistsOnHackmd && isRevisionMatch && this.props.hasDraftOnHackmd) {
  97. content = (
  98. <div>
  99. <p className="text-center hackmd-status-label"><i className="fa fa-file-text"></i> HackMD is READY!</p>
  100. <p className="text-center">
  101. <button className="btn btn-success btn-lg waves-effect waves-light" type="button"
  102. onClick={() => this.resumeToEdit()}>
  103. <span className="btn-label"><i className="icon-control-end"></i></span>
  104. Resume to edit with HackMD
  105. </button>
  106. </p>
  107. <p className="text-center">Click to edit from the previous continuation.</p>
  108. </div>
  109. );
  110. }
  111. else {
  112. content = (
  113. <div>
  114. <p className="text-center hackmd-status-label"><i className="fa fa-file-text"></i> HackMD is READY!</p>
  115. <p className="text-center">
  116. <button className="btn btn-info btn-lg waves-effect waves-light" type="button"
  117. onClick={() => this.startToEdit()} disabled={this.state.isInitializing}>
  118. <span className="btn-label"><i className="icon-paper-plane"></i></span>
  119. Start to edit with HackMD
  120. </button>
  121. </p>
  122. <p className="text-center">Click to clone page content and start to edit.</p>
  123. </div>
  124. );
  125. }
  126. return (
  127. <div className="hackmd-preinit d-flex justify-content-center align-items-center">
  128. {content}
  129. </div>
  130. );
  131. }
  132. }
  133. PageEditorByHackmd.propTypes = {
  134. crowi: PropTypes.object.isRequired,
  135. markdown: PropTypes.string.isRequired,
  136. pageId: PropTypes.string,
  137. revisionId: PropTypes.string,
  138. pageIdOnHackmd: PropTypes.string,
  139. revisionIdHackmdSynced: PropTypes.string,
  140. hasDraftOnHackmd: PropTypes.bool,
  141. };