Yuki Takei 8 лет назад
Родитель
Сommit
163f03eec1

+ 1 - 1
resource/js/app.js

@@ -71,7 +71,7 @@ if (isEnabledPlugins) {
 const componentMappings = {
   'search-top': <HeaderSearchBox crowi={crowi} />,
   'search-page': <SearchPage crowi={crowi} />,
-  'page-editor': <PageEditor crowi={crowi} markdown={entities.decodeHTML(pageContent)} />,
+  'page-editor': <PageEditor crowi={crowi} pageId={pageId} revisionId={pageRevisionId} pagePath={pagePath} markdown={entities.decodeHTML(pageContent)} />,
   'page-list-search': <PageListSearch crowi={crowi} />,
   'page-comments-list': <PageComments pageId={pageId} revisionId={pageRevisionId} revisionCreatedAt= {pageRevisionCreatedAt} crowi={crowi} />,
   'page-attachment': <PageAttachment pageId={pageId} pageContent={pageContent} crowi={crowi} />,

+ 69 - 1
resource/js/components/PageEditor.js

@@ -1,6 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
+import * as toastr from 'toastr';
+
 import Editor from './PageEditor/Editor';
 import Preview from './PageEditor/Preview';
 
@@ -10,6 +12,7 @@ export default class PageEditor extends React.Component {
     super(props);
 
     this.state = {
+      revisionId: this.props.revisionId,
       markdown: this.props.markdown,
     };
     // initial preview
@@ -18,6 +21,7 @@ export default class PageEditor extends React.Component {
     this.setCaretLine = this.setCaretLine.bind(this);
     this.focusToEditor = this.focusToEditor.bind(this);
     this.onMarkdownChanged = this.onMarkdownChanged.bind(this);
+    this.onSave = this.onSave.bind(this);
   }
 
   focusToEditor() {
@@ -45,6 +49,64 @@ export default class PageEditor extends React.Component {
     this.renderPreview();
   }
 
+  /**
+   * the save event handler
+   */
+  onSave() {
+    let endpoint;
+    let data;
+
+    // update
+    if (this.props.pageId != null) {
+      endpoint = '/pages.update';
+      data = {
+        page_id: this.props.pageId,
+        revision_id: this.state.revisionId,
+        body: this.state.markdown,
+      };
+    }
+    // create
+    else {
+      endpoint = '/pages.create';
+      data = {
+        path: this.props.pagePath,
+        body: this.state.markdown,
+      };
+    }
+
+    this.props.crowi.apiPost(endpoint, data)
+      .then((res) => {
+        const page = res.page;
+
+        toastr.success(undefined, 'Saved successfully', {
+          closeButton: true,
+          progressBar: true,
+          newestOnTop: false,
+          showDuration: "100",
+          hideDuration: "100",
+          timeOut: "1200",
+          extendedTimeOut: "150",
+        });
+
+        // update states
+        this.setState({
+          revisionId: page.revision._id,
+          markdown: page.revision.body
+        })
+      })
+      .catch((error) => {
+        console.error(error);
+        toastr.error(error.message, 'Error occured on saveing', {
+          closeButton: true,
+          progressBar: true,
+          newestOnTop: false,
+          showDuration: "100",
+          hideDuration: "100",
+          timeOut: "3000",
+        });
+      });
+  }
+
   renderPreview() {
     const config = this.props.crowi.config;
 
@@ -90,7 +152,10 @@ export default class PageEditor extends React.Component {
     return (
       <div className="row">
         <div className="col-md-6 col-sm-12 page-editor-editor-container">
-          <Editor ref="editor" value={this.state.markdown} onChange={this.onMarkdownChanged} />
+          <Editor ref="editor" value={this.state.markdown}
+              onChange={this.onMarkdownChanged}
+              onSave={this.onSave}
+          />
         </div>
         <div className="col-md-6 hidden-sm hidden-xs page-editor-preview-container">
           <Preview html={this.state.html} inputRef={el => this.previewElement = el} />
@@ -102,5 +167,8 @@ export default class PageEditor extends React.Component {
 
 PageEditor.propTypes = {
   crowi: PropTypes.object.isRequired,
+  pageId: PropTypes.string,
+  revisionId: PropTypes.string,
+  pagePath: PropTypes.string,
   markdown: PropTypes.string,
 };

+ 17 - 3
resource/js/components/PageEditor/Editor.js

@@ -1,7 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import { UnControlled as CodeMirror } from 'react-codemirror2';
+import * as codemirror from 'codemirror';
+
+import { UnControlled as ReactCodeMirror } from 'react-codemirror2';
 require('codemirror/lib/codemirror.css');
 require('codemirror/addon/display/autorefresh');
 require('codemirror/addon/edit/matchbrackets');
@@ -28,11 +30,14 @@ export default class Editor extends React.Component {
     this.getCodeMirror = this.getCodeMirror.bind(this);
     this.setCaretLine = this.setCaretLine.bind(this);
     this.forceToFocus = this.forceToFocus.bind(this);
+    this.dispatchSave = this.dispatchSave.bind(this);
   }
 
   componentDidMount() {
     // initialize caret line
     this.setCaretLine(0);
+    // set save handler
+    codemirror.commands.save = this.dispatchSave;
   }
 
   getCodeMirror() {
@@ -59,9 +64,18 @@ export default class Editor extends React.Component {
     editor.setCursor({line: line-1});   // leave 'ch' field as null/undefined to indicate the end of line
   }
 
+  /**
+   * dispatch onSave event
+   */
+  dispatchSave() {
+    if (this.props.onSave != null) {
+      this.props.onSave();
+    }
+  }
+
   render() {
     return (
-      <CodeMirror
+      <ReactCodeMirror
         ref="cm"
         value={this.state.value}
         options={{
@@ -83,7 +97,6 @@ export default class Editor extends React.Component {
           extraKeys: {
             "Enter": "newlineAndIndentContinueMarkdownList",
             "Tab": "autoIndentMarkdownList",
-            "Shift-Tab": "autoUnindentMarkdownList"
           }
         }}
         onScroll={(editor, data) => {
@@ -106,4 +119,5 @@ Editor.propTypes = {
   value: PropTypes.string,
   onChange: PropTypes.func,
   onScroll: PropTypes.func,
+  onSave: PropTypes.func,
 };