yks-element 1.0.0 → 1.0.315

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -4
  3. package/{dist → lib}/fonts/element-icons.535877f5.woff +0 -0
  4. package/{dist → lib}/fonts/element-icons.732389de.ttf +0 -0
  5. package/lib/fonts/iconfont.19124b0d.ttf +0 -0
  6. package/lib/fonts/iconfont.3ae3dd4e.woff +0 -0
  7. package/lib/yks.css +1 -0
  8. package/package.json +74 -51
  9. package/packages/Button/index.js +8 -0
  10. package/packages/Button/src/index.vue +67 -0
  11. package/packages/Dialog/index.js +8 -0
  12. package/packages/Dialog/src/index.vue +103 -0
  13. package/packages/Multimedia/index.js +8 -0
  14. package/packages/Multimedia/src/index.vue +167 -0
  15. package/packages/Pagination/index.js +8 -0
  16. package/packages/Pagination/src/index.vue +149 -0
  17. package/packages/Scrollbar/index.js +8 -0
  18. package/packages/Scrollbar/src/index.vue +27 -0
  19. package/packages/Select/index.js +8 -0
  20. package/packages/Select/src/index.vue +350 -0
  21. package/packages/Select/src/option.vue +29 -0
  22. package/packages/Table/index.js +8 -0
  23. package/packages/Table/src/index.vue +141 -0
  24. package/packages/Tinymce/index.js +8 -0
  25. package/packages/Tinymce/src/config.js +25 -0
  26. package/packages/Tinymce/src/index.vue +500 -0
  27. package/packages/UploadFile/index.js +8 -0
  28. package/packages/UploadFile/src/index.vue +388 -0
  29. package/packages/Video/index.js +8 -0
  30. package/packages/Video/src/index.vue +352 -0
  31. package/packages/assets/utils/index.js +83 -0
  32. package/packages/icon/default/icons.js +182 -0
  33. package/packages/icon/default/icons.min.js +1 -0
  34. package/packages/icon/default/index.js +7 -0
  35. package/packages/icon/ks-pdf.png +0 -0
  36. package/packages/icon/ks-ppt.png +0 -0
  37. package/packages/icon/ks-word.png +0 -0
  38. package/packages/icon/ks-xslx.png +0 -0
  39. package/packages/icon/music-bg.png +0 -0
  40. package/packages/icon/video-bg.png +0 -0
  41. package/packages/index.js +221 -0
  42. package/packages/option/index.js +6 -0
  43. package/packages/styles/_mixin.scss +93 -0
  44. package/packages/styles/_variables.scss +40 -0
  45. package/packages/styles/common.scss +167 -0
  46. package/packages/styles/element-ui.scss +135 -0
  47. package/packages/styles/element-variables.scss +794 -0
  48. package/packages/styles/fonts/element-icons.ttf +0 -0
  49. package/packages/styles/fonts/element-icons.woff +0 -0
  50. package/packages/styles/fonts/iconfont.ttf +0 -0
  51. package/packages/styles/fonts/iconfont.woff +0 -0
  52. package/packages/styles/icon.scss +69 -0
  53. package/packages/styles/index.scss +10 -0
  54. package/packages/styles/select.scss +98 -0
  55. package/packages/styles/table.scss +45 -0
  56. package/types/index.d.ts +4 -0
  57. package/dist/demo.html +0 -10
  58. package/dist/yks.common.js +0 -64801
  59. package/dist/yks.css +0 -1
  60. package/dist/yks.umd.js +0 -64811
  61. package/dist/yks.umd.min.js +0 -15
  62. package/packages/button/index.vue +0 -16
  63. package/packages/index.ts +0 -12
