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.
Files changed (58) hide show
  1. package/examples/App.vue +5 -8
  2. package/lib/components/button/button.vue.d.ts +13 -13
  3. package/lib/components/button/props.d.ts +1 -1
  4. package/lib/components/checkbox/checkbox.vue.d.ts +10 -10
  5. package/lib/components/checkbox/props.d.ts +1 -1
  6. package/lib/components/colors/colors.vue.d.ts +6 -6
  7. package/lib/components/colors/props.d.ts +1 -1
  8. package/lib/components/icon/icon.vue.d.ts +1 -1
  9. package/lib/components/insertImage/insertImage.vue.d.ts +11 -11
  10. package/lib/components/insertLink/insertLink.vue.d.ts +4 -4
  11. package/lib/components/insertTable/insertTable.vue.d.ts +4 -4
  12. package/lib/components/insertVideo/insertVideo.vue.d.ts +11 -11
  13. package/lib/components/layer/layer.vue.d.ts +9 -9
  14. package/lib/components/menu/menu.vue.d.ts +6 -6
  15. package/lib/components/menu/props.d.ts +1 -1
  16. package/lib/components/toolbar/props.d.ts +1 -1
  17. package/lib/components/toolbar/toolbar.vue.d.ts +11 -11
  18. package/lib/components/tooltip/tooltip.vue.d.ts +1 -1
  19. package/lib/components/triangle/triangle.vue.d.ts +4 -4
  20. package/lib/core/function.d.ts +8 -1
  21. package/lib/core/rule.d.ts +3 -3
  22. package/lib/core/tool.d.ts +9 -11
  23. package/lib/editify/editify.vue.d.ts +110 -84
  24. package/lib/editify/props.d.ts +9 -5
  25. package/lib/editify.es.js +15226 -418
  26. package/lib/editify.umd.js +1 -1
  27. package/lib/index.d.ts +6 -4
  28. package/lib/plugins/attachment/index.d.ts +3 -2
  29. package/lib/plugins/attachment/insertAttachment/insertAttachment.vue.d.ts +11 -11
  30. package/lib/plugins/mathformula/index.d.ts +31 -0
  31. package/lib/plugins/mathformula/insertMathformula/insertMathformula.vue.d.ts +18 -0
  32. package/lib/plugins/mathformula/insertMathformula/props.d.ts +9 -0
  33. package/lib/style.css +1 -1
  34. package/package.json +4 -2
  35. package/src/components/insertImage/insertImage.less +1 -0
  36. package/src/components/insertLink/insertLink.less +1 -0
  37. package/src/components/insertVideo/insertVideo.less +1 -0
  38. package/src/components/menu/menu.vue +33 -1
  39. package/src/components/tooltip/tooltip.less +2 -2
  40. package/src/core/function.ts +18 -6
  41. package/src/core/rule.ts +34 -11
  42. package/src/core/tool.ts +48 -67
  43. package/src/css/base.less +2 -0
  44. package/src/editify/editify.less +12 -3
  45. package/src/editify/editify.vue +113 -39
  46. package/src/editify/props.ts +11 -4
  47. package/src/icon/iconfont.css +8 -16
  48. package/src/icon/iconfont.ttf +0 -0
  49. package/src/icon/iconfont.woff +0 -0
  50. package/src/index.ts +7 -5
  51. package/src/locale/en_US.ts +7 -1
  52. package/src/locale/zh_CN.ts +8 -2
  53. package/src/plugins/attachment/index.ts +39 -25
  54. package/src/plugins/attachment/insertAttachment/insertAttachment.less +1 -0
  55. package/src/plugins/mathformula/index.ts +210 -0
  56. package/src/plugins/mathformula/insertMathformula/insertMathformula.less +64 -0
  57. package/src/plugins/mathformula/insertMathformula/insertMathformula.vue +40 -0
  58. package/src/plugins/mathformula/insertMathformula/props.ts +11 -0
@@ -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 { pasteKeepData, mergeObject, getToolbarConfig, getMenuConfig, MenuConfigType, ObjectType, ToolbarConfigType, PluginResultType } from '../core/tool'
26
- import { parseList, orderdListHandle, mediaHandle, tableHandle, preHandle, specialInblockHandle } from '../core/rule'
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
- mediaHandle(editor.value!, el)
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
- for (let key in keepMarks) {
456
- if (el.marks!.hasOwnProperty(key) && ((Array.isArray(keepMarks[key]) && keepMarks[key].includes(el.parsedom)) || keepMarks[key] == '*')) {
457
- marks[key] = el.marks![key]
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
- el.marks = marks
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
- for (let key in keepStyles) {
465
- if (el.styles!.hasOwnProperty(key) && ((Array.isArray(keepStyles[key]) && keepStyles[key].includes(el.parsedom)) || keepStyles[key] == '*')) {
466
- styles[key] = el.styles![key]
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
- el.styles = styles
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) {
@@ -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: Object as PropType<ObjectType>,
124
+ type: Function as PropType<(el: AlexElement) => ObjectType>,
125
125
  default: null
126
126
  },
127
- //粘贴html时额外保留的样式(仅在非文本元素生效)
127
+ //粘贴html时对非文本元素额外保留样式的自定义处理
128
128
  pasteKeepStyles: {
129
- type: Object as PropType<ObjectType>,
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)[]>,
@@ -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
  }
Binary file
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.36'
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 }
@@ -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
  }
@@ -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
- disabled: isDisabled,
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.moveToStart(afterText)
143
- editor.range!.focus.moveToStart(afterText)
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
- //span元素粘贴保留data-attachment
190
- pasteKeepMarks: {
191
- 'data-attachment': ['span'],
192
- 'data-attachment-name': ['span']
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.type == 'closed' && el.hasMarks() && el.marks!['data-attachment']) {
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
  }
@@ -130,6 +130,7 @@
130
130
  background-color: transparent;
131
131
  outline: none;
132
132
  box-sizing: border-box;
133
+ font-family: inherit;
133
134
 
134
135
  &::-webkit-input-placeholder,
135
136
  &::placeholder {