2021-06-30 21:21:54 +08:00

344 lines
12 KiB
JavaScript
Vendored

import marked from '../../config/marked';
import common from '../../mixins/common';
export default {
name: 'markdown-simple',
mixins: [common],
data() {
return {
textareaHeight: this.height
};
},
mounted() {
this.init();
},
methods: {
init() {
this.currentValue = this.value;
this.themeName = this.theme;
this.preview = this.isPreview;
if (this.isPreview) {
return;
}
setTimeout(() => {
const textarea = this.$refs.textarea;
textarea.focus();
textarea.addEventListener('keydown', e => {
if (e.keyCode === 83) {
if (e.metaKey || e.ctrlKey) {
e.preventDefault();
this.handleSave();
}
}
});
textarea.addEventListener('paste', this.handlePaste);
if (this.autoSave) {
this.timerId = setInterval(() => {
this.handleSave();
}, this.interval);
}
this.$emit('on-ready',{
vm:this,
insertContent:this.insertContent
})
}, 20);
},
insertContent(initStr) {
// 插入文本
this.lastInsert = initStr;
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
const lastFourCharts = this.currentValue.substring(
point - 4,
point
);
if (
lastChart !== '\n' &&
this.currentValue !== '' &&
lastFourCharts !== ' '
) {
const str = '\n' + initStr;
this.insertAfterText(str);
} else {
this.insertAfterText(initStr);
}
},
getCursortPosition() {
// 获取光标位置
const textDom = this.$refs.textarea;
let cursorPos = 0;
if (document.selection) {
textDom.focus();
let selectRange = document.selection.createRange();
selectRange.moveStart('character', -this.currentValue.length);
cursorPos = selectRange.text.length;
} else if (
textDom.selectionStart ||
parseInt(textDom.selectionStart, 0) === 0
) {
cursorPos = textDom.selectionStart;
}
return cursorPos;
},
insertAfterText(value) {
// 插入文本
const textDom = this.$refs.textarea;
let selectRange;
if (document.selection) {
textDom.focus();
selectRange = document.selection.createRange();
selectRange.text = value;
textDom.focus();
} else if (
textDom.selectionStart ||
parseInt(textDom.selectionStart, 0) === 0
) {
const startPos = textDom.selectionStart;
const endPos = textDom.selectionEnd;
const scrollTop = textDom.scrollTop;
textDom.value =
textDom.value.substring(0, startPos) +
value +
textDom.value.substring(endPos, textDom.value.length);
textDom.focus();
textDom.selectionStart = startPos + value.length;
textDom.selectionEnd = startPos + value.length;
textDom.scrollTop = scrollTop;
} else {
textDom.value += value;
textDom.focus();
}
this.$set(this, 'currentValue', textDom.value);
},
setCaretPosition(position) {
// 设置光标位置
const textDom = this.$refs.textarea;
if (textDom.setSelectionRange) {
textDom.focus();
textDom.setSelectionRange(position, position);
} else if (textDom.createTextRange) {
let range = textDom.createTextRange();
range.collapse(true);
range.moveEnd('character', position);
range.moveStart('character', position);
range.select();
}
},
insertQuote() {
// 引用
this.insertContent('\n> ');
},
insertUl() {
// 无需列表
this.insertContent('- ');
},
insertOl() {
// 有序列表
this.insertContent('1. ');
},
insertFinished() {
// 已完成列表
this.insertContent('- [x] ');
},
insertNotFinished() {
// 未完成列表
this.insertContent('- [ ] ');
},
insertCode() {
// 插入code
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('\n```\n\n```');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 5);
} else {
this.setCaretPosition(point + 5);
}
},
insertStrong() {
// 粗体
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('****');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 2);
} else {
this.setCaretPosition(point + 2);
}
},
insertItalic() {
// 斜体
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('**');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 1);
} else {
this.setCaretPosition(point + 1);
}
},
insertBg() {
// 背景色
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('====');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 5);
} else {
this.setCaretPosition(point + 5);
}
},
insertUnderline() {
// 下划线
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('<u></u>');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 3);
} else {
this.setCaretPosition(point + 5);
}
},
insertOverline() {
// overline
const point = this.getCursortPosition();
const lastChart = this.currentValue.substring(point - 1, point);
this.insertContent('~~~~');
if (lastChart !== '\n' && this.currentValue !== '') {
this.setCaretPosition(point + 2);
} else {
this.setCaretPosition(point + 2);
}
},
insertTitle(level) {
// 插入标题
const titleLevel = {
1: '# ',
2: '## ',
3: '### ',
4: '#### ',
5: '##### ',
6: '###### '
};
this.insertContent(titleLevel[level]);
},
tab(e) {
// 屏蔽teatarea tab默认事件
this.insertContent(' ', this);
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
},
insertLine() {
// 插入分割线
this.insertContent('\n----\n');
},
enter() {
// 回车事件
const {lastInsert} = this;
const list = ['- ', '1. ', '- [ ] ', '- [x] '];
if (list.includes(lastInsert)) {
this.insertContent(lastInsert);
}
},
onDelete() {
// 删除时,以回车为界分割,如果数组最后一个元素为''时,将行一次插入的共嗯那个置为空,避免回车时再次插入
const lines = this.currentValue.split('\n');
if (lines[lines.length - 1] === '') {
this.lastInsert = '';
}
},
handlePaste(e) {
// 粘贴图片
const {clipboardData = {}} = e;
const {types = [], items} = clipboardData;
let item = null;
for (let i = 0; i < types.length; i++) {
if (types[i] === 'Files') {
item = items[i];
break;
}
}
if (item) {
const file = item.getAsFile();
if (/image/gi.test(file.type)) {
this.$emit('on-paste-image', file);
e.preventDefault();
}
}
},
markdownScroll() {
const {scrolling} = this;
if (!scrolling) {
return;
}
if (this.scroll === 'left') {
const markdownEditor = this.$refs.markdownEditor;
const preview = this.$refs.preview;
const contentHeight = preview.offsetHeight;
const markdownScrollHeight = markdownEditor.scrollHeight;
const markdownScrollTop = markdownEditor.scrollTop;
const previewScrollHeight = preview.scrollHeight;
preview.scrollTop = parseInt(
(markdownScrollTop /
(markdownScrollHeight - contentHeight)) *
(previewScrollHeight - contentHeight),
0
);
}
},
previewScroll() {
const {scrolling} = this;
if (!scrolling) {
return;
}
if (this.scroll === 'right') {
const markdownEditor = this.$refs.markdownEditor;
const preview = this.$refs.preview;
const contentHeight = preview.offsetHeight;
const markdownScrollHeight = markdownEditor.scrollHeight;
const previewScrollHeight = preview.scrollHeight;
const previewScrollTop = preview.scrollTop;
markdownEditor.scrollTop = parseInt(
(previewScrollTop / (previewScrollHeight - contentHeight)) *
(markdownScrollHeight - contentHeight),
0
);
}
},
mousescrollSide(side) {
// 设置究竟是哪个半边在主动滑动
this.scroll = side;
}
},
watch: {
currentValue() {
clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => {
const {currentValue} = this;
let html = marked(currentValue, {
sanitize: false,
...this.markedOptions
}).replace(/href="/gi, 'target="_blank" href="');
if (this.copyCode && html !== '') {
html = html.replace(/<pre>/g, '<div class="code-block"><span class="copy-code">'+this.copyBtnText+'</span><pre>').replace(/<\/pre>/g, '</pre></div>');
}
this.html = html;
this.indexLenth = this.currentValue.split('\n').length;
this.textareaHeight = this.indexLenth * 22;
this.addImageClickListener();
this.addCopyListener();
this.$emit('input', currentValue);
}, 30);
},
value() {
if (this.currentValue !== this.value) {
this.currentValue = this.value;
}
}
}
};