| New file |
| | |
| | | <template> |
| | | <div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}"> |
| | | <textarea :id="tinymceId" class="tinymce-textarea" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | /** |
| | | * docs: |
| | | * https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce |
| | | */ |
| | | import plugins from './plugins' |
| | | import toolbar from './toolbar' |
| | | import load from './dynamicLoadScript' |
| | | |
| | | // why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one |
| | | const resourceCdn1 = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js' |
| | | const resourceCdn2 = 'https://unpkg.zhimg.com/tinymce-all-in-one@4.9.3/tinymce.min.js' |
| | | const resourceCdn3 = 'https://unpkg.com/tinymce-all-in-one@4.9.3/tinymce.min.js' |
| | | |
| | | export default { |
| | | name: 'Tinymce', |
| | | props: { |
| | | id: { |
| | | type: String, |
| | | default: function () { |
| | | return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '') |
| | | } |
| | | }, |
| | | value: { |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | toolbar: { |
| | | type: Array, |
| | | required: false, |
| | | default () { |
| | | return [] |
| | | } |
| | | }, |
| | | menubar: { |
| | | type: String, |
| | | default: 'file edit insert view format table' |
| | | }, |
| | | height: { |
| | | type: [Number, String], |
| | | required: false, |
| | | default: 360 |
| | | }, |
| | | width: { |
| | | type: [Number, String], |
| | | required: false, |
| | | default: 'auto' |
| | | } |
| | | }, |
| | | data () { |
| | | return { |
| | | hasChange: false, |
| | | hasInit: false, |
| | | tinymceId: this.id, |
| | | fullscreen: false |
| | | } |
| | | }, |
| | | computed: { |
| | | language () { |
| | | return localStorage.getItem('lang') || 'zh_CN' |
| | | }, |
| | | containerWidth () { |
| | | const width = this.width |
| | | if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'` |
| | | return `${width}px` |
| | | } |
| | | return width |
| | | } |
| | | }, |
| | | watch: { |
| | | value (val) { |
| | | if (!this.hasChange && this.hasInit) { |
| | | this.$nextTick(() => |
| | | window.tinymce.get(this.tinymceId).setContent(val || '')) |
| | | } |
| | | }, |
| | | language () { |
| | | this.destroyTinymce() |
| | | this.$nextTick(() => this.initTinymce()) |
| | | } |
| | | }, |
| | | mounted () { |
| | | this.init() |
| | | }, |
| | | activated () { |
| | | if (window.tinymce) { |
| | | this.initTinymce() |
| | | } |
| | | }, |
| | | deactivated () { |
| | | this.destroyTinymce() |
| | | }, |
| | | destroyed () { |
| | | this.destroyTinymce() |
| | | }, |
| | | methods: { |
| | | init () { |
| | | // dynamic load tinymce from cdn |
| | | load(resourceCdn1, (err) => { |
| | | if (!err) { |
| | | this.initTinymce() |
| | | return |
| | | } |
| | | load(resourceCdn2, (err2) => { |
| | | if (!err2) { |
| | | this.initTinymce() |
| | | return |
| | | } |
| | | load(resourceCdn3, (err3) => { |
| | | if (!err3) { |
| | | this.initTinymce() |
| | | return |
| | | } |
| | | this.$message.error(err.message) |
| | | }) |
| | | }) |
| | | }) |
| | | }, |
| | | initTinymce () { |
| | | const _this = this |
| | | window.tinymce.init({ |
| | | language: this.language, |
| | | selector: `#${this.tinymceId}`, |
| | | height: this.height, |
| | | body_class: 'panel-body ', |
| | | object_resizing: false, |
| | | toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar, |
| | | menubar: this.menubar, |
| | | plugins: plugins, |
| | | end_container_on_empty_block: true, |
| | | powerpaste_word_import: 'clean', |
| | | code_dialog_height: 450, |
| | | code_dialog_width: 1000, |
| | | advlist_bullet_styles: 'square', |
| | | advlist_number_styles: 'default', |
| | | imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'], |
| | | default_link_target: '_blank', |
| | | link_title: false, |
| | | nonbreaking_force_tab: true, // inserting nonbreaking space need Nonbreaking Space Plugin |
| | | init_instance_callback: editor => { |
| | | if (_this.value) { |
| | | editor.setContent(_this.value) |
| | | } |
| | | _this.hasInit = true |
| | | editor.on('NodeChange Change KeyUp SetContent', () => { |
| | | this.hasChange = true |
| | | this.$emit('input', editor.getContent()) |
| | | }) |
| | | }, |
| | | setup (editor) { |
| | | editor.on('FullscreenStateChanged', (e) => { |
| | | _this.fullscreen = e.state |
| | | }) |
| | | }, |
| | | // it will try to keep these URLs intact |
| | | // https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/ |
| | | // https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions |
| | | convert_urls: false |
| | | // 整合七牛上传 |
| | | // images_dataimg_filter(img) { |
| | | // setTimeout(() => { |
| | | // const $image = $(img); |
| | | // $image.removeAttr('width'); |
| | | // $image.removeAttr('height'); |
| | | // if ($image[0].height && $image[0].width) { |
| | | // $image.attr('data-wscntype', 'image'); |
| | | // $image.attr('data-wscnh', $image[0].height); |
| | | // $image.attr('data-wscnw', $image[0].width); |
| | | // $image.addClass('wscnph'); |
| | | // } |
| | | // }, 0); |
| | | // return img |
| | | // }, |
| | | // images_upload_handler(blobInfo, success, failure, progress) { |
| | | // progress(0); |
| | | // const token = _this.$store.getters.token; |
| | | // getToken(token).then(response => { |
| | | // const url = response.data.qiniu_url; |
| | | // const formData = new FormData(); |
| | | // formData.append('token', response.data.qiniu_token); |
| | | // formData.append('key', response.data.qiniu_key); |
| | | // formData.append('file', blobInfo.blob(), url); |
| | | // upload(formData).then(() => { |
| | | // success(url); |
| | | // progress(100); |
| | | // }) |
| | | // }).catch(err => { |
| | | // failure('出现未知问题,刷新页面,或者联系程序员') |
| | | // console.log(err); |
| | | // }); |
| | | // }, |
| | | }) |
| | | }, |
| | | destroyTinymce () { |
| | | const tinymce = window.tinymce.get(this.tinymceId) |
| | | if (this.fullscreen) { |
| | | tinymce.execCommand('mceFullScreen') |
| | | } |
| | | |
| | | if (tinymce) { |
| | | tinymce.destroy() |
| | | } |
| | | }, |
| | | setContent (value) { |
| | | window.tinymce.get(this.tinymceId).setContent(value) |
| | | }, |
| | | getContent () { |
| | | window.tinymce.get(this.tinymceId).getContent() |
| | | }, |
| | | imageSuccessCBK (arr) { |
| | | const _this = this |
| | | arr.forEach(v => { |
| | | window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v}" >`) |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .tinymce-container { |
| | | position: relative; |
| | | line-height: normal; |
| | | } |
| | | |
| | | .tinymce-container { |
| | | ::v-deep { |
| | | .mce-fullscreen { |
| | | z-index: 10000; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .tinymce-textarea { |
| | | visibility: hidden; |
| | | z-index: -1; |
| | | } |
| | | |
| | | .editor-custom-btn-container { |
| | | position: absolute; |
| | | right: 4px; |
| | | top: 4px; |
| | | /*z-index: 2005;*/ |
| | | } |
| | | |
| | | .fullscreen .editor-custom-btn-container { |
| | | z-index: 10000; |
| | | position: fixed; |
| | | } |
| | | |
| | | .editor-upload-btn { |
| | | display: inline-block; |
| | | } |
| | | </style> |