yusuketk 5 лет назад
Родитель
Сommit
472dcb301a

+ 1 - 1
src/client/js/components/PageEditor/CodeMirrorEditor.jsx

@@ -667,7 +667,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
   }
 
   showLinkEditHandler() {
-    this.linkEditModal.current.show(mlu.getMarkdownLinkOrSelectedText(this.getCodeMirror()));
+    this.linkEditModal.current.show(mlu.getMarkdownLink(this.getCodeMirror()));
   }
 
   showHandsonTableHandler() {

+ 5 - 6
src/client/js/components/PageEditor/MarkdownLinkUtil.js

@@ -6,24 +6,23 @@ import Linker from '../models/Linker';
 class MarkdownLinkUtil {
 
   constructor() {
-    this.getMarkdownLinkOrSelectedText = this.getMarkdownLinkOrSelectedText.bind(this);
+    this.getMarkdownLink = this.getMarkdownLink.bind(this);
     this.isInLink = this.isInLink.bind(this);
-    this.getBeginningAndEndOfTheClosestLinkToCursor = this.getBeginningAndEndOfTheClosestLinkToCursor.bind(this);
     this.replaceFocusedMarkdownLinkWithEditor = this.replaceFocusedMarkdownLinkWithEditor.bind(this);
   }
 
   // return text as markdown link if the cursor on markdown link else return text as default label of new link.
-  getMarkdownLinkOrSelectedText(editor) {
+  getMarkdownLink(editor) {
     if (!this.isInLink(editor)) {
-      return editor.getDoc().getSelection();
+      return Linker.fromMarkdownString(editor.getDoc().getSelection());
     }
     const curPos = editor.getCursor();
-    return Linker.fromLineAndPos(editor.getDoc().getLine(curPos.line), curPos.ch)
+    return Linker.fromLineContainsLink(editor.getDoc().getLine(curPos.line), curPos.ch)
   }
 
   isInLink(editor) {
     const curPos = editor.getCursor();
-    const { beginningOfLink, endOfLink } = this.getBeginningAndEndOfTheClosestLinkToCursor(editor);
+    const { beginningOfLink, endOfLink } = Linker.getBeginningAndEndIndexOfLink(editor.getDoc().getLine(curPos.line), curPos.ch);
     return beginningOfLink >= 0 && endOfLink >= 0 && beginningOfLink <= curPos.ch && curPos.ch <= endOfLink;
   }
 

+ 104 - 0
src/client/js/models/Linker.js

@@ -0,0 +1,104 @@
+const types = {
+  markdownLink: 'mdLink',
+  growiLink: 'growiLink',
+  pukiwikiLink: 'pukiwikiLink',
+}
+
+const isApplyPukiwikiLikeLinkerPlugin = window.growiRenderer.preProcessors.some(process => process.constructor.name === 'PukiwikiLikeLinker');
+
+export default class Linker {
+
+  constructor(type, label, link) {
+    this.type = type;
+    this.label = label;
+    this.link = link;
+  }
+
+  // create a linker from string
+  static fromMarkdownString(str) {
+    // if str doesn't mean a linker, create markdown link whose label is str
+    let label=str;
+    let link='';
+    let type=types.markdownLink;
+
+    // pukiwiki
+    // https://regex101.com/r/2fNmUN/1
+    if (str.match(/^\[\[.*\]\]$/) && isApplyPukiwikiLikeLinkerPlugin) {
+      type = types.pukiwikiLink;
+      const value = str.slice(2, -2);
+      const indexOfSplit = value.lastIndexOf('>');
+      if (indexOfSplit < 0) {
+        label = value;
+        link = value;
+      }
+      label = value.slice(0, indexOfSplit);
+      link = value.slice(indexOfSplit + 1);
+    }
+    // growi
+    // https://regex101.com/r/DJfkYf/1
+    else if (str.match(/^\[\/.*\]$/)) {
+      type = types.growiLink;
+      const value = str.slice(1, -1);
+      label = value;
+      link = value;
+    }
+    // markdown
+    // https://regex101.com/r/DZCKP3/1
+    else if (str.match(/^\[.*\]\(.*\)$/)) {
+      type = types.markdownLink;
+      const value = MarkdownLink.slice(1, -1);
+      const indexOfSplit = value.lastIndexOf('](');
+      label = value.slice(0, indexOfSplit);
+      link = value.slice(indexOfSplit + 2);
+    }
+
+    return new Linker(type, label, link);
+  }
+
+  // create a linker from text with index
+  static fromLineWithIndex(line, index) {
+    const { beginningOfLink, endOfLink } = this.getBeginningAndEndIndexOfLink(line, index);
+    let linkStr = '';
+    if (beginningOfLink < 0 || endOfLink < 0) {
+     linkStr = line.substring(beginningOfLink, endOfLink);
+    }
+    return this.fromMarkdownString(linkStr);
+  }
+
+  // return beginning index and end index of the closest link to index
+  // if there is no link, return { beginningOfLink: -1, endOfLink: -1}
+  static getBeginningAndEndIndexOfLink(line, index) {
+    let beginningOfLink, endOfLink;
+
+    // growi link ('[/link]')
+    [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[/', ']');
+
+    // markdown link ('[label](link)')
+    [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[', ')', '](');
+
+    // pukiwiki link ('[[link]]')
+    if (isApplyPukiwikiLikeLinkerPlugin) {
+      [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[[', ']]');
+    }
+
+    return { beginningOfLink, endOfLink };
+  }
+
+  // return begin and end indexies as array only when index between prefix and suffix.
+  // if line doesn't contain containText, return null.
+  static getBeginningAndEndIndexWithPrefixAndSuffix(line, index, prefix, suffix, containText=null) {
+    const beginningIndex = line.lastIndexOf(prefix, index + prefix.length);
+    let startIndex = beginningIndex;
+    if (containText != null){
+      startIndex = line.indexOf(containText, beginningOfLink);
+    }
+    const endIndex = line.indexOf(suffix, startIndex);
+
+    if (beginningIndex < 0 || endIndex < 0 || startIndex < 0) {
+      return [-1, -1];
+    }
+
+    return [beginningIndex, endIndex + suffix.lengt];
+  }
+
+}