Просмотр исходного кода

Merge branch 'feat/dsv-table-data-import' into feat/html-table-data-import

# Conflicts:
#	src/client/js/models/MarkdownTable.js
utsushiiro 7 лет назад
Родитель
Сommit
9fc6ad97ec

+ 1 - 1
package.json

@@ -73,6 +73,7 @@
     "cookie-parser": "^1.4.3",
     "cross-env": "^5.0.5",
     "csrf": "~3.0.3",
+    "csv-to-markdown-table": "^0.4.0",
     "diff": "^3.5.0",
     "elasticsearch": "^15.0.0",
     "entities": "^1.1.1",
@@ -147,7 +148,6 @@
     "commander": "^2.11.0",
     "connect-browser-sync": "^2.1.0",
     "css-loader": "^1.0.0",
-    "csv-to-markdown-table": "^0.4.0",
     "date-fns": "^1.29.0",
     "diff2html": "^2.3.3",
     "eazy-logger": "^3.0.2",

+ 54 - 0
src/client/js/components/PageEditor/DataImportForm.js

@@ -0,0 +1,54 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import FormGroup from 'react-bootstrap/es/FormGroup';
+import ControlLabel from 'react-bootstrap/es/ControlLabel';
+import FormControl from 'react-bootstrap/es/FormControl';
+import Button from 'react-bootstrap/es/Button';
+
+export default class DataImportForm extends React.PureComponent {
+
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      dataFormat: 'csv',
+      data: ''
+    };
+
+    this.importButtonHandler = this.importButtonHandler.bind(this);
+  }
+
+  importButtonHandler() {
+    this.props.onImport(this.state.dataFormat, this.state.data);
+  }
+
+  render() {
+    return (
+      <form action="" className="data-import-form pt-5">
+        <FormGroup>
+          <ControlLabel>Select Data Format</ControlLabel>
+          <FormControl componentClass="select" placeholder="select"
+                       value={this.state.dataFormat} onChange={e => this.setState({dataFormat: e.target.value})}>
+            <option value="csv">CSV</option>
+            <option value="tsv">TSV</option>
+            <option value="html">(TBD) HTML</option>
+          </FormControl>
+        </FormGroup>
+        <FormGroup>
+          <ControlLabel>Import Data</ControlLabel>
+          <FormControl componentClass="textarea" placeholder="Paste table data" style={{ height: 200 }}
+                       onChange={e => this.setState({data: e.target.value})}/>
+        </FormGroup>
+        <div className="d-flex justify-content-end">
+          <Button bsStyle="default" onClick={this.props.onCancel}>Cancel</Button>
+          <Button bsStyle="primary" onClick={this.importButtonHandler}>Import</Button>
+        </div>
+      </form>
+    );
+  }
+}
+
+DataImportForm.propTypes = {
+  onCancel: PropTypes.func,
+  onImport: PropTypes.func
+};

+ 15 - 25
src/client/js/components/PageEditor/HandsontableModal.jsx

@@ -1,19 +1,14 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-
 import Modal from 'react-bootstrap/es/Modal';
 import Button from 'react-bootstrap/es/Button';
 import ButtonGroup from 'react-bootstrap/es/ButtonGroup';
-
-import { debounce } from 'throttle-debounce';
 import Collapse from 'react-bootstrap/es/Collapse';
-import FormGroup from 'react-bootstrap/es/FormGroup';
-import ControlLabel from 'react-bootstrap/es/ControlLabel';
-import FormControl from 'react-bootstrap/es/FormControl';
-
 import Handsontable from 'handsontable';
 import { HotTable } from '@handsontable/react';
+import { debounce } from 'throttle-debounce';
 
+import DataImportForm from './DataImportForm';
 import MarkdownTable from '../../models/MarkdownTable';
 
 const DEFAULT_HOT_HEIGHT = 300;
@@ -51,6 +46,7 @@ export default class HandsontableModal extends React.PureComponent {
     this.synchronizeAlignment = this.synchronizeAlignment.bind(this);
     this.alignButtonHandler = this.alignButtonHandler.bind(this);
     this.toggleDataImportArea = this.toggleDataImportArea.bind(this);
+    this.importData = this.importData.bind(this);
     this.expandWindow = this.expandWindow.bind(this);
     this.contractWindow = this.contractWindow.bind(this);
 
@@ -248,6 +244,17 @@ export default class HandsontableModal extends React.PureComponent {
     this.setState({ isDataImportAreaExpanded: !this.state.isDataImportAreaExpanded });
   }
 
+  importData(dataFormat, data) {
+    switch (dataFormat) {
+      case 'csv':
+        this.init(MarkdownTable.fromDSV(data, ','));
+        break;
+      case 'tsv':
+        this.init(MarkdownTable.fromDSV(data, '\t'));
+        break;
+    }
+  }
+
   expandWindow() {
     this.setState({ isWindowExpanded: true });
 
@@ -307,24 +314,7 @@ export default class HandsontableModal extends React.PureComponent {
             </ButtonGroup>
             <Collapse in={this.state.isDataImportAreaExpanded}>
               <div> {/* This div is necessary for smoothing animations. (https://react-bootstrap.github.io/utilities/transitions/#transitions-collapse) */}
-                <form action="" className="data-import-form pt-5">
-                  <FormGroup>
-                    <ControlLabel>Select Data Format</ControlLabel>
-                    <FormControl componentClass="select" placeholder="select">
-                      <option value="select">CSV</option>
-                      <option value="other">(TBD) TSV</option>
-                      <option value="other">(TBD) HTML</option>
-                    </FormControl>
-                  </FormGroup>
-                  <FormGroup>
-                    <ControlLabel>Import Data</ControlLabel>
-                    <FormControl componentClass="textarea" placeholder="Paste table data" style={{ height: 200 }}  />
-                  </FormGroup>
-                  <div className="d-flex justify-content-end">
-                    <Button bsStyle="default" onClick={this.toggleDataImportArea}>Cancel</Button>
-                    <Button bsStyle="primary">Import</Button>
-                  </div>
-                </form>
+                <DataImportForm onCancel={this.toggleDataImportArea} onImport={this.importData}/>
               </div>
             </Collapse>
           </div>

+ 9 - 1
src/client/js/models/MarkdownTable.js

@@ -2,6 +2,7 @@ import markdownTable from 'markdown-table';
 import stringWidth from 'string-width';
 import TurndownService from 'turndown';
 import {tables} from 'turndown-plugin-gfm';
+import csvToMarkdown from 'csv-to-markdown-table';
 
 // https://github.com/markdown-it/markdown-it/blob/d29f421927e93e88daf75f22089a3e732e195bd2/lib/rules_block/table.js#L83
 // https://regex101.com/r/7BN2fR/7
@@ -47,7 +48,14 @@ export default class MarkdownTable {
   }
 
   /**
-   * returns MarkdownTable instance
+   * return a MarkdownTable instance made from a string of delimiter-separated values
+   */
+  static fromDSV(str, delimiter) {
+    return MarkdownTable.fromMarkdownString(csvToMarkdown(str, delimiter, true));
+  }
+
+  /**
+   * return a MarkdownTable instance
    *   ref. https://github.com/wooorm/markdown-table
    * @param {string} str markdown string
    */