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

Merge pull request #2425 from weseek/feat/replace-perma-link

Feat/replace perma link
Yuki Takei 5 лет назад
Родитель
Сommit
bdac4ef770

+ 2 - 2
resource/locales/en_US/translation.json

@@ -208,8 +208,8 @@
     "Copy to clipboard": "Copy to clipboard",
     "Page path": "Page path",
     "Page URL": "Page URL",
-    "Parmanent link": "Parmanent link",
-    "Page path and parmanent link": "Page path and parmanent link",
+    "Permanent link": "Permanent link",
+    "Page path and permanent link": "Page path and permanent link",
     "Markdown link": "Markdown link"
   },
   "search_help": {

+ 2 - 2
resource/locales/ja_JP/translation.json

@@ -210,8 +210,8 @@
     "Copy to clipboard": "クリップボードにコピー",
     "Page path": "ページ名",
     "Page URL": "ページURL",
-    "Parmanent link": "パーマリンク",
-    "Page path and parmanent link": "ページ名とパーマリンク",
+    "Permanent link": "パーマリンク",
+    "Page path and permanent link": "ページ名とパーマリンク",
     "Markdown link": "マークダウン形式のリンク"
   },
   "search_help": {

+ 4 - 4
src/client/js/components/Page/CopyDropdown.jsx

@@ -149,22 +149,22 @@ class CopyDropdown extends React.Component {
 
             <DropdownItem divider className="my-0"></DropdownItem>
 
-            {/* Parmanent Link */}
+            {/* Permanent Link */}
             { pageId && (
               <CopyToClipboard text={permalink} onCopy={this.showToolTip}>
                 <DropdownItem className="px-3">
-                  <DropdownItemContents title={t('copy_to_clipboard.Parmanent link')} contents={permalink} />
+                  <DropdownItemContents title={t('copy_to_clipboard.Permanent link')} contents={permalink} />
                 </DropdownItem>
               </CopyToClipboard>
             )}
 
             <DropdownItem divider className="my-0"></DropdownItem>
 
-            {/* Page path + Parmanent Link */}
+            {/* Page path + Permanent Link */}
             { pageId && (
               <CopyToClipboard text={`${pagePathWithParams}\n${permalink}`} onCopy={this.showToolTip}>
                 <DropdownItem className="px-3">
-                  <DropdownItemContents title={t('copy_to_clipboard.Page path and parmanent link')} contents={<>{pagePathWithParams}<br />{permalink}</>} />
+                  <DropdownItemContents title={t('copy_to_clipboard.Page path and permanent link')} contents={<>{pagePathWithParams}<br />{permalink}</>} />
                 </DropdownItem>
               </CopyToClipboard>
             )}

+ 55 - 38
src/client/js/components/PageEditor/LinkEditModal.jsx

@@ -1,7 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import path from 'path';
 import {
   Modal,
   ModalHeader,
@@ -32,6 +31,7 @@ class LinkEditModal extends React.PureComponent {
       labelInputValue: '',
       linkerType: Linker.types.markdownLink,
       markdown: '',
+      permalink: '',
     };
 
     this.isApplyPukiwikiLikeLinkerPlugin = window.growiRenderer.preProcessors.some(process => process.constructor.name === 'PukiwikiLikeLinker');
@@ -44,17 +44,18 @@ class LinkEditModal extends React.PureComponent {
     this.handleChangeLinkInput = this.handleChangeLinkInput.bind(this);
     this.handleSelecteLinkerType = this.handleSelecteLinkerType.bind(this);
     this.toggleIsUseRelativePath = this.toggleIsUseRelativePath.bind(this);
-    this.setMarkdown = this.setMarkdown.bind(this);
     this.toggleIsUsePamanentLink = this.toggleIsUsePamanentLink.bind(this);
     this.save = this.save.bind(this);
     this.generateLink = this.generateLink.bind(this);
+    this.getPreview = this.getPreview.bind(this);
+    this.renderPreview = this.renderPreview.bind(this);
   }
 
   componentDidUpdate(prevState) {
     const { linkInputValue: prevLinkInputValue } = prevState;
     const { linkInputValue } = this.state;
     if (linkInputValue !== prevLinkInputValue) {
-      this.setMarkdown(linkInputValue);
+      this.getPreview(linkInputValue);
     }
   }
 
@@ -73,6 +74,8 @@ class LinkEditModal extends React.PureComponent {
       show: true,
       labelInputValue: label,
       linkInputValue: link,
+      isUsePermanentLink: false,
+      permalink: '',
       linkerType: type,
     });
   }
@@ -91,11 +94,18 @@ class LinkEditModal extends React.PureComponent {
     if (this.state.linkerType === Linker.types.growiLink) {
       return;
     }
-    this.setState({ isUseRelativePath: !this.state.isUseRelativePath });
+
+    // User can't use both relativePath and permalink at the same time
+    this.setState({ isUseRelativePath: !this.state.isUseRelativePath, isUsePermanentLink: false });
   }
 
   toggleIsUsePamanentLink() {
-    this.setState({ isUsePermanentLink: !this.state.isUsePermanentLink });
+    if (this.state.permalink === '' || this.state.linkerType === Linker.types.growiLink) {
+      return;
+    }
+
+    // User can't use both relativePath and permalink at the same time
+    this.setState({ isUsePermanentLink: !this.state.isUsePermanentLink, isUseRelativePath: false });
   }
 
   renderPreview() {
@@ -108,22 +118,25 @@ class LinkEditModal extends React.PureComponent {
     );
   }
 
-  async setMarkdown(path) {
+  async getPreview(path) {
     let markdown = '';
+    let permalink = '';
     try {
-      await this.props.appContainer.apiGet('/pages.get', { path }).then((res) => {
-        markdown = res.page.revision.body;
-      });
+      const res = await this.props.appContainer.apiGet('/pages.get', { path });
+      markdown = res.page.revision.body;
+      permalink = `${window.location.origin}/${res.page.id}`;
     }
     catch (err) {
       markdown = `<div class="alert alert-warning" role="alert"><strong>${err.message}</strong></div>`;
     }
-    this.setState({ markdown });
+    this.setState({ markdown, permalink });
   }
 
   handleChangeTypeahead(selected) {
     const page = selected[0];
-    this.setState({ linkInputValue: page.path });
+    if (page != null) {
+      this.setState({ linkInputValue: page.path });
+    }
   }
 
   handleChangeLabelInput(label) {
@@ -135,10 +148,12 @@ class LinkEditModal extends React.PureComponent {
   }
 
   handleSelecteLinkerType(linkerType) {
-    if (this.state.isUseRelativePath && linkerType === Linker.types.growiLink) {
-      this.toggleIsUseRelativePath();
+    let { isUseRelativePath, isUsePermanentLink } = this.state;
+    if (linkerType === Linker.types.growiLink) {
+      isUseRelativePath = false;
+      isUsePermanentLink = false;
     }
-    this.setState({ linkerType });
+    this.setState({ linkerType, isUseRelativePath, isUsePermanentLink });
   }
 
   save() {
@@ -158,23 +173,19 @@ class LinkEditModal extends React.PureComponent {
       labelInputValue,
       linkerType,
       isUseRelativePath,
+      isUsePermanentLink,
+      permalink,
     } = this.state;
 
-    let reshapedLink = linkInputValue;
-
-    if (isUseRelativePath && linkInputValue.match(/^\//)) {
-      reshapedLink = path.relative(pageContainer.state.path, linkInputValue);
-    }
-
-    if (linkerType === Linker.types.pukiwikiLink) {
-      return `[[${labelInputValue}>${reshapedLink}]]`;
-    }
-    if (linkerType === Linker.types.growiLink) {
-      return `[${reshapedLink}]`;
-    }
-    if (linkerType === Linker.types.markdownLink) {
-      return `[${labelInputValue}](${reshapedLink})`;
-    }
+    return new Linker(
+      linkerType,
+      labelInputValue,
+      linkInputValue,
+      isUseRelativePath,
+      pageContainer.state.path,
+      isUsePermanentLink,
+      permalink,
+    );
   }
 
   render() {
@@ -186,7 +197,7 @@ class LinkEditModal extends React.PureComponent {
 
         <ModalBody className="container">
           <div className="row">
-            <div className="col">
+            <div className="col-12 col-lg-6">
               <form className="form-group">
                 <div className="form-gorup my-3">
                   <label htmlFor="linkInput">Link</label>
@@ -200,14 +211,6 @@ class LinkEditModal extends React.PureComponent {
                     />
                   </div>
                 </div>
-                <div className="form-inline">
-                  <div className="custom-control custom-checkbox custom-checkbox-info">
-                    <input className="custom-control-input" id="permanentLink" type="checkbox" checked={this.state.isUsePamanentLink} />
-                    <label className="custom-control-label" htmlFor="permanentLink" onClick={this.toggleIsUsePamanentLink}>
-                      Use permanent link
-                    </label>
-                  </div>
-                </div>
               </form>
 
               <div className="d-block d-lg-none mb-3 overflow-auto">
@@ -271,6 +274,20 @@ class LinkEditModal extends React.PureComponent {
                         </label>
                       </div>
                     </div>
+                    <div className="form-inline">
+                      <div className="custom-control custom-checkbox custom-checkbox-info">
+                        <input
+                          className="custom-control-input"
+                          id="permanentLink"
+                          type="checkbox"
+                          checked={this.state.isUsePermanentLink}
+                          disabled={this.state.permalink === '' || this.state.linkerType === Linker.types.growiLink}
+                        />
+                        <label className="custom-control-label" htmlFor="permanentLink" onClick={this.toggleIsUsePamanentLink}>
+                          Use permanent link
+                        </label>
+                      </div>
+                    </div>
                   </form>
                 </div>
               </div>

+ 52 - 3
src/client/js/models/Linker.js

@@ -1,10 +1,25 @@
+import path from 'path';
+
 export default class Linker {
 
-  constructor(type, label, link) {
+  constructor(
+      type,
+      label,
+      link,
+      isUseRelativePath = false,
+      rootPath = '',
+      isUsePermanentLink = false,
+      permalink = '',
+  ) {
     this.type = type;
     this.label = label;
     this.link = link;
-    // TODO GW-3074 相対パスを利用しているかの情報も持つようにする
+    this.isUseRelativePath = isUseRelativePath;
+    this.rootPath = rootPath;
+    this.isUsePermanentLink = isUsePermanentLink;
+    this.permalink = permalink;
+
+    this.generateMarkdownText = this.generateMarkdownText.bind(this);
   }
 
   static types = {
@@ -20,6 +35,28 @@ export default class Linker {
     markdownLink: /^\[(?<label>.*)\]\((?<link>.*)\)$/, // https://regex101.com/r/DZCKP3/2
   }
 
+  generateMarkdownText() {
+    let reshapedLink = this.link;
+
+    if (this.isUseRelativePath && this.link.match(/^\//)) {
+      reshapedLink = path.relative(this.rootPath, this.link);
+    }
+    if (this.isUsePermanentLink && this.permalink != null) {
+      reshapedLink = this.permalink;
+    }
+
+    if (this.type === Linker.types.pukiwikiLink) {
+      if (this.label === reshapedLink) return `[[${reshapedLink}]]`;
+      return `[[${this.label}>${reshapedLink}]]`;
+    }
+    if (this.type === Linker.types.growiLink) {
+      return `[${reshapedLink}]`;
+    }
+    if (this.type === Linker.types.markdownLink) {
+      return `[${this.label}](${reshapedLink})`;
+    }
+  }
+
   // create an instance of Linker from string
   static fromMarkdownString(str) {
     // if str doesn't mean a linker, create a link whose label is str
@@ -50,7 +87,19 @@ export default class Linker {
       ({ label, link } = str.match(this.patterns.markdownLink).groups);
     }
 
-    return new Linker(type, label, link);
+    // TODO GW-3074 相対パスを利用しているかテキストから判定し以下の値に反映する
+    const isUseRelativePath = false;
+    const rootPath = '';
+
+    return new Linker(
+      type,
+      label,
+      link,
+      isUseRelativePath,
+      rootPath,
+      false,
+      '',
+    );
   }
 
   // create an instance of Linker from text with index