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

Merge branch 'feat/enable-update-link-with-link-editor-modal' into feat/replace-updated-markdown-link

yusuketk 5 лет назад
Родитель
Сommit
9061b8c1e1

+ 29 - 20
src/client/js/components/PageEditor/LinkEditModal.jsx

@@ -10,12 +10,12 @@ import {
 } from 'reactstrap';
 
 import Preview from './Preview';
-import PagePathAutoComplete from '../PagePathAutoComplete';
 
 import AppContainer from '../../services/AppContainer';
 import PageContainer from '../../services/PageContainer';
 
 import SearchTypeahead from '../SearchTypeahead';
+import Linker from '../../models/Linker';
 
 import { withUnstatedContainers } from '../UnstatedUtils';
 
@@ -30,7 +30,7 @@ class LinkEditModal extends React.PureComponent {
       isUsePermanentLink: false,
       linkInputValue: '',
       labelInputValue: '',
-      linkerType: 'mdLink',
+      linkerType: Linker.types.markdownLink,
       markdown: '',
     };
 
@@ -39,6 +39,7 @@ class LinkEditModal extends React.PureComponent {
     this.show = this.show.bind(this);
     this.hide = this.hide.bind(this);
     this.cancel = this.cancel.bind(this);
+    this.handleChangeTypeahead = this.handleChangeTypeahead.bind(this);
     this.handleChangeLabelInput = this.handleChangeLabelInput.bind(this);
     this.handleChangeLinkInput = this.handleChangeLinkInput.bind(this);
     this.handleSelecteLinkerType = this.handleSelecteLinkerType.bind(this);
@@ -57,9 +58,16 @@ class LinkEditModal extends React.PureComponent {
     }
   }
 