@@ -0,0 +1,500 @@
1
+ <template>
2
+ <div
3
+ :class="{ fullscreen: fullscreen }"
4
+ class="tinymce-container"
5
+ :style="{ width: containerWidth }"
6
+ >
7
+ <TinymceEditor
8
+ :id="tinymceId"
9
+ ref="tinymceEditor"
10
+ :key="tinymceId"
11
+ v-model="tinymceContent"
12
+ :init="initOptions"
13
+ :class="{ 'tinymce-inline': inline }"
14
+ />
15
+ <div v-if="fileParams.length !== 0" class="ti-multimedia">
16
+ <div
17
+ v-for="(values, index) in fileParams"
18
+ :key="`fileParams${index}${Math.random()}`"
19
+ class="media-file"
20
+ >
21
+ <yks-multimedia
22
+ :data="values"
23
+ visibleDel
24
+ @delete="handleCloseFile(values, index)"
25
+ ></yks-multimedia>
26
+ </div>
27
+ </div>
28
+ <yks-uploadfile
29
+ :show.sync="show"
30
+ :fileData="fileData"
31
+ :title="title"
32
+ :uploadFileFunction="uploadFileFunction"
33
+ @sure="onSure"
34
+ ></yks-uploadfile>
35
+ </div>
36
+ </template>
37
+
38
+ <script>
39
+ // Docs: https://armour.github.io/vue-typescript-admin-docs/features/components/rich-editor.html#tinymce
40
+ import 'tinymce/tinymce'
41
+ import 'tinymce/themes/silver' // Import themes
42
+ import 'tinymce/themes/mobile'
43
+ import 'tinymce/plugins/advlist' // Any plugins you want to use has to be imported
44
+ import 'tinymce/plugins/anchor'
45
+ import 'tinymce/plugins/autolink'
46
+ import 'tinymce/plugins/autosave'
47
+ import 'tinymce/plugins/charmap'
48
+ import 'tinymce/plugins/code'
49
+ import 'tinymce/plugins/codesample'
50
+ import 'tinymce/plugins/directionality'
51
+ import 'tinymce/plugins/emoticons'
52
+ import 'tinymce/plugins/fullscreen'
53
+ import 'tinymce/plugins/hr'
54
+ import 'tinymce/plugins/image'
55
+ import 'tinymce/plugins/imagetools'
56
+ import 'tinymce/plugins/insertdatetime'
57
+ import 'tinymce/plugins/link'
58
+ import 'tinymce/plugins/lists'
59
+ import 'tinymce/plugins/media'
60
+ import 'tinymce/plugins/nonbreaking'
61
+ import 'tinymce/plugins/noneditable'
62
+ import 'tinymce/plugins/pagebreak'
63
+ import 'tinymce/plugins/paste'
64
+ import 'tinymce/plugins/preview'
65
+ import 'tinymce/plugins/print'
66
+ import 'tinymce/plugins/save'
67
+ import 'tinymce/plugins/searchreplace'
68
+ import 'tinymce/plugins/spellchecker'
69
+ import 'tinymce/plugins/tabfocus'
70
+ import 'tinymce/plugins/table'
71
+ import 'tinymce/plugins/template'
72
+ import 'tinymce/plugins/textpattern'
73
+ import 'tinymce/plugins/visualblocks'
74
+ import 'tinymce/plugins/visualchars'
75
+ import 'tinymce/plugins/wordcount'
76
+ import '../../icon/default'
77
+ import TinymceEditor from '@tinymce/tinymce-vue' // TinyMCE vue wrapper
78
+ // eslint-disable-next-line no-duplicate-imports
79
+ import tinymce from 'tinymce/tinymce'
80
+ import { uploadAudio, uploadVideo, uploadFile, uploadRecording, plugins, toolbar } from './config'
81
+ import YksUploadfile from '../../UploadFile/index'
82
+ import YksMultimedia from '../../Multimedia/index'
83
+
84
+ import { Loading } from 'element-ui'
85
+
86
+ export default {
87
+ name: 'YksTinymce',
88
+ components: {
89
+ TinymceEditor,
90
+ YksUploadfile,
91
+ YksMultimedia
92
+ },
93
+ props: {
94
+ value: {
95
+ required: true
96
+ },
97
+ /* 语言包 */
98
+ language: {
99
+ type: String,
100
+ default: 'zh_CN'
101
+ },
102
+ /* 扩展bar */
103
+ toolbar: {
104
+ type: [String, Array],
105
+ default: () => []
106
+ },
107
+ /* 字数限制 */
108
+ charLimit: {
109
+ type: Number,
110
+ default: 5000
111
+ },
112
+ /* 插件 */
113
+ plugins: {
114
+ type: [String, Array],
115
+ default: () => []
116
+ },
117
+ menubar: {
118
+ type: String,
119
+ default: 'file edit insert view format table'
120
+ },
121
+ height: {
122
+ type: String,
123
+ default: '660px'
124
+ },
125
+ width: {
126
+ type: String,
127
+ default: 'auto'
128
+ },
129
+ inline: {
130
+ type: Boolean,
131
+ default: false
132
+ },
133
+ /* 音视频数据 */
134
+ fileParams: {
135
+ type: Array,
136
+ default: () => []
137
+ },
138
+ /*
139
+ 上传文件函数
140
+ 抛出blobInfo函数
141
+ 接收data src
142
+ */
143
+ uploadFileToHwCloud: {
144
+ required: true,
145
+ type: Function
146
+ },
147
+ /*
148
+ 上传音视频文件函数
149
+ 抛出数组文件信息
150
+ 接收data src
151
+ */
152
+ uploadFileFunction: {
153
+ required: true,
154
+ type: Function
155
+ },
156
+ /* 扩展插件 */
157
+ externalPlugins: {
158
+ type: Object,
159
+ default: () => {
160
+ return {}
161
+ }
162
+ }
163
+ },
164
+ data() {
165
+ return {
166
+ hasChange: false,
167
+ hasInit: false,
168
+ fullscreen: false,
169
+ isComposition: false,
170
+ show: false,
171
+ fileData: {
172
+ fileType: '',
173
+ typeList: [],
174
+ fileSize: 0
175
+ },
176
+ limitNum: 0
177
+ }
178
+ },
179
+ computed: {
180
+ tinymceContent: {
181
+ get() {
182
+ return this.value
183
+ },
184
+ set(value) {
185
+ this.$emit('input', value)
186
+ }
187
+ },
188
+ containerWidth() {
189
+ const width = this.width
190
+ // Test matches `100`, `'100'`
191
+ if (/^[\d]+(\.[\d]+)?$/.test(width.toString())) {
192
+ return `${width}px`
193
+ }
194
+ return width
195
+ },
196
+ title() {
197
+ const params = {
198
+ recording: '音频录制',
199
+ video: '视频上传',
200
+ audio: '音频上传',
201
+ file: '文件上传'
202
+ }
203
+ return params[this.fileData.fileType]
204
+ },
205
+ mediaTypeList() {
206
+ return this.fileParams.map((v) => v.fileType)
207
+ },
208
+ initOptions() {
209
+ return {
210
+ selector: `#${this.tinymceId}`,
211
+ height: this.height,
212
+ charLimit: this.charLimit,
213
+ body_class: 'panel-body ',
214
+ object_resizing: false,
215
+ inline: this.inline,
216
+ toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
217
+ menubar: this.menubar,
218
+ plugins: this.plugins.length > 0 ? this.plugins : plugins,
219
+ language: this.language,
220
+ language_url: `https://pub-static.yks365.net/assets/tinymce/langs/${this.language}.js`,
221
+ skin_url: 'https://pub-static.yks365.net/assets/tinymce/skins',
222
+ emoticons_database_url:
223
+ 'https://pub-static.yks365.net/assets/tinymce/emojis.min.js',
224
+ end_container_on_empty_block: true,
225
+ powerpaste_word_import: 'clean',
226
+ code_dialog_height: 450,
227
+ code_dialog_width: 1000,
228
+ advlist_bullet_styles: 'square',
229
+ advlist_number_styles: 'default',
230
+ imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
231
+ default_link_target: '_blank',
232
+ link_title: false,
233
+ nonbreaking_force_tab: true,
234
+ branding: false,
235
+ convert_urls: false,
236
+ resize: false,
237
+ elementpath: false,
238
+ paste_as_text: false,
239
+ paste_data_image: true,
240
+ paste_data_images: true,
241
+ external_plugins: {
242
+ ...this.externalPlugins,
243
+ powerpaste: `https://pub-static.yks365.net/assets/tinymce/powerpaste/plugin.min.js`,
244
+ 'kityformula-editor': `https://pub-static.yks365.net/assets/tinymce/kityformula-editor/plugin.min.js`
245
+ },
246
+ images_upload_handler: async (blobInfo, success) => {
247
+ const loading = Loading.service({
248
+ lock: true,
249
+ text: '上传中...',
250
+ spinner: 'el-icon-loading',
251
+ background: 'rgba(0, 0, 0, 0.7)'
252
+ })
253
+
254
+ try {
255
+ const data = await this.uploadFileToHwCloud(blobInfo)
256
+ success(data)
257
+ } catch (error) {
258
+ console.log(error)
259
+ success('')
260
+ }
261
+ loading.close()
262
+ },
263
+ paste_preprocess: (e, args) => {
264
+ const tinymax = this.charLimit
265
+ const text = this.tinymceContent.replace(/(<([^>]+)>)/gi, '')
266
+ const contentOnBlur = args.content.replace(/(<([^>]+)>)/gi, '')
267
+ // 粘贴字数限制
268
+ if (tinymax - text.length < contentOnBlur.length) {
269
+ this.$message.error(`长度限制为${tinymax}个字符`)
270
+ this.limitNum++
271
+ if (tinymax > text.length) {
272
+ args.content = contentOnBlur.substr(0, tinymax - text.length)
273
+ } else {
274
+ args.content = ''
275
+ }
276
+ }
277
+ },
278
+ init_instance_callback: (editor) => {
279
+ if (this.value) {
280
+ editor.setContent(this.value)
281
+ }
282
+ this.hasInit = true
283
+ editor.on('NodeChange Change KeyUp SetContent', () => {
284
+ this.hasChange = true
285
+ this.$emit('input', editor.getContent())
286
+ })
287
+ },
288
+ setup: (editor) => {
289
+ editor.on('FullscreenStateChanged', (e) => {
290
+ this.fullscreen = e.state
291
+ })
292
+ editor.on('compositionstart', () => {
293
+ this.isComposition = false
294
+ })
295
+ editor.on('compositionend', () => {
296
+ this.isComposition = true
297
+ })
298
+ editor.on('input', (e) => {
299
+ this.wordLimit(e, editor)
300
+ })
301
+
302
+ editor.ui.registry.addButton('uploadRecording', {
303
+ text: uploadRecording,
304
+ onAction: () => {
305
+ if (this.mediaTypeList.includes('recording')) {
306
+ this.$message.warning('最多选择一种!')
307
+ return
308
+ }
309
+ this.show = true
310
+ this.fileData.fileType = 'recording'
311
+ this.fileData.typeList = []
312
+ this.fileData.fileSize = 600
313
+ }
314
+ })
315
+
316
+ editor.ui.registry.addButton('uploadVideo', {
317
+ text: uploadVideo,
318
+ onAction: () => {
319
+ if (this.mediaTypeList.includes('video')) {
320
+ this.$message.warning('最多选择一种!')
321
+ return
322
+ }
323
+ this.fileData.fileType = 'video'
324
+ this.fileData.typeList = ['mp4']
325
+ this.fileData.fileSize = 20
326
+ this.show = true
327
+ }
328
+ })
329
+
330
+ editor.ui.registry.addButton('uploadAudio', {
331
+ text: uploadAudio,
332
+ onAction: () => {
333
+ if (this.mediaTypeList.includes('audio')) {
334
+ this.$message.warning('最多选择一种!')
335
+ return
336
+ }
337
+ this.fileData.fileType = 'audio'
338
+ this.show = true
339
+ this.fileData.typeList = ['mp3']
340
+ this.fileData.fileSize = 20
341
+ }
342
+ })
343
+
344
+ editor.ui.registry.addButton('uploadFile', {
345
+ text: uploadFile,
346
+ onAction: () => {
347
+ if (this.mediaTypeList.includes('file')) {
348
+ this.$message.warning('最多选择一种!')
349
+ return
350
+ }
351
+ this.fileData.fileType = 'file'
352
+ this.fileData.typeList = ['pptx', 'docx', 'pdf', 'xlsx']
353
+ this.fileData.fileSize = 20
354
+ this.show = true
355
+ }
356
+ })
357
+ }
358
+ }
359
+ },
360
+ tinymceId() {
361
+ return 'vue-tinymce-' + Number(new Date()) + String((Math.random() * 1000).toFixed(0))
362
+ }
363
+ },
364
+ destroy() {
365
+ const tinymce = window.tinymce.get(this.tinymceId)
366
+ tinymce.destroy()
367
+ },
368
+ methods: {
369
+ handleCloseFile(row, index) {
370
+ this.$emit('delteFile', {
371
+ row: row,
372
+ index: index
373
+ })
374
+ },
375
+ handleFillInBlanks(value, id) {
376
+ const editor = this.$refs.tinymceEditor.editor
377
+ editor.editorManager.get(editor.id).focus()
378
+ tinymce.activeEditor.insertContent(
379
+ `<input type="text" class="fill-icon ${id}" disabled readonly value="${value}">`
380
+ )
381
+ },
382
+ deleFillItem(index) {
383
+ const el = this.$refs.tinymceEditor.editor
384
+ el.editorManager.get(el.id).focus()
385
+ const elList =
386
+ tinymce.activeEditor && tinymce.activeEditor.iframeElement
387
+ ? tinymce.activeEditor.iframeElement.contentWindow &&
388
+ tinymce.activeEditor.iframeElement.contentWindow.document.getElementsByTagName(
389
+ 'input'
390
+ )
391
+ : []
392
+ elList[index].remove()
393
+ for (let i = 0; i < elList.length; i++) {
394
+ elList[i].setAttribute('value', i + 1)
395
+ }
396
+ },
397
+ onSure(value) {
398
+ this.$emit('changeFile', {
399
+ value: this.tinymceContent,
400
+ itemAttr: { type: this.fileData.fileType, content: value }
401
+ })
402
+ },
403
+ wordLimit(e, editor) {
404
+ const tinymax = editor.settings.charLimit
405
+ const text = e.target.innerText
406
+ const html = e.target.innerHTML
407
+ let last = ''
408
+ let lastIndex = ''
409
+ let startVal = ''
410
+ let endVal = ''
411
+ if (text.length === tinymax) {
412
+ this.tinymceContent = html
413
+ // 兼容输入法有可能会跳过最大值
414
+ } else if (!this.isComposition && text.length === tinymax + 1) {
415
+ last = text.substr(text.length - 1, 1)
416
+ lastIndex = html.lastIndexOf(last)
417
+ startVal = html.substring(0, lastIndex)
418
+ endVal = html.substring(lastIndex + 1, html.length)
419
+ this.tinymceContent = startVal + endVal
420
+ }
421
+ if (text.length > tinymax) {
422
+ e.target.innerHTML = this.tinymceContent
423
+ this.keepLastIndex()
424
+ editor.focus()
425
+ if (!this.limitNum) {
426
+ this.$message.error(`长度限制为${tinymax}个字符`)
427
+ this.limitNum++
428
+ }
429
+ } else {
430
+ this.limitNum = 0
431
+ }
432
+ },
433
+ keepLastIndex() {
434
+ const tinymce = window.tinymce.get(this.tinymceId)
435
+ const wind = tinymce.contentWindow
436
+ const obj = wind.document.getElementById('tinymce')
437
+ if (wind.getSelection) {
438
+ // ie11 10 9 ff safari
439
+ obj.focus() // 解决ff不获取焦点无法定位问题
440
+ const range = wind.getSelection() // 创建range
441
+ console.log(range)
442
+ range.selectAllChildren(obj) // range 选择obj下所有子内容
443
+ range.collapseToEnd() // 光标移至最后
444
+ } else if (document.selection) {
445
+ // ie10 9 8 7 6 5
446
+ const range = document.selection.createRange() // 创建选择对象
447
+ range.moveToElementText(obj) // range定位到obj
448
+ range.collapse(false) // 光标移至最后
449
+ range.select()
450
+ }
451
+ }
452
+ }
453
+ }
454
+ </script>
455
+
456
+ <style lang="scss" scoped>
457
+ .tinymce-container {
458
+ line-height: normal;
459
+ position: relative;
460
+
461
+ .mce-fullscreen {
462
+ z-index: 10000;
463
+ }
464
+
465
+ .editor-custom-btn-container {
466
+ position: absolute;
467
+ top: 6px;
468
+ right: 6px;
469
+
470
+ &.fullscreen {
471
+ position: fixed;
472
+ z-index: 10000;
473
+ }
474
+ }
475
+
476
+ .editor-upload-btn {
477
+ display: inline-block;
478
+ }
479
+
480
+ textarea {
481
+ visibility: hidden;
482
+ z-index: -1;
483
+ }
484
+ .ti-multimedia {
485
+ position: relative;
486
+ display: flex;
487
+ align-items: flex-start;
488
+ flex-wrap: wrap;
489
+ margin-top: 10px;
490
+ }
491
+
492
+ .tinymce-inline {
493
+ padding: 0 20px;
494
+ border: 1px solid #ccc;
495
+ }
496
+ .tox-statusbar__wordcount {
497
+ opacity: 0 !important;
498
+ }
499
+ }
500
+ </style>
@@ -0,0 +1,8 @@
1
+ import YksUploadfile from './src/index';
2
+
3
+ /* istanbul ignore next */
4
+ YksUploadfile.install = function(Vue) {
5
+ Vue.component(YksUploadfile.name, YksUploadfile);
6
+ };
7
+
8
+ export default YksUploadfile;