From b37a789f636004c23b55ce92aaa51bc21e1f9be7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com>
Date: Wed, 28 Nov 2018 11:05:41 +0800
Subject: [PATCH] add tui.editor (#1374)

---
 package.json                                  |   3 +-
 .../MarkdownEditor/defaultOptions.js          |  31 ++++
 src/components/MarkdownEditor/index.vue       | 171 +++++++++---------
 src/views/components-demo/markdown.vue        |  63 +++++--
 4 files changed, 166 insertions(+), 102 deletions(-)
 create mode 100644 src/components/MarkdownEditor/defaultOptions.js

diff --git a/package.json b/package.json
index 36045c4d..e02be220 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,6 @@
     "echarts": "4.1.0",
     "element-ui": "2.4.6",
     "file-saver": "1.3.8",
-    "font-awesome": "4.7.0",
     "js-cookie": "2.2.0",
     "jsonlint": "1.6.3",
     "jszip": "3.1.5",
@@ -52,8 +51,8 @@
     "nprogress": "0.2.0",
     "screenfull": "3.3.3",
     "showdown": "1.8.6",
-    "simplemde": "1.11.2",
     "sortablejs": "1.7.0",
+    "tui-editor": "1.2.7",
     "vue": "2.5.17",
     "vue-count-to": "1.0.13",
     "vue-i18n": "7.3.2",
diff --git a/src/components/MarkdownEditor/defaultOptions.js b/src/components/MarkdownEditor/defaultOptions.js
new file mode 100644
index 00000000..303aa13d
--- /dev/null
+++ b/src/components/MarkdownEditor/defaultOptions.js
@@ -0,0 +1,31 @@
+// doc: https://nhnent.github.io/tui.editor/api/latest/ToastUIEditor.html#ToastUIEditor
+export default {
+  minHeight: '200px',
+  previewStyle: 'vertical',
+  useCommandShortcut: true,
+  useDefaultHTMLSanitizer: true,
+  usageStatistics: false,
+  hideModeSwitch: false,
+  toolbarItems: [
+    'heading',
+    'bold',
+    'italic',
+    'strike',
+    'divider',
+    'hr',
+    'quote',
+    'divider',
+    'ul',
+    'ol',
+    'task',
+    'indent',
+    'outdent',
+    'divider',
+    'table',
+    'image',
+    'link',
+    'divider',
+    'code',
+    'codeblock'
+  ]
+}
diff --git a/src/components/MarkdownEditor/index.vue b/src/components/MarkdownEditor/index.vue
index 9847668a..4a6d8b0f 100644
--- a/src/components/MarkdownEditor/index.vue
+++ b/src/components/MarkdownEditor/index.vue
@@ -1,16 +1,18 @@
 <template>
-  <div :style="{height:height+'px',zIndex:zIndex}" class="simplemde-container">
-    <textarea :id="id"/>
-  </div>
+  <div :id="id"/>
 </template>
 
 <script>
-import 'font-awesome/css/font-awesome.min.css'
-import 'simplemde/dist/simplemde.min.css'
-import SimpleMDE from 'simplemde'
+// deps for editor
+import 'codemirror/lib/codemirror.css' // codemirror
+import 'tui-editor/dist/tui-editor.css' // editor ui
+import 'tui-editor/dist/tui-editor-contents.css' // editor content
+
+import Editor from 'tui-editor'
+import defaultOptions from './defaultOptions'
 
 export default {
-  name: 'SimplemdeMd',
+  name: 'MarddownEditor',
   props: {
     value: {
       type: String,
@@ -19,105 +21,98 @@ export default {
     id: {
       type: String,
       required: false,
-      default: 'markdown-editor-' + +new Date()
+      default() {
+        return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
+      }
     },
-    autofocus: {
-      type: Boolean,
-      default: false
+    options: {
+      type: Object,
+      default() {
+        return defaultOptions
+      }
     },
-    placeholder: {
+    mode: {
       type: String,
-      default: ''
+      default: 'markdown'
     },
     height: {
-      type: Number,
-      default: 150
-    },
-    zIndex: {
-      type: Number,
-      default: 10
+      type: String,
+      required: false,
+      default: '300px'
     },
-    toolbar: {
-      type: Array,
-      default: function() {
-        return []
-      }
+    language: {
+      type: String,
+      required: false,
+      default: 'en_US' // https://github.com/nhnent/tui.editor/tree/master/src/js/langs
     }
   },
   data() {
     return {
-      simplemde: null,
-      hasChange: false
+      editor: null
+    }
+  },
+  computed: {
+    editorOptions() {
+      const options = Object.assign({}, defaultOptions, this.options)
+      options.initialEditType = this.mode
+      options.height = this.height
+      options.language = this.language
+      return options
     }
   },
   watch: {
-    value(val) {
-      if (val === this.simplemde.value() && !this.hasChange) return
-      this.simplemde.value(val)
+    value(newValue, preValue) {
+      if (newValue !== preValue && newValue !== this.editor.getValue()) {
+        this.editor.setValue(newValue)
+      }
+    },
+    language(val) {
+      this.destroyEditor()
+      this.initEditor()
+    },
+    height(newValue) {
+      this.editor.height(newValue)
+    },
+    mode(newValue) {
+      this.editor.changeMode(newValue)
     }
   },
   mounted() {
-    this.simplemde = new SimpleMDE({
-      element: document.getElementById(this.id),
-      autoDownloadFontAwesome: false,
-      autofocus: this.autofocus,
-      toolbar: this.toolbar.length > 0 ? this.toolbar : undefined,
-      spellChecker: false,
-      insertTexts: {
-        link: ['[', ']( )']
-      },
-      // hideIcons: ['guide', 'heading', 'quote', 'image', 'preview', 'side-by-side', 'fullscreen'],
-      placeholder: this.placeholder
-    })
-    if (this.value) {
-      this.simplemde.value(this.value)
-    }
-    this.simplemde.codemirror.on('change', () => {
-      if (this.hasChange) {
-        this.hasChange = true
-      }
-      this.$emit('input', this.simplemde.value())
-    })
+    this.initEditor()
   },
   destroyed() {
-    this.simplemde.toTextArea()
-    this.simplemde = null
+    this.destroyEditor()
+  },
+  methods: {
+    initEditor() {
+      this.editor = new Editor({
+        el: document.getElementById(this.id),
+        ...this.editorOptions
+      })
+      if (this.value) {
+        this.editor.setValue(this.value)
+      }
+      this.editor.on('change', () => {
+        this.$emit('input', this.editor.getValue())
+      })
+    },
+    destroyEditor() {
+      if (!this.editor) return
+      this.editor.off('change')
+      this.editor.remove()
+    },
+    setValue(value) {
+      this.editor.setValue(value)
+    },
+    getValue() {
+      return this.editor.getValue()
+    },
+    setHtml(value) {
+      this.editor.setHtml(value)
+    },
+    getHtml() {
+      return this.editor.getHtml()
+    }
   }
 }
 </script>
-
-<style scoped>
-.simplemde-container>>>.CodeMirror {
-  min-height: 150px;
-  line-height: 20px;
-}
-
-.simplemde-container>>>.CodeMirror-scroll {
-  min-height: 150px;
-}
-
-.simplemde-container>>>.CodeMirror-code {
-  padding-bottom: 40px;
-}
-
-.simplemde-container>>>.editor-statusbar {
-  display: none;
-}
-
-.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-link {
-  color: #1890ff;
-}
-
-.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-string.cm-url {
-  color: #2d3b4d;
-}
-
-.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url {
-  padding: 0 2px;
-  color: #E61E1E;
-}
-.simplemde-container >>> .editor-toolbar.fullscreen,
-.simplemde-container >>> .CodeMirror-fullscreen {
-  z-index: 1003;
-}
-</style>
diff --git a/src/views/components-demo/markdown.vue b/src/views/components-demo/markdown.vue
index f60911d0..5fb39569 100644
--- a/src/views/components-demo/markdown.vue
+++ b/src/views/components-demo/markdown.vue
@@ -1,15 +1,40 @@
 <template>
   <div class="components-container">
+
     <code>Markdown is based on
-      <a href="https://github.com/sparksuite/simplemde-markdown-editor" target="_blank">simplemde-markdown-editor</a> ,Simply encapsulated in Vue.
+      <a href="https://github.com/nhnent/tui.editor" target="_blank">tui.editor</a> ,Simply encapsulated in Vue.
       <a target="_blank" href="https://juejin.im/post/593121aa0ce4630057f70d35#heading-15">
         相关文章 </a>
     </code>
+
+    <div class="editor-container">
+      <el-tag class="tag-title">Basic:</el-tag>
+      <markdown-editor v-model="content" height="300px"/>
+    </div>
+
+    <div class="editor-container">
+      <el-tag class="tag-title">Markdown Mode:</el-tag>
+      <markdown-editor ref="markdownEditor" v-model="content" :options="{hideModeSwitch:true,previewStyle:'tab'}" height="200px"/>
+    </div>
+
+    <div class="editor-container">
+      <el-tag class="tag-title">Customize Toolbar:</el-tag>
+      <markdown-editor
+        ref="markdownEditor"
+        v-model="content"
+        :options="{ toolbarItems: ['heading','bold','italic']}"
+      />
+    </div>
+
     <div class="editor-container">
-      <markdown-editor id="contentEditor" ref="contentEditor" v-model="content" :height="300" :z-index="20"/>
+      <el-tag class="tag-title">I18n:</el-tag>
+      <el-alert :closable="false" title="You can change the language of the admin system to see the effect" type="success"/>
+      <markdown-editor v-model="content" :language="language" height="300px"/>
     </div>
-    <el-button style="margin-top:80px;" type="primary" icon="el-icon-document" @click="markdown2Html">To HTML</el-button>
+
+    <el-button style="margin-top:80px;" type="primary" icon="el-icon-document" @click="getHtml">Get HTML</el-button>
     <div v-html="html"/>
+
   </div>
 </template>
 
@@ -17,32 +42,46 @@
 import MarkdownEditor from '@/components/MarkdownEditor'
 
 const content = `
-**this is test**
+**This is test**
 
 * vue
 * element
 * webpack
 
-## Simplemde
 `
-
 export default {
   name: 'MarkdownDemo',
   components: { MarkdownEditor },
   data() {
     return {
       content: content,
-      html: ''
+      html: '',
+      languageTypeList: {
+        'en': 'en_US',
+        'zh': 'zh_CN',
+        'es': 'es_ES'
+      }
+    }
+  },
+  computed: {
+    language() {
+      return this.languageTypeList[this.$store.getters.language]
     }
   },
   methods: {
-    markdown2Html() {
-      import('showdown').then(showdown => {
-        const converter = new showdown.Converter()
-        this.html = converter.makeHtml(this.content)
-      })
+    getHtml() {
+      this.html = this.$refs.markdownEditor.getHtml()
+      console.log(this.html)
     }
   }
 }
 </script>
 
+<style scoped>
+.editor-container{
+  margin-bottom: 30px;
+}
+.tag-title{
+  margin-bottom: 5px;
+}
+</style>
-- 
GitLab