+  // defaultMarkdownLink is an instance of Linker
   show(defaultMarkdownLink = null) {
     // if defaultMarkdownLink is null, set default value in inputs.
-    const {type='mdLink', label='', link=''} = defaultMarkdownLink ;
+    const { label = '', link = '' } = defaultMarkdownLink;
+    let { type = Linker.types.markdownLink } = defaultMarkdownLink;
+
+    // if type of defaultMarkdownLink is pukiwikiLink when pukiwikiLikeLinker plugin is disable, change type(not change label and link)
+    if (type === Linker.types.pukiwikiLink && !this.isApplyPukiwikiLikeLinkerPlugin) {
+      type = Linker.types.markdownLink;
+    }
 
     this.setState({
       show: true,
@@ -80,7 +88,7 @@ class LinkEditModal extends React.PureComponent {
   }
 
   toggleIsUseRelativePath() {
-    if (this.state.linkerType === 'growiLink') {
+    if (this.state.linkerType === Linker.types.growiLink) {
       return;
     }
     this.setState({ isUseRelativePath: !this.state.isUseRelativePath });
@@ -100,10 +108,6 @@ class LinkEditModal extends React.PureComponent {
     );
   }
 
-  insertLinkIntoEditor() {
-    // TODO GW-2659
-  }
-
   async setMarkdown(path) {
     let markdown = '';
     try {
@@ -117,6 +121,11 @@ class LinkEditModal extends React.PureComponent {
     this.setState({ markdown });
   }
 
+  handleChangeTypeahead(selected) {
+    const page = selected[0];
+    this.setState({ linkInputValue: page.path });
+  }
+
   handleChangeLabelInput(label) {
     this.setState({ labelInputValue: label });
   }
@@ -126,7 +135,7 @@ class LinkEditModal extends React.PureComponent {
   }
 
   handleSelecteLinkerType(linkerType) {
-    if (this.state.isUseRelativePath && linkerType === 'growiLink') {
+    if (this.state.isUseRelativePath && linkerType === Linker.types.growiLink) {
       this.toggleIsUseRelativePath();
     }
     this.setState({ linkerType });
@@ -157,13 +166,13 @@ class LinkEditModal extends React.PureComponent {
       reshapedLink = path.relative(pageContainer.state.path, linkInputValue);
     }
 
-    if (linkerType === 'pukiwikiLink') {
+    if (linkerType === Linker.types.pukiwikiLink) {
       return `[[${labelInputValue}>${reshapedLink}]]`;
     }
-    if (linkerType === 'growiLink') {
+    if (linkerType === Linker.types.growiLink) {
       return `[${reshapedLink}]`;
     }
-    if (linkerType === 'mdLink') {
+    if (linkerType === Linker.types.markdownLink) {
       return `[${labelInputValue}](${reshapedLink})`;
     }
   }
@@ -211,16 +220,16 @@ class LinkEditModal extends React.PureComponent {
                     <div className="form-group btn-group d-flex" role="group" aria-label="type">
                       <button
                         type="button"
-                        name="mdLink"
-                        className={`btn btn-outline-secondary w-100 ${this.state.linkerType === 'mdLink' && 'active'}`}
+                        name={Linker.types.markdownLink}
+                        className={`btn btn-outline-secondary w-100 ${this.state.linkerType === Linker.types.markdownLink && 'active'}`}
                         onClick={e => this.handleSelecteLinkerType(e.target.name)}
                       >
                         Markdown
                       </button>
                       <button
                         type="button"
-                        name="growiLink"
-                        className={`btn btn-outline-secondary w-100 ${this.state.linkerType === 'growiLink' && 'active'}`}
+                        name={Linker.types.growiLink}
+                        className={`btn btn-outline-secondary w-100 ${this.state.linkerType === Linker.types.growiLink && 'active'}`}
                         onClick={e => this.handleSelecteLinkerType(e.target.name)}
                       >
                         Growi Original
@@ -228,8 +237,8 @@ class LinkEditModal extends React.PureComponent {
                       {this.isApplyPukiwikiLikeLinkerPlugin && (
                         <button
                           type="button"
-                          name="pukiwikiLink"
-                          className={`btn btn-outline-secondary w-100 ${this.state.linkerType === 'pukiwikiLink' && 'active'}`}
+                          name={Linker.types.pukiwikiLink}
+                          className={`btn btn-outline-secondary w-100 ${this.state.linkerType === Linker.types.pukiwikiLink && 'active'}`}
                           onClick={e => this.handleSelecteLinkerType(e.target.name)}
                         >
                           Pukiwiki
@@ -245,7 +254,7 @@ class LinkEditModal extends React.PureComponent {
                         id="label"
                         value={this.state.labelInputValue}
                         onChange={e => this.handleChangeLabelInput(e.target.value)}
-                        disabled={this.state.linkerType === 'growiLink'}
+                        disabled={this.state.linkerType === Linker.types.growiLink}
                       />
                     </div>
                     <div className="form-inline">
@@ -255,7 +264,7 @@ class LinkEditModal extends React.PureComponent {
                           id="relativePath"
                           type="checkbox"
                           checked={this.state.isUseRelativePath}
-                          disabled={this.state.linkerType === 'growiLink'}
+                          disabled={this.state.linkerType === Linker.types.growiLink}
                         />
                         <label className="custom-control-label" htmlFor="relativePath" onClick={this.toggleIsUseRelativePath}>
                           Use relative path

+ 4 - 4
src/client/js/components/PageEditor/MarkdownLinkUtil.js

@@ -1,4 +1,4 @@
-import Linker from '../models/Linker';
+import Linker from '../../models/Linker';
 
 /**
  * Utility for markdown link
@@ -11,19 +11,19 @@ class MarkdownLinkUtil {
     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.
+  // return an instance of Linker from cursor position or selected text.
   getMarkdownLink(editor) {
     if (!this.isInLink(editor)) {
       return Linker.fromMarkdownString(editor.getDoc().getSelection());
     }
     const curPos = editor.getCursor();
-    return Linker.fromLineContainsLink(editor.getDoc().getLine(curPos.line), curPos.ch)
+    return Linker.fromLineWithIndex(editor.getDoc().getLine(curPos.line), curPos.ch);
   }
 
   isInLink(editor) {
     const curPos = editor.getCursor();
     const { beginningOfLink, endOfLink } = Linker.getBeginningAndEndIndexOfLink(editor.getDoc().getLine(curPos.line), curPos.ch);
-    return beginningOfLink >= 0 && endOfLink >= 0 && beginningOfLink <= curPos.ch && curPos.ch <= endOfLink;
+    return beginningOfLink >= 0 && endOfLink >= 0;
   }
 
   replaceFocusedMarkdownLinkWithEditor(editor, linkStr) {

+ 51 - 43
src/client/js/models/Linker.js

@@ -1,43 +1,44 @@
-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;
+    // TODO GW-3074 相対パスを利用しているかの情報も持つようにする
+  }
+
+  static types = {
+    markdownLink: 'mdLink',
+    growiLink: 'growiLink',
+    pukiwikiLink: 'pukiwikiLink',
   }
 
-  // create a linker from string
+  // create an instance of 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;
+    // if str doesn't mean a linker, create a link whose label is str
+    let label = str;
+    let link = '';
+    let type = this.types.markdownLink;
 
     // pukiwiki
     // https://regex101.com/r/2fNmUN/1
-    if (str.match(/^\[\[.*\]\]$/) && isApplyPukiwikiLikeLinkerPlugin) {
-      type = types.pukiwikiLink;
+    if (str.match(/^\[\[.*\]\]$/)) {
+      type = this.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);
+      else {
+        label = value.slice(0, indexOfSplit);
+        link = value.slice(indexOfSplit + 1);
+      }
     }
     // growi
     // https://regex101.com/r/DJfkYf/1
     else if (str.match(/^\[\/.*\]$/)) {
-      type = types.growiLink;
+      type = this.types.growiLink;
       const value = str.slice(1, -1);
       label = value;
       link = value;
@@ -45,8 +46,8 @@ export default class Linker {
     // markdown
     // https://regex101.com/r/DZCKP3/1
     else if (str.match(/^\[.*\]\(.*\)$/)) {
-      type = types.markdownLink;
-      const value = MarkdownLink.slice(1, -1);
+      type = this.types.markdownLink;
+      const value = str.slice(1, -1);
       const indexOfSplit = value.lastIndexOf('](');
       label = value.slice(0, indexOfSplit);
       link = value.slice(indexOfSplit + 2);
@@ -55,50 +56,57 @@ export default class Linker {
     return new Linker(type, label, link);
   }
 
-  // create a linker from text with index
+  // create an instance of Linker from text with index
   static fromLineWithIndex(line, index) {
     const { beginningOfLink, endOfLink } = this.getBeginningAndEndIndexOfLink(line, index);
+    // if index is in a link, extract it from line
     let linkStr = '';
-    if (beginningOfLink < 0 || endOfLink < 0) {
-     linkStr = line.substring(beginningOfLink, endOfLink);
+    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}
+  // return beginning and end indexies of link
+  // if index is not in a link, return { beginningOfLink: -1, endOfLink: -1 }
   static getBeginningAndEndIndexOfLink(line, index) {
-    let beginningOfLink, endOfLink;
+    let beginningOfLink;
+    let endOfLink;
 
+    // pukiwiki link ('[[link]]')
+    [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[[', ']]');
+
+    // if index is not in a pukiwiki link
     // growi link ('[/link]')
-    [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[/', ']');
+    if (beginningOfLink < 0 || endOfLink < 0 || beginningOfLink > index || endOfLink < index) {
+      [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[/', ']');
+    }
 
+    // and if index is not in a growi link
     // markdown link ('[label](link)')
-    [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[', ')', '](');
+    if (beginningOfLink < 0 || endOfLink < 0 || beginningOfLink > index || endOfLink < index) {
+      [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[', ')', '](');
+    }
 
-    // pukiwiki link ('[[link]]')
-    if (isApplyPukiwikiLikeLinkerPlugin) {
-      [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[[', ']]');
+    // and if index is not in a markdown link
+    // return { beginningOfLink: -1, endOfLink: -1 }
+    if (beginningOfLink < 0 || endOfLink < 0 || beginningOfLink > index || endOfLink < index) {
+      [beginningOfLink, endOfLink] = [-1, -1];
     }
 
     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);
+  // return begin and end indexies as array only when index is between prefix and suffix and link contains containText.
+  static getBeginningAndEndIndexWithPrefixAndSuffix(line, index, prefix, suffix, containText = '') {
+    const beginningIndex = line.lastIndexOf(prefix, index);
+    const IndexOfContainText = line.indexOf(containText, beginningIndex + prefix.length);
+    const endIndex = line.indexOf(suffix, IndexOfContainText + containText.length);
 
-    if (beginningIndex < 0 || endIndex < 0 || startIndex < 0) {
+    if (beginningIndex < 0 || IndexOfContainText < 0 || endIndex < 0) {
       return [-1, -1];
     }
-
-    return [beginningIndex, endIndex + suffix.lengt];
+    return [beginningIndex, endIndex + suffix.length];
   }
 
 }