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

Enter key behavior in markdown table

Yuki Takei 6 лет назад
Родитель
Сommit
77de38c18b

+ 1 - 0
CHANGES.md

@@ -4,6 +4,7 @@
 
 * Improvement: Reactify admin pages (Customize)
 * Improvement: Ensure not to consider `[text|site](https://example.com]` as a row in the table
+* Improvement: Enter key behavior in markdown table
 * Fix: Emoji Autocomplete window does not float correctly
     * Introduced by 3.5.0
 

+ 8 - 0
src/client/js/components/PageEditor/AbstractEditor.jsx

@@ -79,6 +79,14 @@ export default class AbstractEditor extends React.Component {
     throw new Error('this method should be impelemented in subclass');
   }
 
+  /**
+   * replace the current line with param 'text'
+   * @param {string} text
+   */
+  replaceLine(text) {
+    throw new Error('this method should be impelemented in subclass');
+  }
+
   /**
    * insert text
    * @param {string} text

+ 8 - 0
src/client/js/components/PageEditor/CodeMirrorEditor.jsx

@@ -247,6 +247,14 @@ export default class CodeMirrorEditor extends AbstractEditor {
     editor.getDoc().replaceRange(text, this.getBol(), pos);
   }
 
+  /**
+   * @inheritDoc
+   */
+  replaceLine(text) {
+    const editor = this.getCodeMirror();
+    editor.getDoc().replaceRange(text, this.getBol(), this.getEol());
+  }
+
   /**
    * @inheritDoc
    */

+ 42 - 19
src/client/js/components/PageEditor/MarkdownTableInterceptor.js

@@ -24,44 +24,67 @@ export default class MarkdownTableInterceptor extends BasicInterceptor {
     return false;
   }
 
+  addRow(cm) {
+    // get lines all of table from current position to beginning of table
+    const strFromBot = mtu.getStrFromBot(cm);
+    let table = MarkdownTable.fromMarkdownString(strFromBot);
+
+    mtu.addRowToMarkdownTable(table);
+
+    const strToEot = mtu.getStrToEot(cm);
+    const tableBottom = MarkdownTable.fromMarkdownString(strToEot);
+    if (tableBottom.table.length > 0) {
+      table = mtu.mergeMarkdownTable([table, tableBottom]);
+    }
+
+    mtu.replaceMarkdownTableWithReformed(cm, table);
+  }
+
+  reformTable(cm) {
+    const tableStr = mtu.getStrFromBot(cm) + mtu.getStrToEot(cm);
+    const table = MarkdownTable.fromMarkdownString(tableStr);
+    mtu.replaceMarkdownTableWithReformed(cm, table);
+  }
+
+  removeRow(editor) {
+    editor.replaceLine('\n');
+  }
+
   /**
    * @inheritdoc
    */
-  process(contextName, ...args) {
+  async process(contextName, ...args) {
     const context = Object.assign(args[0]); // clone
     const editor = context.editor; // AbstractEditor instance
 
     // do nothing if editor is not a CodeMirrorEditor
     if (editor == null || editor.getCodeMirror() == null) {
-      return Promise.resolve(context);
+      return context;
     }
 
     const cm = editor.getCodeMirror();
 
-    // get strings from BOL(beginning of line) to current position
-    const strFromBol = editor.getStrFromBol();
-
-    if (mtu.isEndOfLine(cm) && mtu.linePartOfTableRE.test(strFromBol)) {
-      // get lines all of table from current position to beginning of table
-      const strFromBot = mtu.getStrFromBot(cm);
-      let table = MarkdownTable.fromMarkdownString(strFromBot);
-
-      mtu.addRowToMarkdownTable(table);
+    const isInTable = mtu.isInTable(cm);
+    const isLastRow = mtu.getStrToEot(cm) === editor.getStrToEol();
 
-      const strToEot = mtu.getStrToEot(cm);
-      const tableBottom = MarkdownTable.fromMarkdownString(strToEot);
-      if (tableBottom.table.length > 0) {
-        table = mtu.mergeMarkdownTable([table, tableBottom]);
+    if (isInTable) {
+      // at EOL in the table
+      if (mtu.isEndOfLine(cm)) {
+        this.addRow(cm);
+      }
+      // last empty row
+      else if (isLastRow && mtu.emptyLineOfTableRE.test(editor.getStrFromBol() + editor.getStrToEol())) {
+        this.removeRow(editor);
+      }
+      else {
+        this.reformTable(cm);
       }
-
-      mtu.replaceMarkdownTableWithReformed(cm, table);
 
       // report to manager that handling was done
       context.handlers.push(this.className);
+      return context;
     }
 
-    // resolve
-    return Promise.resolve(context);
   }
 
 }

+ 2 - 9
src/client/js/components/PageEditor/MarkdownTableUtil.js

@@ -11,9 +11,10 @@ class MarkdownTableUtil {
     this.tableAlignmentLineNegRE = /^[^-:]*$/; // it is need to check to ignore empty row which is matched above RE
     // https://regex101.com/r/7BN2fR/10
     this.linePartOfTableRE = /^([^\r\n|]*)\|(([^\r\n|]*\|)+)$/;
+    // https://regex101.com/r/1UuWBJ/3
+    this.emptyLineOfTableRE = /^([^\r\n|]*)\|((\s*\|)+)$/;
 
     this.getEot = this.getEot.bind(this);
-    this.getBol = this.getBol.bind(this);
     this.getStrFromBot = this.getStrFromBot.bind(this);
     this.getStrToEot = this.getStrToEot.bind(this);
     this.isInTable = this.isInTable.bind(this);
@@ -66,14 +67,6 @@ class MarkdownTableUtil {
     return { line: eotLine, ch: lineLength };
   }
 
-  /**
-   * return the postion of the BOL(beginning of line)
-   */
-  getBol(editor) {
-    const curPos = editor.getCursor();
-    return { line: curPos.line, ch: 0 };
-  }
-
   /**
    * return strings from BOT(beginning of table) to the cursor position
    */

+ 7 - 0
src/client/js/components/PageEditor/TextAreaEditor.jsx

@@ -149,6 +149,13 @@ export default class TextAreaEditor extends AbstractEditor {
     this.replaceValue(text, this.getBolPos(), lowerPos);
   }
 
+  /**
+   * @inheritDoc
+   */
+  replaceLine(text) {
+    this.replaceValue(text, this.getBolPos(), this.getEolPos());
+  }
+
   getBolPos() {
     const currentPos = this.textarea.selectionStart;
     return this.textarea.value.lastIndexOf('\n', currentPos - 1) + 1;