Procházet zdrojové kódy

WIP: impl HandsontableModal

refactor
Yuki Takei před 7 roky
rodič
revize
a08c0b9290

+ 17 - 12
src/client/js/components/PageEditor/HandsontableModal.jsx

@@ -11,6 +11,8 @@ import MenuItem from 'react-bootstrap/es/MenuItem';
 
 import { HotTable } from '@handsontable/react';
 
+import MarkdownTable from '../../util/MarkdownTable';
+
 export default class HandsontableModal extends React.Component {
   constructor(props) {
     super(props);
@@ -29,23 +31,26 @@ export default class HandsontableModal extends React.Component {
       selectionMode: 'multiple',
     };
 
-    this.initData(this.props.data);
-
+    this.init = this.init.bind(this);
     this.cancel = this.cancel.bind(this);
     this.dispatchSave = this.dispatchSave.bind(this);
   }
 
-  initData(data) {
-    const initData = data || [
+  componentWillMount() {
+    this.init(this.props.markdownTable);
+  }
+
+  init(markdownTable) {
+    const initMarkdownTable = markdownTable || new MarkdownTable([
       ['col1', 'col2', 'col3'],
       ['', '', ''],
       ['', '', ''],
-    ];
-    this.setState({ data: initData });
+    ]);
+    this.setState({ markdownTable: initMarkdownTable });
   }
 
-  show(data, doneHandler) {
-    this.initData(data);
+  show(markdownTable, doneHandler) {
+    this.init(markdownTable);
     this.setState({ show: true });
   }
 
@@ -58,7 +63,7 @@ export default class HandsontableModal extends React.Component {
    */
   dispatchSave() {
     if (this.props.onSave != null) {
-      this.props.onSave(this.state.data);
+      this.props.onSave(this.state.markdownTable);
     }
   }
 
@@ -87,12 +92,12 @@ export default class HandsontableModal extends React.Component {
             </Navbar.Form>
           </Navbar>
           <div className="p-4">
-            <HotTable data={this.state.data} settings={this.settings} />
+            <HotTable data={this.state.markdownTable.data} settings={this.settings} />
           </div>
         </Modal.Body>
         <Modal.Footer>
           <div className="d-flex justify-content-between">
-            <Button bsStyle="danger" onClick={() => this.initData(this.props.data)}>Reset</Button>
+            <Button bsStyle="danger" onClick={() => this.init(this.props.markdownTable)}>Reset</Button>
             <div className="d-flex">
               <Button bsStyle="default" onClick={this.cancel}>Cancel</Button>
               <Button bsStyle="primary" onClick={this.dispatchSave}>Done</Button>
@@ -105,6 +110,6 @@ export default class HandsontableModal extends React.Component {
 }
 
 HandsontableModal.propTypes = {
-  data: PropTypes.object,
+  markdownTable: PropTypes.instanceOf(MarkdownTable),
   onSave: PropTypes.func,
 };

+ 70 - 0
src/client/js/util/MarkdownTable.js

@@ -0,0 +1,70 @@
+import markdownTable from 'markdown-table';
+import stringWidth from 'string-width';
+
+// https://github.com/markdown-it/markdown-it/blob/d29f421927e93e88daf75f22089a3e732e195bd2/lib/rules_block/table.js#L83
+// https://regex101.com/r/7BN2fR/7
+const tableAlignmentLineRE = /^[-:|][-:|\s]*$/;
+const tableAlignmentLineNegRE = /^[^-:]*$/;  // it is need to check to ignore empty row which is matched above RE
+const linePartOfTableRE = /^\|[^\r\n]*|[^\r\n]*\|$|([^|\r\n]+\|[^|\r\n]*)+/; // own idea
+
+/**
+ * markdown table class for markdown-table module
+ *   ref. https://github.com/wooorm/markdown-table
+ */
+export default class MarkdownTable {
+
+  constructor(data, options) {
+    this.data = data || [];
+    this.options = options || {};
+
+    this.toString = this.toString.bind(this);
+  }
+
+  toString() {
+    return markdownTable(this.data, this.options);
+  }
+
+  static fromTableTag(str) {
+    // TODO impl
+    return new MarkdownTable();
+  }
+
+  /**
+   * returns MarkdownTable instance
+   *   ref. https://github.com/wooorm/markdown-table
+   * @param {string} str markdown string
+   */
+  static fromMarkdownString(str) {
+    const arrMDTableLines = str.split(/(\r\n|\r|\n)/);
+    let contents = [];
+    let aligns = [];
+    for (let n = 0; n < arrMDTableLines.length; n++) {
+      const line = arrMDTableLines[n];
+
+      if (tableAlignmentLineRE.test(line) && !tableAlignmentLineNegRE.test(line)) {
+        // parse line which described alignment
+        const alignRuleRE = [
+          { align: 'c', regex: /^:-+:$/ },
+          { align: 'l', regex: /^:-+$/  },
+          { align: 'r', regex: /^-+:$/  },
+        ];
+        let lineText = '';
+        lineText = line.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
+        lineText = lineText.replace(/\s*/g, '');
+        aligns = lineText.split(/\|/).map(col => {
+          const rule = alignRuleRE.find(rule => col.match(rule.regex));
+          return (rule != undefined) ? rule.align : '';
+        });
+      }
+      else if (linePartOfTableRE.test(line)) {
+        // parse line whether header or body
+        let lineText = '';
+        lineText = line.replace(/\s*\|\s*/g, '|');
+        lineText = lineText.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
+        const row = lineText.split(/\|/);
+        contents.push(row);
+      }
+    }
+    return (new MarkdownTable(contents, { align: aligns, stringLength: stringWidth }));
+  }
+}