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