2020-02-11 17:51:04 +08:00
|
|
|
<template>
|
2020-05-02 11:50:26 +08:00
|
|
|
<div id="app" class="container">
|
|
|
|
<el-container>
|
|
|
|
<el-header class="top editor__header">
|
|
|
|
<editor-header
|
2020-05-02 17:40:03 +08:00
|
|
|
@uploaded="uploaded"
|
2020-05-02 12:33:44 +08:00
|
|
|
@cssChanged="cssChanged"
|
2020-05-02 11:50:26 +08:00
|
|
|
@showBox="showBox = !showBox"
|
|
|
|
@showAboutDialog="aboutDialogVisible = true"
|
|
|
|
@showDialogForm="dialogFormVisible = true"
|
|
|
|
/>
|
|
|
|
</el-header>
|
|
|
|
<el-main class="main-body">
|
|
|
|
<el-row :gutter="10" class="main-section">
|
|
|
|
<el-col :span="12">
|
|
|
|
<textarea id="editor" type="textarea" placeholder="Your markdown text here." v-model="source">
|
|
|
|
</textarea>
|
|
|
|
</el-col>
|
|
|
|
<el-col :span="12" class="preview-wrapper" id="preview">
|
|
|
|
<section id="output-wrapper">
|
|
|
|
<div class="preview" contenteditable="true">
|
|
|
|
<section id="output" v-html="output">
|
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
</section>
|
|
|
|
</el-col>
|
|
|
|
<transition name="custom-classes-transition" enter-active-class="animated bounceInRight">
|
|
|
|
<el-col id="cssBox" :span="12" v-show="showBox">
|
|
|
|
<textarea id="cssEditor" type="textarea" placeholder="Your custom css here.">
|
|
|
|
</textarea>
|
|
|
|
</el-col>
|
|
|
|
</transition>
|
|
|
|
</el-row>
|
|
|
|
</el-main>
|
|
|
|
</el-container>
|
|
|
|
<about-dialog :aboutDialogVisible="aboutDialogVisible"
|
|
|
|
@close="aboutDialogVisible = false" />
|
|
|
|
<insert-form-dialog :dialogFormVisible="dialogFormVisible"
|
|
|
|
@close="dialogFormVisible = false" />
|
|
|
|
</div>
|
2020-02-11 17:51:04 +08:00
|
|
|
</template>
|
|
|
|
<script>
|
2020-05-02 12:33:44 +08:00
|
|
|
import CodeMirror from 'codemirror/lib/codemirror'
|
|
|
|
|
|
|
|
import 'codemirror/mode/css/css'
|
|
|
|
import 'codemirror/mode/markdown/markdown'
|
|
|
|
import 'codemirror/addon/edit/matchbrackets'
|
|
|
|
import 'codemirror/addon/selection/active-line'
|
|
|
|
|
|
|
|
import 'codemirror/addon/hint/show-hint.js'
|
|
|
|
import 'codemirror/addon/hint/css-hint.js'
|
|
|
|
import '../scripts/format.js'
|
|
|
|
|
|
|
|
import fileApi from '../api/file';
|
|
|
|
import editorHeader from './codeMirror/header';
|
|
|
|
import aboutDialog from './codeMirror/aboutDialog';
|
|
|
|
import insertFormDialog from './codeMirror/insertForm';
|
|
|
|
import {
|
|
|
|
setFontSize,
|
|
|
|
css2json,
|
|
|
|
customCssWithTemplate,
|
2020-05-01 21:30:25 +08:00
|
|
|
saveEditorContent,
|
2020-05-02 11:50:26 +08:00
|
|
|
isImageIllegal
|
2020-05-02 12:33:44 +08:00
|
|
|
} from '../scripts/util'
|
|
|
|
|
|
|
|
require('codemirror/mode/javascript/javascript')
|
|
|
|
import '../scripts/closebrackets'
|
|
|
|
import $ from 'jquery'
|
2020-05-03 10:26:26 +08:00
|
|
|
require('../scripts/google-code-prettify/prettify.js')
|
2020-05-02 12:33:44 +08:00
|
|
|
import config from '../scripts/config'
|
|
|
|
import {mapState, mapMutations} from 'vuex';
|
|
|
|
export default {
|
2020-05-01 21:30:25 +08:00
|
|
|
data() {
|
2020-05-02 11:50:26 +08:00
|
|
|
return {
|
|
|
|
config: config,
|
|
|
|
showBox: false,
|
|
|
|
aboutDialogVisible: false,
|
|
|
|
dialogFormVisible: false,
|
|
|
|
timeout: null,
|
|
|
|
source: ''
|
|
|
|
}
|
2020-02-11 17:51:04 +08:00
|
|
|
},
|
2020-05-01 21:30:25 +08:00
|
|
|
components: {
|
2020-05-02 11:50:26 +08:00
|
|
|
editorHeader, aboutDialog, insertFormDialog
|
2020-02-11 17:51:04 +08:00
|
|
|
},
|
2020-05-01 21:30:25 +08:00
|
|
|
computed: {
|
|
|
|
...mapState({
|
|
|
|
wxRenderer: state=> state.wxRenderer,
|
|
|
|
output: state=> state.output,
|
|
|
|
editor: state=> state.editor,
|
|
|
|
cssEditor: state=> state.cssEditor,
|
2020-05-02 12:33:44 +08:00
|
|
|
currentSize: state=> state.currentSize,
|
|
|
|
currentColor: state=> state.currentColor,
|
2020-05-02 11:50:26 +08:00
|
|
|
html: state=> state.html
|
2020-02-11 17:51:04 +08:00
|
|
|
})
|
|
|
|
},
|
2020-05-01 21:30:25 +08:00
|
|
|
created() {
|
|
|
|
this.initEditorState()
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.initEditor()
|
|
|
|
this.initCssEditor()
|
|
|
|
this.editorRefresh()
|
2020-02-11 17:51:04 +08:00
|
|
|
})
|
|
|
|
},
|
2020-05-01 21:30:25 +08:00
|
|
|
methods: {
|
|
|
|
initEditor() {
|
|
|
|
this.initEditorEntity();
|
|
|
|
this.editor.on('change', (cm, e) => {
|
|
|
|
this.editorRefresh()
|
2020-05-03 10:26:26 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
PR.prettyPrint()
|
|
|
|
}, 300);
|
2020-05-01 21:30:25 +08:00
|
|
|
saveEditorContent(this.editor, '__editor_content')
|
|
|
|
});
|
2020-02-11 17:51:04 +08:00
|
|
|
|
2020-05-01 21:30:25 +08:00
|
|
|
// 粘贴上传图片并插入
|
|
|
|
this.editor.on('paste', (cm, e) => {
|
|
|
|
if (!(e.clipboardData && e.clipboardData.items)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for (let i = 0, len = e.clipboardData.items.length; i < len; ++i) {
|
|
|
|
let item = e.clipboardData.items[i]
|
|
|
|
if (item.kind === 'file') {
|
|
|
|
const pasteFile = item.getAsFile()
|
2020-05-02 11:50:26 +08:00
|
|
|
const checkImageResult = isImageIllegal(pasteFile);
|
2020-02-11 17:51:04 +08:00
|
|
|
|
2020-05-01 21:30:25 +08:00
|
|
|
if (checkImageResult) {
|
|
|
|
this.$message({
|
|
|
|
showClose: true,
|
|
|
|
message: checkImageResult,
|
|
|
|
type: 'error'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let data = new FormData()
|
|
|
|
data.append('file', pasteFile)
|
|
|
|
|
|
|
|
fileApi.fileUpload(data).then(res => {
|
2020-05-02 16:28:00 +08:00
|
|
|
this.uploaded(res)
|
2020-05-01 21:30:25 +08:00
|
|
|
}).catch(err => {
|
|
|
|
console.log(err.message)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
initCssEditor() {
|
|
|
|
this.initCssEditorEntity();
|
|
|
|
// 自动提示
|
|
|
|
this.cssEditor.on('keyup', (cm, e) => {
|
|
|
|
if ((e.keyCode >= 65 && e.keyCode <= 90) || e.keyCode === 189) {
|
|
|
|
cm.showHint(e)
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.cssEditor.on('update', (instance) => {
|
|
|
|
this.cssChanged()
|
|
|
|
saveEditorContent(this.cssEditor, '__css_content')
|
|
|
|
})
|
|
|
|
},
|
2020-05-02 12:33:44 +08:00
|
|
|
cssChanged() {
|
|
|
|
let json = css2json(this.cssEditor.getValue(0))
|
|
|
|
let theme = setFontSize(this.currentSize.replace('px', ''))
|
|
|
|
|
|
|
|
theme = customCssWithTemplate(json, this.currentColor, theme)
|
|
|
|
this.setWxRendererOptions({
|
|
|
|
theme: theme
|
|
|
|
});
|
|
|
|
this.editorRefresh()
|
|
|
|
},
|
2020-05-03 10:26:26 +08:00
|
|
|
onTextareaChange() {
|
|
|
|
console.log('change');
|
|
|
|
},
|
2020-05-01 21:30:25 +08:00
|
|
|
// 图片上传结束
|
|
|
|
uploaded(response, file, fileList) {
|
2020-05-02 17:40:03 +08:00
|
|
|
if (response) {
|
|
|
|
if (response.success) {
|
|
|
|
// 上传成功,获取光标
|
|
|
|
const cursor = this.editor.getCursor()
|
|
|
|
const imageUrl = response.data
|
|
|
|
const markdownImage = `![](${imageUrl})`
|
|
|
|
// 将 Markdown 形式的 URL 插入编辑框光标所在位置
|
|
|
|
this.editor.replaceSelection(`\n${markdownImage}\n`, cursor)
|
|
|
|
this.$message({
|
|
|
|
showClose: true,
|
|
|
|
message: '图片插入成功',
|
|
|
|
type: 'success'
|
|
|
|
})
|
|
|
|
this.editorRefresh()
|
|
|
|
} else {
|
|
|
|
// 上传失败
|
|
|
|
this.$message({
|
|
|
|
showClose: true,
|
|
|
|
message: response.message,
|
|
|
|
type: 'error'
|
|
|
|
})
|
|
|
|
}
|
2020-05-01 21:30:25 +08:00
|
|
|
} else {
|
|
|
|
this.$message({
|
|
|
|
showClose: true,
|
2020-05-02 17:40:03 +08:00
|
|
|
message: '上传图片未知异常',
|
2020-05-01 21:30:25 +08:00
|
|
|
type: 'error'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// 左右栏同步滚动
|
|
|
|
leftAndRightScroll() {
|
|
|
|
$('div.CodeMirror-scroll, #preview').on('scroll', function callback() {
|
|
|
|
clearTimeout(this.timeout)
|
2020-02-13 21:50:27 +08:00
|
|
|
|
2020-05-01 21:30:25 +08:00
|
|
|
let source = $(this)
|
|
|
|
let target = $(source.is('#preview') ? 'div.CodeMirror-scroll' : '#preview')
|
2020-02-13 21:50:27 +08:00
|
|
|
|
2020-05-01 21:30:25 +08:00
|
|
|
target.off('scroll')
|
2020-02-13 21:50:27 +08:00
|
|
|
|
2020-05-01 21:30:25 +08:00
|
|
|
let source0 = source[0]
|
|
|
|
let target0 = target[0]
|
2020-02-13 21:50:27 +08:00
|
|
|
|
2020-05-01 21:30:25 +08:00
|
|
|
let percentage = source0.scrollTop / (source0.scrollHeight - source0.offsetHeight)
|
|
|
|
let height = percentage * (target0.scrollHeight - target0.offsetHeight)
|
|
|
|
target0.scrollTo(0, height)
|
2020-02-13 21:50:27 +08:00
|
|
|
|
2020-05-01 21:30:25 +08:00
|
|
|
this.timeout = setTimeout(() => {
|
|
|
|
target.on('scroll', callback)
|
|
|
|
}, 100)
|
|
|
|
})
|
|
|
|
},
|
2020-05-02 12:33:44 +08:00
|
|
|
...mapMutations(['initEditorState', 'initEditorEntity', 'setWxRendererOptions',
|
|
|
|
'editorRefresh', 'initCssEditorEntity'])
|
2020-05-01 21:30:25 +08:00
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.leftAndRightScroll()
|
2020-05-03 10:26:26 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
PR.prettyPrint()
|
|
|
|
}, 300);
|
2020-02-11 17:51:04 +08:00
|
|
|
}
|
2020-05-02 11:50:26 +08:00
|
|
|
}
|
2020-05-01 21:30:25 +08:00
|
|
|
|
2020-02-11 17:51:04 +08:00
|
|
|
</script>
|
2020-05-01 22:35:39 +08:00
|
|
|
<style lang="less" scoped>
|
2020-05-03 10:26:26 +08:00
|
|
|
@import url('../scripts/google-code-prettify/prettify.css');
|
2020-05-02 11:50:26 +08:00
|
|
|
.main-body {
|
|
|
|
padding-top: 0;
|
2020-05-01 22:35:39 +08:00
|
|
|
}
|
2020-02-11 17:51:04 +08:00
|
|
|
</style>
|