THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

219 lines
5.7 KiB

  1. <template>
  2. <div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
  3. <textarea :id="tinymceId" class="tinymce-textarea" />
  4. <div class="editor-custom-btn-container">
  5. <editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />
  6. </div>
  7. </div>
  8. </template>
  9. <script>
  10. /**
  11. * docs:
  12. * https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
  13. */
  14. import editorImage from './components/EditorImage'
  15. import plugins from './plugins'
  16. import toolbar from './toolbar'
  17. export default {
  18. name: 'Tinymce',
  19. components: { editorImage },
  20. props: {
  21. id: {
  22. type: String,
  23. default: function() {
  24. return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
  25. }
  26. },
  27. value: {
  28. type: String,
  29. default: ''
  30. },
  31. toolbar: {
  32. type: Array,
  33. required: false,
  34. default() {
  35. return []
  36. }
  37. },
  38. menubar: {
  39. type: String,
  40. default: 'file edit insert view format table'
  41. },
  42. height: {
  43. type: [Number, String],
  44. required: false,
  45. default: 360
  46. },
  47. width: {
  48. type: [Number, String],
  49. required: false,
  50. default: 'auto'
  51. }
  52. },
  53. data() {
  54. return {
  55. hasChange: false,
  56. hasInit: false,
  57. tinymceId: this.id,
  58. fullscreen: false,
  59. languageTypeList: {
  60. 'en': 'en',
  61. 'zh': 'zh_CN'
  62. }
  63. }
  64. },
  65. computed: {
  66. containerWidth() {
  67. const width = this.width
  68. if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
  69. return `${width}px`
  70. }
  71. return width
  72. }
  73. },
  74. watch: {
  75. value(val) {
  76. if (!this.hasChange && this.hasInit) {
  77. this.$nextTick(() =>
  78. window.tinymce.get(this.tinymceId).setContent(val || ''))
  79. }
  80. }
  81. },
  82. mounted() {
  83. this.initTinymce()
  84. },
  85. activated() {
  86. this.initTinymce()
  87. },
  88. deactivated() {
  89. this.destroyTinymce()
  90. },
  91. destroyed() {
  92. this.destroyTinymce()
  93. },
  94. methods: {
  95. initTinymce() {
  96. const _this = this
  97. window.tinymce.init({
  98. selector: `#${this.tinymceId}`,
  99. height: this.height,
  100. body_class: 'panel-body ',
  101. object_resizing: false,
  102. toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
  103. menubar: this.menubar,
  104. plugins: plugins,
  105. end_container_on_empty_block: true,
  106. powerpaste_word_import: 'clean',
  107. code_dialog_height: 450,
  108. code_dialog_width: 1000,
  109. advlist_bullet_styles: 'square',
  110. advlist_number_styles: 'default',
  111. imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
  112. default_link_target: '_blank',
  113. link_title: false,
  114. nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
  115. init_instance_callback: editor => {
  116. if (_this.value) {
  117. editor.setContent(_this.value)
  118. }
  119. _this.hasInit = true
  120. editor.on('NodeChange Change KeyUp SetContent', () => {
  121. this.hasChange = true
  122. this.$emit('input', editor.getContent())
  123. })
  124. },
  125. setup(editor) {
  126. editor.on('FullscreenStateChanged', (e) => {
  127. _this.fullscreen = e.state
  128. })
  129. }
  130. // 整合七牛上传
  131. // images_dataimg_filter(img) {
  132. // setTimeout(() => {
  133. // const $image = $(img);
  134. // $image.removeAttr('width');
  135. // $image.removeAttr('height');
  136. // if ($image[0].height && $image[0].width) {
  137. // $image.attr('data-wscntype', 'image');
  138. // $image.attr('data-wscnh', $image[0].height);
  139. // $image.attr('data-wscnw', $image[0].width);
  140. // $image.addClass('wscnph');
  141. // }
  142. // }, 0);
  143. // return img
  144. // },
  145. // images_upload_handler(blobInfo, success, failure, progress) {
  146. // progress(0);
  147. // const token = _this.$store.getters.token;
  148. // getToken(token).then(response => {
  149. // const url = response.data.qiniu_url;
  150. // const formData = new FormData();
  151. // formData.append('token', response.data.qiniu_token);
  152. // formData.append('key', response.data.qiniu_key);
  153. // formData.append('file', blobInfo.blob(), url);
  154. // upload(formData).then(() => {
  155. // success(url);
  156. // progress(100);
  157. // })
  158. // }).catch(err => {
  159. // failure('出现未知问题,刷新页面,或者联系程序员')
  160. // console.log(err);
  161. // });
  162. // },
  163. })
  164. },
  165. destroyTinymce() {
  166. const tinymce = window.tinymce.get(this.tinymceId)
  167. if (this.fullscreen) {
  168. tinymce.execCommand('mceFullScreen')
  169. }
  170. if (tinymce) {
  171. tinymce.destroy()
  172. }
  173. },
  174. setContent(value) {
  175. window.tinymce.get(this.tinymceId).setContent(value)
  176. },
  177. getContent() {
  178. window.tinymce.get(this.tinymceId).getContent()
  179. },
  180. imageSuccessCBK(arr) {
  181. const _this = this
  182. arr.forEach(v => {
  183. window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
  184. })
  185. }
  186. }
  187. }
  188. </script>
  189. <style scoped>
  190. .tinymce-container {
  191. position: relative;
  192. line-height: normal;
  193. }
  194. .tinymce-container>>>.mce-fullscreen {
  195. z-index: 10000;
  196. }
  197. .tinymce-textarea {
  198. visibility: hidden;
  199. z-index: -1;
  200. }
  201. .editor-custom-btn-container {
  202. position: absolute;
  203. right: 4px;
  204. top: 4px;
  205. /*z-index: 2005;*/
  206. }
  207. .fullscreen .editor-custom-btn-container {
  208. z-index: 10000;
  209. position: fixed;
  210. }
  211. .editor-upload-btn {
  212. display: inline-block;
  213. }
  214. </style>