vue-editify 0.1.36 → 0.1.39
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.
- package/examples/App.vue +5 -8
- package/lib/components/button/button.vue.d.ts +13 -13
- package/lib/components/button/props.d.ts +1 -1
- package/lib/components/checkbox/checkbox.vue.d.ts +10 -10
- package/lib/components/checkbox/props.d.ts +1 -1
- package/lib/components/colors/colors.vue.d.ts +6 -6
- package/lib/components/colors/props.d.ts +1 -1
- package/lib/components/icon/icon.vue.d.ts +1 -1
- package/lib/components/insertImage/insertImage.vue.d.ts +11 -11
- package/lib/components/insertLink/insertLink.vue.d.ts +4 -4
- package/lib/components/insertTable/insertTable.vue.d.ts +4 -4
- package/lib/components/insertVideo/insertVideo.vue.d.ts +11 -11
- package/lib/components/layer/layer.vue.d.ts +9 -9
- package/lib/components/menu/menu.vue.d.ts +6 -6
- package/lib/components/menu/props.d.ts +1 -1
- package/lib/components/toolbar/props.d.ts +1 -1
- package/lib/components/toolbar/toolbar.vue.d.ts +11 -11
- package/lib/components/tooltip/tooltip.vue.d.ts +1 -1
- package/lib/components/triangle/triangle.vue.d.ts +4 -4
- package/lib/core/function.d.ts +8 -1
- package/lib/core/rule.d.ts +3 -3
- package/lib/core/tool.d.ts +9 -11
- package/lib/editify/editify.vue.d.ts +110 -84
- package/lib/editify/props.d.ts +9 -5
- package/lib/editify.es.js +15226 -418
- package/lib/editify.umd.js +1 -1
- package/lib/index.d.ts +6 -4
- package/lib/plugins/attachment/index.d.ts +3 -2
- package/lib/plugins/attachment/insertAttachment/insertAttachment.vue.d.ts +11 -11
- package/lib/plugins/mathformula/index.d.ts +31 -0
- package/lib/plugins/mathformula/insertMathformula/insertMathformula.vue.d.ts +18 -0
- package/lib/plugins/mathformula/insertMathformula/props.d.ts +9 -0
- package/lib/style.css +1 -1
- package/package.json +4 -2
- package/src/components/insertImage/insertImage.less +1 -0
- package/src/components/insertLink/insertLink.less +1 -0
- package/src/components/insertVideo/insertVideo.less +1 -0
- package/src/components/menu/menu.vue +33 -1
- package/src/components/tooltip/tooltip.less +2 -2
- package/src/core/function.ts +18 -6
- package/src/core/rule.ts +34 -11
- package/src/core/tool.ts +48 -67
- package/src/css/base.less +2 -0
- package/src/editify/editify.less +12 -3
- package/src/editify/editify.vue +113 -39
- package/src/editify/props.ts +11 -4
- package/src/icon/iconfont.css +8 -16
- package/src/icon/iconfont.ttf +0 -0
- package/src/icon/iconfont.woff +0 -0
- package/src/index.ts +7 -5
- package/src/locale/en_US.ts +7 -1
- package/src/locale/zh_CN.ts +8 -2
- package/src/plugins/attachment/index.ts +39 -25
- package/src/plugins/attachment/insertAttachment/insertAttachment.less +1 -0
- package/src/plugins/mathformula/index.ts +210 -0
- package/src/plugins/mathformula/insertMathformula/insertMathformula.less +64 -0
- package/src/plugins/mathformula/insertMathformula/insertMathformula.vue +40 -0
- package/src/plugins/mathformula/insertMathformula/props.ts +11 -0
package/src/editify/editify.vue
CHANGED
@@ -22,8 +22,8 @@
|
|
22
22
|
import { computed, getCurrentInstance, nextTick, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue'
|
23
23
|
import { AlexEditor, AlexElement, AlexElementRangeType, AlexElementsRangeType } from 'alex-editor'
|
24
24
|
import { element as DapElement, event as DapEvent, data as DapData, number as DapNumber, color as DapColor } from 'dap-util'
|
25
|
-
import {
|
26
|
-
import { parseList, orderdListHandle,
|
25
|
+
import { mergeObject, getToolbarConfig, getMenuConfig, MenuConfigType, ObjectType, ToolbarConfigType, PluginResultType } from '../core/tool'
|
26
|
+
import { parseList, orderdListHandle, commonElementHandle, tableHandle, preHandle, specialInblockHandle } from '../core/rule'
|
27
27
|
import { isTask, elementToParagraph, getCurrentParsedomElement, hasTableInRange, hasLinkInRange, hasPreInRange, hasImageInRange, hasVideoInRange } from '../core/function'
|
28
28
|
import Toolbar from '../components/toolbar/toolbar.vue'
|
29
29
|
import Menu from '../components/menu/menu.vue'
|
@@ -249,6 +249,18 @@ const createEditor = () => {
|
|
249
249
|
pluginRules.push(pluginResult.renderRule)
|
250
250
|
}
|
251
251
|
})
|
252
|
+
//注册插件:将插件定义的额外保留的标签数组与配置合并
|
253
|
+
let extraKeepTags: string[] = [...props.extraKeepTags]
|
254
|
+
pluginResultList.value.forEach(pluginResult => {
|
255
|
+
if (pluginResult.extraKeepTags && Array.isArray(pluginResult.extraKeepTags)) {
|
256
|
+
pluginResult.extraKeepTags.forEach(tag => {
|
257
|
+
//如果不包含则加入数组
|
258
|
+
if (!extraKeepTags.includes(tag)) {
|
259
|
+
extraKeepTags.push(tag)
|
260
|
+
}
|
261
|
+
})
|
262
|
+
}
|
263
|
+
})
|
252
264
|
//创建编辑器
|
253
265
|
editor.value = new AlexEditor(contentRef.value!, {
|
254
266
|
value: value.value,
|
@@ -261,7 +273,7 @@ const createEditor = () => {
|
|
261
273
|
orderdListHandle(editor.value!, el)
|
262
274
|
},
|
263
275
|
el => {
|
264
|
-
|
276
|
+
commonElementHandle(editor.value!, el)
|
265
277
|
},
|
266
278
|
el => {
|
267
279
|
tableHandle(editor.value!, el)
|
@@ -285,7 +297,8 @@ const createEditor = () => {
|
|
285
297
|
customFilePaste: props.customFilePaste,
|
286
298
|
customHtmlPaste: handleCustomHtmlPaste,
|
287
299
|
customMerge: handleCustomMerge,
|
288
|
-
customParseNode: handleCustomParseNode
|
300
|
+
customParseNode: handleCustomParseNode,
|
301
|
+
extraKeepTags: extraKeepTags
|
289
302
|
})
|
290
303
|
//编辑器渲染后会有一个渲染过程,会改变内容,因此重新获取内容的值来设置value
|
291
304
|
internalModify(editor.value.value)
|
@@ -435,39 +448,111 @@ const documentClick = (e: Event) => {
|
|
435
448
|
}
|
436
449
|
//重新定义编辑器粘贴html
|
437
450
|
const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
|
438
|
-
let keepStyles = pasteKeepData.styles
|
439
|
-
let keepMarks = pasteKeepData.marks
|
440
|
-
//注册插件:自定义html粘贴保留
|
441
|
-
pluginResultList.value.forEach(pluginResult => {
|
442
|
-
keepStyles = Object.assign(keepStyles, pluginResult.pasteKeepStyles || {})
|
443
|
-
keepMarks = Object.assign(keepMarks, pluginResult.pasteKeepMarks || {})
|
444
|
-
})
|
445
|
-
keepStyles = Object.assign(keepStyles, props.pasteKeepStyles || {})
|
446
|
-
keepMarks = Object.assign(keepMarks, props.pasteKeepMarks || {})
|
447
|
-
//粘贴html时过滤元素的样式和属性
|
448
451
|
AlexElement.flatElements(elements).forEach(el => {
|
449
|
-
let marks: ObjectType = {}
|
450
|
-
let styles: ObjectType = {}
|
451
|
-
//非文本元素
|
452
452
|
if (!el.isText()) {
|
453
|
-
|
453
|
+
let marks: ObjectType = {}
|
454
|
+
let styles: ObjectType = {}
|
455
|
+
//处理需要保留的标记
|
454
456
|
if (el.hasMarks()) {
|
455
|
-
|
456
|
-
|
457
|
-
|
457
|
+
//contenteditable属性保留
|
458
|
+
if (el.marks!['contenteditable']) {
|
459
|
+
marks['contenteditable'] = el.marks!['contenteditable']
|
460
|
+
}
|
461
|
+
//name属性保留
|
462
|
+
if (el.marks!['name']) {
|
463
|
+
marks['name'] = el.marks!['name']
|
464
|
+
}
|
465
|
+
//disabled属性保留
|
466
|
+
if (el.marks!['disabled']) {
|
467
|
+
marks['disabled'] = el.marks!['disabled']
|
468
|
+
}
|
469
|
+
//td的colspan属性保留
|
470
|
+
if (el.parsedom == 'td' && el.marks!['colspan']) {
|
471
|
+
marks['colspan'] = el.marks!['colspan']
|
472
|
+
}
|
473
|
+
//图片和视频的src属性保留
|
474
|
+
if (['img', 'video'].includes(el.parsedom!) && el.marks!['src']) {
|
475
|
+
marks['src'] = el.marks!['src']
|
476
|
+
}
|
477
|
+
//视频的autoplay属性保留
|
478
|
+
if (el.parsedom == 'video' && el.marks!['autoplay']) {
|
479
|
+
marks['autoplay'] = el.marks!['autoplay']
|
480
|
+
}
|
481
|
+
//视频的loop属性保留
|
482
|
+
if (el.parsedom == 'video' && el.marks!['loop']) {
|
483
|
+
marks['loop'] = el.marks!['loop']
|
484
|
+
}
|
485
|
+
//视频的muted属性保留
|
486
|
+
if (el.parsedom == 'video' && el.marks!['muted']) {
|
487
|
+
marks['muted'] = el.marks!['muted']
|
488
|
+
}
|
489
|
+
//视频的controls属性保留
|
490
|
+
if (el.parsedom == 'video' && el.marks!['controls']) {
|
491
|
+
marks['controls'] = el.marks!['controls']
|
492
|
+
}
|
493
|
+
//链接的href属性保留
|
494
|
+
if (el.parsedom == 'a' && el.marks!['href']) {
|
495
|
+
marks['href'] = el.marks!['href']
|
496
|
+
}
|
497
|
+
//链接的target属性保留
|
498
|
+
if (el.parsedom == 'a' && el.marks!['target']) {
|
499
|
+
marks['target'] = el.marks!['target']
|
500
|
+
}
|
501
|
+
//有序和无序列表属性保留
|
502
|
+
if (el.parsedom == 'div' && el.marks!['data-editify-list']) {
|
503
|
+
marks['data-editify-list'] = el.marks!['data-editify-list']
|
504
|
+
//有序列表保留序列号标记
|
505
|
+
if (el.marks!['data-editify-value']) {
|
506
|
+
marks['data-editify-value'] = el.marks!['data-editify-value']
|
458
507
|
}
|
459
508
|
}
|
460
|
-
|
509
|
+
//行内代码属性保留
|
510
|
+
if (el.parsedom == AlexElement.TEXT_NODE && el.marks!['data-editify-code']) {
|
511
|
+
marks['data-editify-code'] = el.marks!['data-editify-code']
|
512
|
+
}
|
513
|
+
//任务列表属性保留
|
514
|
+
if (el.parsedom == 'div' && el.marks!['data-editify-task']) {
|
515
|
+
marks['data-editify-task'] = el.marks!['data-editify-task']
|
516
|
+
}
|
461
517
|
}
|
462
|
-
|
518
|
+
//处理需要保留的样式
|
463
519
|
if (el.hasStyles()) {
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
520
|
+
//块元素保留text-indent样式
|
521
|
+
if ((el.isBlock() || el.isInblock()) && el.styles!['text-indent']) {
|
522
|
+
styles['text-indent'] = el.styles!['text-indent']
|
523
|
+
}
|
524
|
+
//块元素保留text-align样式
|
525
|
+
if ((el.isBlock() || el.isInblock()) && el.styles!['text-align']) {
|
526
|
+
styles['text-align'] = el.styles!['text-align']
|
527
|
+
}
|
528
|
+
//块元素保留line-height样式
|
529
|
+
if ((el.isBlock() || el.isInblock()) && el.styles!['line-height']) {
|
530
|
+
styles['line-height'] = el.styles!['line-height']
|
531
|
+
}
|
532
|
+
}
|
533
|
+
//注册插件:自定义属性和样式的保留
|
534
|
+
pluginResultList.value.forEach(pluginResult => {
|
535
|
+
if (typeof pluginResult.pasteKeepMarks == 'function') {
|
536
|
+
const keepMarks = pluginResult.pasteKeepMarks(el)
|
537
|
+
marks = mergeObject(marks, keepMarks)!
|
538
|
+
}
|
539
|
+
if (typeof pluginResult.pasteKeepStyles == 'function') {
|
540
|
+
const keepStyles = pluginResult.pasteKeepStyles(el)
|
541
|
+
styles = mergeObject(styles, keepStyles)!
|
468
542
|
}
|
469
|
-
|
543
|
+
})
|
544
|
+
//对外的自定义属性和样式保留
|
545
|
+
if (typeof props.pasteKeepMarks == 'function') {
|
546
|
+
const keepMarks = props.pasteKeepMarks(el)
|
547
|
+
marks = mergeObject(marks, keepMarks)!
|
548
|
+
}
|
549
|
+
if (typeof props.pasteKeepStyles == 'function') {
|
550
|
+
const keepStyles = props.pasteKeepStyles(el)
|
551
|
+
styles = mergeObject(styles, keepStyles)!
|
470
552
|
}
|
553
|
+
//将处理后的样式和标记给元素
|
554
|
+
el.marks = marks
|
555
|
+
el.styles = styles
|
471
556
|
}
|
472
557
|
})
|
473
558
|
//如果使用了自定义粘贴html的功能
|
@@ -501,17 +586,6 @@ const handleCustomMerge = (ele: AlexElement, preEle: AlexElement) => {
|
|
501
586
|
}
|
502
587
|
//针对node转为元素进行额外的处理
|
503
588
|
const handleCustomParseNode = (ele: AlexElement) => {
|
504
|
-
if (ele.parsedom == 'code') {
|
505
|
-
ele.parsedom = 'span'
|
506
|
-
const marks = {
|
507
|
-
'data-editify-code': true
|
508
|
-
}
|
509
|
-
if (ele.hasMarks()) {
|
510
|
-
Object.assign(ele.marks!, marks)
|
511
|
-
} else {
|
512
|
-
ele.marks = marks
|
513
|
-
}
|
514
|
-
}
|
515
589
|
//注册插件:自定义元素转换处理
|
516
590
|
pluginResultList.value.forEach(pluginResult => {
|
517
591
|
if (pluginResult.customParseNode) {
|
package/src/editify/props.ts
CHANGED
@@ -119,14 +119,14 @@ export const EditifyProps = {
|
|
119
119
|
type: Object as PropType<MenuConfigType>,
|
120
120
|
default: null
|
121
121
|
},
|
122
|
-
//粘贴html
|
122
|
+
//粘贴html时对非文本元素额外保留标记的自定义处理
|
123
123
|
pasteKeepMarks: {
|
124
|
-
type:
|
124
|
+
type: Function as PropType<(el: AlexElement) => ObjectType>,
|
125
125
|
default: null
|
126
126
|
},
|
127
|
-
//粘贴html
|
127
|
+
//粘贴html时对非文本元素额外保留样式的自定义处理
|
128
128
|
pasteKeepStyles: {
|
129
|
-
type:
|
129
|
+
type: Function as PropType<(el: AlexElement) => ObjectType>,
|
130
130
|
default: null
|
131
131
|
},
|
132
132
|
//自定义node转元素时的处理
|
@@ -134,6 +134,13 @@ export const EditifyProps = {
|
|
134
134
|
type: Function as PropType<(el: AlexElement) => AlexElement>,
|
135
135
|
default: null
|
136
136
|
},
|
137
|
+
//node转为元素时需要额外保留的标签数组
|
138
|
+
extraKeepTags: {
|
139
|
+
type: Array as PropType<string[]>,
|
140
|
+
default: function () {
|
141
|
+
return []
|
142
|
+
}
|
143
|
+
},
|
137
144
|
//自定义额外的渲染规范
|
138
145
|
renderRules: {
|
139
146
|
type: Array as PropType<((el: AlexElement) => void)[]>,
|
package/src/icon/iconfont.css
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
.editify-icon-mathformula:before {
|
2
|
+
content: '\e616';
|
3
|
+
}
|
4
|
+
|
5
|
+
.editify-icon-separator:before {
|
6
|
+
content: '\e6e5';
|
7
|
+
}
|
8
|
+
|
1
9
|
.editify-icon-attachment:before {
|
2
10
|
content: '\e689';
|
3
11
|
}
|
@@ -98,14 +106,6 @@
|
|
98
106
|
content: '\e620';
|
99
107
|
}
|
100
108
|
|
101
|
-
.editify-icon-width:before {
|
102
|
-
content: '\e674';
|
103
|
-
}
|
104
|
-
|
105
|
-
.editify-icon-edit:before {
|
106
|
-
content: '\e817';
|
107
|
-
}
|
108
|
-
|
109
109
|
.editify-icon-table:before {
|
110
110
|
content: '\e6c4';
|
111
111
|
}
|
@@ -166,14 +166,6 @@
|
|
166
166
|
content: '\e7a1';
|
167
167
|
}
|
168
168
|
|
169
|
-
.editify-icon-paragraph:before {
|
170
|
-
content: '\e7a3';
|
171
|
-
}
|
172
|
-
|
173
|
-
.editify-icon-separator:before {
|
174
|
-
content: '\e7a4';
|
175
|
-
}
|
176
|
-
|
177
169
|
.editify-icon-subscript:before {
|
178
170
|
content: '\e7a5';
|
179
171
|
}
|
package/src/icon/iconfont.ttf
CHANGED
Binary file
|
package/src/icon/iconfont.woff
CHANGED
Binary file
|
package/src/index.ts
CHANGED
@@ -9,9 +9,6 @@ export type { ButtonTypeType, ButtonOptionsItemType, ButtonSelectConfigType, But
|
|
9
9
|
export type { InsertImageUploadErrorType } from './components/insertImage/props'
|
10
10
|
export type { InsertVideoUploadErrorType } from './components/insertVideo/props'
|
11
11
|
export type { MenuButtonType, MenuSelectButtonType, MenuDisplayButtonType, MenuImageButtonType, MenuVideoButtonType, MenuTableButtonType, MenuCustomButtonType, CodeBlockToolbarType, TextToolbarType, ToolbarConfigType, MenuSequenceType, MenuModeType, MenuExtendType, MenuConfigType, PluginType, PluginResultType } from './core/tool'
|
12
|
-
//导出插件相关类型
|
13
|
-
export type { AttachmentOptionsType } from './plugins/attachment'
|
14
|
-
export type { InsertAttachmentUploadErrorType } from './plugins/attachment/insertAttachment/props'
|
15
12
|
|
16
13
|
//导出编辑器操作方法
|
17
14
|
export { getParsedomElementByElement, getCurrentParsedomElement, elementIsInList, elementIsInTask, isList, isTask, hasPreInRange, isRangeInPre, hasQuoteInRange, isRangeInQuote, hasListInRange, isRangeInList, hasTaskInRange, isRangeInTask, hasLinkInRange, hasTableInRange, hasImageInRange, hasVideoInRange, queryTextStyle, queryTextMark, getRangeText, setIndentIncrease, setIndentDecrease, setQuote, setAlign, setList, setTask, setTextStyle, setTextMark, removeTextStyle, removeTextMark, setLineHeight, insertLink, insertImage, insertVideo, insertTable, insertCodeBlock } from './core/function'
|
@@ -21,13 +18,18 @@ const install: FunctionPlugin = (app: App) => {
|
|
21
18
|
app.component(Editify.name!, Editify)
|
22
19
|
}
|
23
20
|
//版本号
|
24
|
-
const version = '0.1.
|
21
|
+
const version = '0.1.39'
|
25
22
|
|
26
23
|
//导出AlexElement元素
|
27
24
|
export { AlexElement } from 'alex-editor'
|
28
25
|
|
29
|
-
|
26
|
+
//导出attachment插件相关的方法和类型
|
27
|
+
export type { AttachmentOptionsType } from './plugins/attachment'
|
28
|
+
export type { InsertAttachmentUploadErrorType } from './plugins/attachment/insertAttachment/props'
|
30
29
|
export { attachment, isAttachment, hasAttachmentInRange } from './plugins/attachment'
|
30
|
+
//导出mathformula插件相关的方法和类型
|
31
|
+
export type { MathformulaOptionsType } from './plugins/mathformula'
|
32
|
+
export { mathformula, isMathformula, isUnderMathformula, getMathformulaElement } from './plugins/mathformula'
|
31
33
|
|
32
34
|
//导出组件和安装函数
|
33
35
|
export { install as default, install, Editify, version }
|
package/src/locale/en_US.ts
CHANGED
@@ -60,6 +60,7 @@ export const en_US: ObjectType = {
|
|
60
60
|
undo: 'Undo',
|
61
61
|
redo: 'Redo',
|
62
62
|
quote: 'Quote',
|
63
|
+
separator: 'Separator',
|
63
64
|
lineHeight: 'Line height',
|
64
65
|
indent: 'Indent',
|
65
66
|
insertLink: 'Insert Link',
|
@@ -85,6 +86,7 @@ export const en_US: ObjectType = {
|
|
85
86
|
defaultLineHeight: 'Default',
|
86
87
|
auto: 'auto',
|
87
88
|
fullScreen: 'Full screen',
|
89
|
+
confirm: 'Confirm',
|
88
90
|
|
89
91
|
//插件语言配置
|
90
92
|
insertAttachment: 'Insert attachment',
|
@@ -93,5 +95,9 @@ export const en_US: ObjectType = {
|
|
93
95
|
attachmentNamePlaceholder: 'Please enter the attachment name',
|
94
96
|
attachmentUrlPlaceholder: 'Please enter the attachment address',
|
95
97
|
attachmentDownloadTitle: 'Click to download attachment',
|
96
|
-
attachmentDefaultName: 'attachment'
|
98
|
+
attachmentDefaultName: 'attachment',
|
99
|
+
|
100
|
+
//数学公式插件语言配置
|
101
|
+
insertMathformula: 'Insert mathematical formula',
|
102
|
+
mathformulaPlaceholder: 'Please enter LaTex syntax'
|
97
103
|
}
|
package/src/locale/zh_CN.ts
CHANGED
@@ -60,6 +60,7 @@ export const zh_CN: ObjectType = {
|
|
60
60
|
undo: '撤销',
|
61
61
|
redo: '重做',
|
62
62
|
quote: '引用',
|
63
|
+
separator: '分隔线',
|
63
64
|
lineHeight: '行高',
|
64
65
|
indent: '缩进',
|
65
66
|
insertLink: '插入链接',
|
@@ -85,13 +86,18 @@ export const zh_CN: ObjectType = {
|
|
85
86
|
defaultLineHeight: '默认行高',
|
86
87
|
auto: '自适应',
|
87
88
|
fullScreen: '全屏',
|
89
|
+
confirm: '确定',
|
88
90
|
|
89
|
-
|
91
|
+
//附件插件语言配置
|
90
92
|
insertAttachment: '插入附件',
|
91
93
|
uploadAttachment: '上传附件',
|
92
94
|
remoteAttachment: '远程地址',
|
93
95
|
attachmentNamePlaceholder: '请输入附件名称',
|
94
96
|
attachmentUrlPlaceholder: '请输入附件地址',
|
95
97
|
attachmentDownloadTitle: '点击下载附件',
|
96
|
-
attachmentDefaultName: '附件'
|
98
|
+
attachmentDefaultName: '附件',
|
99
|
+
|
100
|
+
//数学公式插件语言配置
|
101
|
+
insertMathformula: '插入数学公式',
|
102
|
+
mathformulaPlaceholder: '请输入LaTex语法'
|
97
103
|
}
|
@@ -8,6 +8,7 @@ import InsertAttachment from './insertAttachment/insertAttachment.vue'
|
|
8
8
|
import { InsertAttachmentUploadErrorType } from './insertAttachment/props'
|
9
9
|
import { event as DapEvent, common as DapCommon } from 'dap-util'
|
10
10
|
import { hasLinkInRange, hasPreInRange, hasQuoteInRange } from '../../core/function'
|
11
|
+
import { hasMathformulaInRange } from '../mathformula'
|
11
12
|
|
12
13
|
export type AttachmentOptionsType = {
|
13
14
|
//排序
|
@@ -18,6 +19,8 @@ export type AttachmentOptionsType = {
|
|
18
19
|
leftBorder?: boolean
|
19
20
|
//按钮是否显示右侧边框
|
20
21
|
rightBorder?: boolean
|
22
|
+
//按钮是否禁用
|
23
|
+
disabled?: boolean
|
21
24
|
//定义可选择的文件类型,默认不限制类型,设定此参数后选择文件时会自动过滤非符合的文件类型
|
22
25
|
accept?: string
|
23
26
|
//支持的类型数组
|
@@ -43,7 +46,7 @@ export const isAttachment = (element: AlexElement) => {
|
|
43
46
|
if (element.isEmpty()) {
|
44
47
|
return false
|
45
48
|
}
|
46
|
-
return element.parsedom == 'span' && element.type == 'closed' && element.hasMarks() && element.marks!['data-attachment']
|
49
|
+
return element.parsedom == 'span' && element.type == 'closed' && element.hasMarks() && element.marks!['data-editify-attachment']
|
47
50
|
}
|
48
51
|
|
49
52
|
/**
|
@@ -75,9 +78,9 @@ export const attachment = (options?: AttachmentOptionsType) => {
|
|
75
78
|
}
|
76
79
|
const plugin: PluginType = (editifyInstance: ComponentInternalInstance, editTrans: (key: string) => any) => {
|
77
80
|
let isDisabled = false
|
78
|
-
|
81
|
+
//如果光标范围内有数学公式、链接、代码块和引用则禁用
|
79
82
|
if (editifyInstance.exposed!.editor.value) {
|
80
|
-
isDisabled = hasPreInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasLinkInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasQuoteInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value)
|
83
|
+
isDisabled = hasMathformulaInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasPreInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasLinkInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasQuoteInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value)
|
81
84
|
}
|
82
85
|
return {
|
83
86
|
name: 'attachment',
|
@@ -97,7 +100,8 @@ export const attachment = (options?: AttachmentOptionsType) => {
|
|
97
100
|
leftBorder: options!.leftBorder,
|
98
101
|
rightBorder: options!.rightBorder,
|
99
102
|
hideScroll: true,
|
100
|
-
|
103
|
+
active: false,
|
104
|
+
disabled: isDisabled || options!.disabled,
|
101
105
|
default: () => h(Icon, { value: 'attachment' }),
|
102
106
|
layer: (_name: string, btnInstance: InstanceType<typeof Button>) =>
|
103
107
|
h(InsertAttachment, {
|
@@ -124,23 +128,16 @@ export const attachment = (options?: AttachmentOptionsType) => {
|
|
124
128
|
//遍历地址数组
|
125
129
|
urls.forEach(url => {
|
126
130
|
const marks: ObjectType = {
|
127
|
-
'data-attachment': url,
|
128
|
-
'data-attachment-name': name || editTrans('attachmentDefaultName')
|
129
|
-
contenteditable: 'false'
|
131
|
+
'data-editify-attachment': url,
|
132
|
+
'data-editify-attachment-name': name || editTrans('attachmentDefaultName')
|
130
133
|
}
|
131
134
|
//创建元素
|
132
135
|
const attachmentElement = new AlexElement('closed', 'span', marks, null, null)
|
133
136
|
//插入编辑器
|
134
137
|
editor.insertElement(attachmentElement)
|
135
|
-
//创建空文本元素
|
136
|
-
const beforeText = AlexElement.getSpaceElement()
|
137
|
-
const afterText = AlexElement.getSpaceElement()
|
138
|
-
//将空白文本元素插入附件两端
|
139
|
-
editor.addElementAfter(afterText, attachmentElement)
|
140
|
-
editor.addElementBefore(beforeText, attachmentElement)
|
141
138
|
//移动光标到新插入的元素
|
142
|
-
editor.range!.anchor.
|
143
|
-
editor.range!.focus.
|
139
|
+
editor.range!.anchor.moveToEnd(attachmentElement)
|
140
|
+
editor.range!.focus.moveToEnd(attachmentElement)
|
144
141
|
})
|
145
142
|
//渲染
|
146
143
|
editor.formatElementStack()
|
@@ -157,12 +154,12 @@ export const attachment = (options?: AttachmentOptionsType) => {
|
|
157
154
|
updateView: () => {
|
158
155
|
const editor = <AlexEditor>editifyInstance.exposed!.editor.value
|
159
156
|
AlexElement.flatElements(editor.stack).forEach(el => {
|
160
|
-
if (el.parsedom == 'span' && el.hasMarks() && el.marks!['data-attachment']) {
|
157
|
+
if (el.parsedom == 'span' && el.hasMarks() && el.marks!['data-editify-attachment']) {
|
161
158
|
DapEvent.off(<HTMLElement>el.elm, 'click')
|
162
159
|
//单击下载
|
163
160
|
DapEvent.on(<HTMLElement>el.elm, 'click', async () => {
|
164
161
|
//获取文件地址
|
165
|
-
const url = el.marks!['data-attachment']
|
162
|
+
const url = el.marks!['data-editify-attachment']
|
166
163
|
//使用fetch读取文件地址
|
167
164
|
const res = await fetch(url, {
|
168
165
|
method: 'GET'
|
@@ -173,29 +170,39 @@ export const attachment = (options?: AttachmentOptionsType) => {
|
|
173
170
|
const a = document.createElement('a')
|
174
171
|
a.setAttribute('target', '_blank')
|
175
172
|
a.setAttribute('href', URL.createObjectURL(blob))
|
176
|
-
a.setAttribute('download', el.marks!['data-attachment-name'])
|
173
|
+
a.setAttribute('download', el.marks!['data-editify-attachment-name'])
|
177
174
|
a.click()
|
178
175
|
})
|
179
176
|
}
|
180
177
|
})
|
181
178
|
},
|
182
|
-
//span含有data-attachment的元素设为自闭合元素
|
179
|
+
//span含有data-editify-attachment的元素设为自闭合元素
|
183
180
|
customParseNode: (el: AlexElement) => {
|
184
|
-
if (el.hasMarks() && el.marks!['data-attachment'] && el.parsedom == 'span') {
|
181
|
+
if (el.hasMarks() && el.marks!['data-editify-attachment'] && el.parsedom == 'span') {
|
185
182
|
el.type = 'closed'
|
186
183
|
}
|
187
184
|
return el
|
188
185
|
},
|
189
|
-
|
190
|
-
pasteKeepMarks: {
|
191
|
-
|
192
|
-
'
|
186
|
+
//附件文件自定义保留的标记
|
187
|
+
pasteKeepMarks: el => {
|
188
|
+
const marks: ObjectType = {}
|
189
|
+
if (el.parsedom == 'span' && el.hasMarks() && el.marks!['data-editify-attachment']) {
|
190
|
+
marks['data-editify-attachment'] = el.marks!['data-editify-attachment']
|
191
|
+
if (el.marks!['data-editify-attachment-name']) {
|
192
|
+
marks['data-editify-attachment-name'] = el.marks!['data-editify-attachment-name']
|
193
|
+
}
|
194
|
+
}
|
195
|
+
return marks
|
193
196
|
},
|
194
197
|
//自定义渲染规范
|
195
198
|
renderRule: (el: AlexElement) => {
|
196
|
-
if (el.
|
199
|
+
if (el.hasMarks() && el.marks!['data-editify-attachment']) {
|
197
200
|
//设置title
|
198
201
|
el.marks!['title'] = editTrans('attachmentDownloadTitle')
|
202
|
+
//如果名称没有则设置名称
|
203
|
+
if (!el.marks!['data-editify-attachment-name']) {
|
204
|
+
el.marks!['data-editify-attachment-name'] = editTrans('attachmentDefaultName')
|
205
|
+
}
|
199
206
|
//获取editor对象
|
200
207
|
const editor = <AlexEditor>editifyInstance.exposed!.editor.value
|
201
208
|
//前一个元素
|
@@ -212,6 +219,13 @@ export const attachment = (options?: AttachmentOptionsType) => {
|
|
212
219
|
const spaceText = AlexElement.getSpaceElement()
|
213
220
|
editor.addElementAfter(spaceText, el)
|
214
221
|
}
|
222
|
+
//如果光标在元素上则更新光标位置
|
223
|
+
if (editor.range && el.isContains(editor.range.anchor.element)) {
|
224
|
+
editor.range.anchor.moveToEnd(editor.getNextElement(el)!)
|
225
|
+
}
|
226
|
+
if (editor.range && el.isContains(editor.range.focus.element)) {
|
227
|
+
editor.range.focus.moveToEnd(editor.getNextElement(el)!)
|
228
|
+
}
|
215
229
|
}
|
216
230
|
}
|
217
231
|
}
|