|
@@ -0,0 +1,118 @@
|
|
|
+<script setup>
|
|
|
+import { onBeforeUnmount, onMounted, ref } from 'vue';
|
|
|
+import tinymce from "tinymce"
|
|
|
+import request from '~/utils/request';
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ 'id': {
|
|
|
+ type: String,
|
|
|
+ default: `tiny-${Date.now()}-${~~(Math.random() * 10000)}`
|
|
|
+ },
|
|
|
+ 'htmlClass': { default: '', type: String },
|
|
|
+ 'modelValue': { default: '' },
|
|
|
+ 'plugins': {
|
|
|
+ default: function () {
|
|
|
+ return [
|
|
|
+ 'advlist autolink lists link image charmap preview anchor pagebreak',
|
|
|
+ 'searchreplace wordcount visualblocks visualchars code fullscreen',
|
|
|
+ 'insertdatetime media nonbreaking save table directionality',
|
|
|
+ 'template help emoticons'
|
|
|
+ ];
|
|
|
+ }, type: Array
|
|
|
+ },
|
|
|
+ toolbar1: { default: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat', type: String },
|
|
|
+ toolbar2: { default: '', type: String },
|
|
|
+ other_options: {
|
|
|
+ default: function () {
|
|
|
+ return {};
|
|
|
+ }, type: Object
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const emits = defineEmits(['update:modelValue'])
|
|
|
+
|
|
|
+const content = ref('')
|
|
|
+
|
|
|
+let editor = null
|
|
|
+let checkerTimeout = null
|
|
|
+let isTyping = false
|
|
|
+
|
|
|
+function init() {
|
|
|
+ let options = {
|
|
|
+ selector: '#' + props.id,
|
|
|
+ base_url: '/tiny',
|
|
|
+ language: 'zh-Hans',
|
|
|
+ // skin: false,
|
|
|
+ toolbar1: props.toolbar1,
|
|
|
+ toolbar2: props.toolbar2,
|
|
|
+ plugins: props.plugins.join(' '),
|
|
|
+ autosave_restore_when_empty: true,
|
|
|
+ init_instance_callback: (_editor) => {
|
|
|
+ _editor.on('KeyUp', (e) => {
|
|
|
+ submitNewContent();
|
|
|
+ });
|
|
|
+ _editor.on('Change', (e) => {
|
|
|
+ if (_editor.getContent() !== props.modelValue) {
|
|
|
+ submitNewContent();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ _editor.on('init', (e) => {
|
|
|
+ _editor.setContent(content.value);
|
|
|
+ // emits('input', content.value);
|
|
|
+ });
|
|
|
+ editor = _editor;
|
|
|
+ },
|
|
|
+ images_upload_handler: (blobInfo, progress) => {
|
|
|
+ const file = blobInfo.blob();
|
|
|
+ return request({
|
|
|
+ $type: 'upload',
|
|
|
+ url: 'upload/main/file',
|
|
|
+ data: {
|
|
|
+ filedata: file
|
|
|
+ },
|
|
|
+ timeout: 1000 * 60,
|
|
|
+ onUploadProgress(progressEvent) {
|
|
|
+ progress(~~(progressEvent.loaded / progressEvent.total * 100 | 0))
|
|
|
+ },
|
|
|
+ }).then(res => {
|
|
|
+ if (res.code === '1') {
|
|
|
+ return window.GLOBAL_CONFIG.oss + (res.data.url)
|
|
|
+ } else {
|
|
|
+ return ('')
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // to solve a third party URL
|
|
|
+ // paste_preprocess: (editor, args) => {
|
|
|
+ // if (/^https?\:\/\/.+(png|jpg)$/.test(args.content)) {
|
|
|
+ // args.content = uploadByThirdPartyUrl(args.content);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ };
|
|
|
+ tinymce.init(Object.assign(options, props.other_options));
|
|
|
+}
|
|
|
+
|
|
|
+function submitNewContent() {
|
|
|
+ isTyping = true;
|
|
|
+ if (checkerTimeout !== null) { clearTimeout(checkerTimeout); }
|
|
|
+ checkerTimeout = setTimeout(() => {
|
|
|
+ isTyping = false;
|
|
|
+ }, 300);
|
|
|
+ emits('update:modelValue', editor.getContent());
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ content.value = props.modelValue
|
|
|
+ init()
|
|
|
+})
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ editor.destroy();
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <textarea :id="id">{{ content }}</textarea>
|
|
|
+ </div>
|
|
|
+</template>
|