vue-editify 0.1.36 → 0.1.39

Sign up to get free protection for your applications and to get access to all the features.
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 {