vue-editify 0.1.22 → 0.1.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. package/examples/App.vue +8 -2
  2. package/lib/components/button/button.vue.d.ts +3 -3
  3. package/lib/components/button/props.d.ts +1 -1
  4. package/lib/components/checkbox/checkbox.vue.d.ts +3 -3
  5. package/lib/components/checkbox/props.d.ts +1 -1
  6. package/lib/components/colors/colors.vue.d.ts +3 -3
  7. package/lib/components/colors/props.d.ts +1 -1
  8. package/lib/components/insertImage/insertImage.vue.d.ts +6 -6
  9. package/lib/components/insertImage/props.d.ts +2 -2
  10. package/lib/components/insertLink/insertLink.vue.d.ts +3 -3
  11. package/lib/components/insertLink/props.d.ts +2 -2
  12. package/lib/components/insertTable/insertTable.vue.d.ts +3 -3
  13. package/lib/components/insertTable/props.d.ts +2 -2
  14. package/lib/components/insertVideo/insertVideo.vue.d.ts +6 -6
  15. package/lib/components/insertVideo/props.d.ts +2 -2
  16. package/lib/components/menu/menu.vue.d.ts +3 -3
  17. package/lib/components/menu/props.d.ts +1 -1
  18. package/lib/components/toolbar/props.d.ts +1 -1
  19. package/lib/components/toolbar/toolbar.vue.d.ts +3 -3
  20. package/lib/core/rule.d.ts +1 -1
  21. package/lib/core/tool.d.ts +19 -9
  22. package/lib/editify/editify.vue.d.ts +12 -3
  23. package/lib/editify/props.d.ts +6 -2
  24. package/lib/editify.es.js +577 -182
  25. package/lib/editify.umd.js +1 -1
  26. package/lib/index.d.ts +7 -4
  27. package/lib/plugins/attachment/index.d.ts +17 -0
  28. package/lib/plugins/attachment/insertAttachment/insertAttachment.vue.d.ts +83 -0
  29. package/lib/plugins/attachment/insertAttachment/props.d.ts +38 -0
  30. package/lib/style.css +1 -1
  31. package/package.json +1 -1
  32. package/src/components/button/button.vue +4 -1
  33. package/src/components/button/props.ts +1 -1
  34. package/src/components/checkbox/props.ts +1 -1
  35. package/src/components/colors/colors.vue +1 -1
  36. package/src/components/colors/props.ts +1 -1
  37. package/src/components/insertImage/insertImage.vue +12 -10
  38. package/src/components/insertImage/props.ts +2 -2
  39. package/src/components/insertLink/insertLink.vue +1 -1
  40. package/src/components/insertLink/props.ts +2 -2
  41. package/src/components/insertTable/props.ts +2 -2
  42. package/src/components/insertVideo/insertVideo.vue +12 -10
  43. package/src/components/insertVideo/props.ts +2 -2
  44. package/src/components/menu/menu.vue +28 -13
  45. package/src/components/menu/props.ts +1 -1
  46. package/src/components/toolbar/props.ts +1 -1
  47. package/src/components/toolbar/toolbar.vue +3 -4
  48. package/src/core/function.ts +5 -5
  49. package/src/core/rule.ts +1 -1
  50. package/src/core/tool.ts +24 -11
  51. package/src/editify/editify.less +27 -0
  52. package/src/editify/editify.vue +54 -10
  53. package/src/editify/props.ts +9 -2
  54. package/src/icon/iconfont.css +4 -0
  55. package/src/icon/iconfont.ttf +0 -0
  56. package/src/icon/iconfont.woff +0 -0
  57. package/src/index.ts +13 -8
  58. package/src/locale/en_US.ts +9 -1
  59. package/src/locale/zh_CN.ts +9 -1
  60. package/src/plugins/attachment/images/attachment.png +0 -0
  61. package/src/plugins/attachment/index.ts +123 -0
  62. package/src/plugins/attachment/insertAttachment/insertAttachment.less +135 -0
  63. package/src/plugins/attachment/insertAttachment/insertAttachment.vue +189 -0
  64. package/src/plugins/attachment/insertAttachment/props.ts +48 -0
@@ -1,9 +1,9 @@
1
- import { ExtractPublicPropTypes } from 'vue'
1
+ import { ExtractPublicPropTypes, PropType } from 'vue'
2
2
 
3
3
  export const InsertLinkProps = {
4
4
  //主题色
5
5
  color: {
6
- type: String,
6
+ type: String as PropType<string | null>,
7
7
  default: ''
8
8
  },
9
9
  //预置的链接文本值
@@ -1,4 +1,4 @@
1
- import { ExtractPublicPropTypes } from 'vue'
1
+ import { ExtractPublicPropTypes, PropType } from 'vue'
2
2
 
3
3
  export type InsertTableGridType = {
4
4
  x: number
@@ -9,7 +9,7 @@ export type InsertTableGridType = {
9
9
  export const InsertTableProps = {
10
10
  //主题色
11
11
  color: {
12
- type: String,
12
+ type: String as PropType<string | null>,
13
13
  default: ''
14
14
  },
15
15
  //最大行数
@@ -8,7 +8,7 @@
8
8
  <!-- 网络视频 -->
9
9
  <div class="editify-video-remote" v-if="current == 'remote'">
10
10
  <input v-model.trim="remoteUrl" :placeholder="$editTrans('videoUrlPlaceholder')" @blur="handleInputBlur" @focus="handleInputFocus" />
11
- <div class="editify-video-remote-footer" :style="{ color: color }">
11
+ <div class="editify-video-remote-footer" :style="{ color: color || '' }">
12
12
  <span @click="insertRemoteVideo">{{ $editTrans('insert') }}</span>
13
13
  </div>
14
14
  </div>
@@ -23,7 +23,7 @@
23
23
  import { file as DapFile } from 'dap-util'
24
24
  import Icon from '../icon/icon.vue'
25
25
  import { InsertVideoProps } from './props'
26
- import { ComponentInternalInstance, computed, inject, ref, watch } from 'vue'
26
+ import { computed, inject, ref, watch } from 'vue'
27
27
  import { ObjectType } from '../../core/tool'
28
28
 
29
29
  defineOptions({
@@ -33,7 +33,6 @@ const props = defineProps(InsertVideoProps)
33
33
  const emits = defineEmits(['change', 'insert'])
34
34
 
35
35
  const $editTrans = inject<(key: string) => any>('$editTrans')!
36
- const editify = inject<ComponentInternalInstance>('editify')!
37
36
 
38
37
  //当前展示的面板,取值remote和upload
39
38
  const current = ref<'remote' | 'upload'>('upload')
@@ -84,14 +83,17 @@ const selectFile = async (e: Event) => {
84
83
  for (let i = 0; i < files.length; i++) {
85
84
  const file = files[i]
86
85
  const suffix = getSuffix(file)
87
- const isMatch = props.accept.some(item => {
88
- return item.toLocaleLowerCase() == suffix.toLocaleLowerCase()
89
- })
86
+ const isMatch =
87
+ props.allowedFileType && Array.isArray(props.allowedFileType) && props.allowedFileType.length
88
+ ? props.allowedFileType.some(item => {
89
+ return item.toLocaleLowerCase() == suffix.toLocaleLowerCase()
90
+ })
91
+ : true
90
92
  //后缀不符合
91
93
  if (!isMatch) {
92
94
  //如果自定义了异常处理
93
95
  if (typeof props.handleError == 'function') {
94
- props.handleError.apply(editify.proxy!, ['suffixError', file])
96
+ props.handleError('suffixError', file)
95
97
  }
96
98
  continue
97
99
  }
@@ -99,7 +101,7 @@ const selectFile = async (e: Event) => {
99
101
  if (props.maxSize && file.size / 1024 > props.maxSize) {
100
102
  //如果自定义了异常处理
101
103
  if (typeof props.handleError == 'function') {
102
- props.handleError.apply(editify.proxy!, ['maxSizeError', file])
104
+ props.handleError('maxSizeError', file)
103
105
  }
104
106
  continue
105
107
  }
@@ -107,7 +109,7 @@ const selectFile = async (e: Event) => {
107
109
  if (props.minSize && file.size / 1024 < props.minSize) {
108
110
  //如果自定义了异常处理
109
111
  if (typeof props.handleError == 'function') {
110
- props.handleError.apply(editify.proxy!, ['minSizeError', file])
112
+ props.handleError('minSizeError', file)
111
113
  }
112
114
  continue
113
115
  }
@@ -118,7 +120,7 @@ const selectFile = async (e: Event) => {
118
120
  let videos = []
119
121
  //自定义上传方法
120
122
  if (typeof props.customUpload == 'function') {
121
- videos = (await props.customUpload.apply(editify.proxy!, [filterFiles])) || []
123
+ videos = (await props.customUpload(filterFiles)) || []
122
124
  }
123
125
  //默认上传方法
124
126
  else {
@@ -5,11 +5,11 @@ export type InsertVideoUploadErrorType = 'suffixError' | 'maxSizeError' | 'minSi
5
5
  export const InsertVideoProps = {
6
6
  //主题色
7
7
  color: {
8
- type: String,
8
+ type: String as PropType<string | null>,
9
9
  default: ''
10
10
  },
11
11
  //支持的视频类型数组
12
- accept: {
12
+ allowedFileType: {
13
13
  type: Array as PropType<string[]>,
14
14
  default: null
15
15
  },
@@ -17,7 +17,7 @@ import { common as DapCommon } from 'dap-util'
17
17
  import { getRangeText, setHeading, setIndentIncrease, setIndentDecrease, setQuote, setAlign, setList, setTask, setTextStyle, setTextMark, removeTextStyle, removeTextMark, setLineHeight, insertLink, insertImage, insertVideo, insertTable, insertCodeBlock, hasPreInRange, hasTableInRange, hasQuoteInRange, hasLinkInRange, isRangeInQuote, isRangeInList, isRangeInTask, queryTextStyle, queryTextMark, getCurrentParsedomElement } from '../../core/function'
18
18
  import { MenuProps } from './props'
19
19
  import { MenuModeType, ObjectType } from '../../core/tool'
20
- import AlexEditor, { AlexElementsRangeType } from 'alex-editor'
20
+ import { AlexEditor, AlexElementsRangeType } from 'alex-editor'
21
21
  import { ButtonOptionsItemType } from '../button/props'
22
22
 
23
23
  defineOptions({
@@ -273,7 +273,7 @@ const imageConfig = ref<ObjectType>({
273
273
  rightBorder: props.config.image!.rightBorder,
274
274
  active: false,
275
275
  disabled: false,
276
- accept: props.config.image!.accept,
276
+ allowedFileType: props.config.image!.allowedFileType,
277
277
  multiple: props.config.image!.multiple,
278
278
  maxSize: props.config.image!.maxSize,
279
279
  minSize: props.config.image!.minSize,
@@ -287,7 +287,7 @@ const videoConfig = ref<ObjectType>({
287
287
  rightBorder: props.config.video!.rightBorder,
288
288
  active: false,
289
289
  disabled: false,
290
- accept: props.config.video!.accept,
290
+ allowedFileType: props.config.video!.allowedFileType,
291
291
  multiple: props.config.video!.multiple,
292
292
  maxSize: props.config.video!.maxSize,
293
293
  minSize: props.config.video!.minSize,
@@ -668,7 +668,7 @@ const handleRangeUpdate = () => {
668
668
  //额外禁用判定
669
669
  const extraDisabled = (name: string) => {
670
670
  if (typeof props.config.extraDisabled == 'function') {
671
- return props.config.extraDisabled.apply(editify.proxy!, [name]) || false
671
+ return props.config.extraDisabled(name) || false
672
672
  }
673
673
  return false
674
674
  }
@@ -1342,7 +1342,7 @@ const MenuItem = defineComponent(
1342
1342
  layer: () =>
1343
1343
  h(InsertImage, {
1344
1344
  color: props.color,
1345
- accept: imageConfig.value.accept,
1345
+ allowedFileType: imageConfig.value.allowedFileType,
1346
1346
  multiple: imageConfig.value.multiple,
1347
1347
  maxSize: imageConfig.value.maxSize,
1348
1348
  minSize: imageConfig.value.minSize,
@@ -1386,7 +1386,7 @@ const MenuItem = defineComponent(
1386
1386
  layer: () =>
1387
1387
  h(InsertVideo, {
1388
1388
  color: props.color,
1389
- accept: videoConfig.value.accept,
1389
+ allowedFileType: videoConfig.value.allowedFileType,
1390
1390
  multiple: videoConfig.value.multiple,
1391
1391
  maxSize: videoConfig.value.maxSize,
1392
1392
  minSize: videoConfig.value.minSize,
@@ -1524,29 +1524,44 @@ const MenuItem = defineComponent(
1524
1524
  color: props.color,
1525
1525
  onLayerShow: () => {
1526
1526
  if (typeof configuration.onLayerShow == 'function') {
1527
- configuration.onLayerShow.apply(editify.proxy!, [itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef])
1527
+ configuration.onLayerShow(itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef)
1528
1528
  }
1529
1529
  },
1530
1530
  onLayerShown: () => {
1531
1531
  if (typeof configuration.onLayerShown == 'function') {
1532
- configuration.onLayerShown.apply(editify.proxy!, [itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef])
1532
+ configuration.onLayerShown(itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef)
1533
1533
  }
1534
1534
  },
1535
1535
  onLayerHidden: () => {
1536
1536
  if (typeof configuration.onLayerHidden == 'function') {
1537
- configuration.onLayerHidden.apply(editify.proxy!, [itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef])
1537
+ configuration.onLayerHidden(itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef)
1538
1538
  }
1539
1539
  },
1540
1540
  onOperate: (name, val) => {
1541
1541
  if (typeof configuration.onOperate == 'function') {
1542
- configuration.onOperate.apply(editify.proxy!, [name, val, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef])
1542
+ configuration.onOperate(name, val, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef)
1543
1543
  }
1544
1544
  }
1545
1545
  },
1546
1546
  {
1547
- default: configuration.default || null,
1548
- layer: configuration.layer || null,
1549
- option: configuration.option || null
1547
+ default: () => {
1548
+ if (configuration.default) {
1549
+ return configuration.default(itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef)
1550
+ }
1551
+ return null
1552
+ },
1553
+ layer: () => {
1554
+ if (configuration.layer) {
1555
+ return configuration.layer(itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef)
1556
+ }
1557
+ return null
1558
+ },
1559
+ option: () => {
1560
+ if (configuration.option) {
1561
+ return configuration.option(itemProps.name, <InstanceType<typeof Button>>itemInstance.proxy!.$refs.btnRef)
1562
+ }
1563
+ return null
1564
+ }
1550
1565
  }
1551
1566
  )
1552
1567
  }
@@ -9,7 +9,7 @@ export const MenuProps = {
9
9
  },
10
10
  //主题色
11
11
  color: {
12
- type: String,
12
+ type: String as PropType<string | null>,
13
13
  default: ''
14
14
  }
15
15
  }
@@ -27,7 +27,7 @@ export const ToolbarProps = {
27
27
  },
28
28
  //主题色
29
29
  color: {
30
- type: String,
30
+ type: String as PropType<string | null>,
31
31
  default: ''
32
32
  }
33
33
  }
@@ -10,7 +10,7 @@
10
10
  <Checkbox @change="modifyLink" v-model="linkConfig.newOpen" :label="$editTrans('newWindowOpen')" :color="color" :size="10"></Checkbox>
11
11
  <div class="editify-toolbar-link-operations">
12
12
  <span @click="removeLink">{{ $editTrans('removeLink') }}</span>
13
- <a :href="linkConfig.url" target="_blank" :style="{ color: color }">{{ $editTrans('viewLink') }}</a>
13
+ <a :href="linkConfig.url" target="_blank" :style="{ color: color || '' }">{{ $editTrans('viewLink') }}</a>
14
14
  </div>
15
15
  </div>
16
16
  </div>
@@ -203,7 +203,7 @@ import { AlexEditor, AlexElement, AlexElementsRangeType } from 'alex-editor'
203
203
  import { common as DapCommon } from 'dap-util'
204
204
  import { getCurrentParsedomElement, removeTextStyle, removeTextMark, setTextStyle, setLineHeight, setTextMark, setList, setTask, setHeading, setAlign, isRangeInList, isRangeInTask, queryTextStyle, queryTextMark } from '../../core/function'
205
205
  import { ToolbarProps } from './props'
206
- import { ComponentInternalInstance, Ref, computed, inject, ref } from 'vue'
206
+ import { Ref, computed, inject, ref } from 'vue'
207
207
  import { ObjectType } from '../../core/tool'
208
208
  import { ButtonOptionsItemType } from '../button/props'
209
209
 
@@ -213,7 +213,6 @@ defineOptions({
213
213
  const props = defineProps(ToolbarProps)
214
214
  const emits = defineEmits(['update:modelValue'])
215
215
 
216
- const editify = inject<ComponentInternalInstance>('editify')!
217
216
  const editor = inject<Ref<AlexEditor>>('editor')!
218
217
  const dataRangeCaches = inject<Ref<AlexElementsRangeType>>('dataRangeCaches')!
219
218
  const $editTrans = inject<(key: string) => any>('$editTrans')!
@@ -953,7 +952,7 @@ const layerShow = () => {
953
952
  //额外禁用判定
954
953
  const extraDisabled = (name: string) => {
955
954
  if (typeof props.config.extraDisabled == 'function') {
956
- return props.config.extraDisabled.apply(editify.proxy!, [name]) || false
955
+ return props.config.extraDisabled(name) || false
957
956
  }
958
957
  return false
959
958
  }
@@ -77,7 +77,7 @@ export const elementIsInTask = (element: AlexElement): boolean => {
77
77
  }
78
78
 
79
79
  //判断元素是否有序或者无序列表
80
- export const isList = function (element: AlexElement, ordered: boolean | undefined = false) {
80
+ export const isList = (element: AlexElement, ordered: boolean | undefined = false) => {
81
81
  if (element.isEmpty()) {
82
82
  return false
83
83
  }
@@ -85,7 +85,7 @@ export const isList = function (element: AlexElement, ordered: boolean | undefin
85
85
  }
86
86
 
87
87
  //判断元素是否任务列表
88
- export const isTask = function (element: AlexElement) {
88
+ export const isTask = (element: AlexElement) => {
89
89
  if (element.isEmpty()) {
90
90
  return false
91
91
  }
@@ -394,14 +394,14 @@ export const getFlatElementsByRange = (editor: AlexEditor, dataRangeCaches: Alex
394
394
  }
395
395
 
396
396
  //将某个元素转为段落标签
397
- export const elementToParagraph = function (element: AlexElement) {
397
+ export const elementToParagraph = (element: AlexElement) => {
398
398
  element.marks = null
399
399
  element.styles = null
400
400
  element.parsedom = AlexElement.BLOCK_NODE
401
401
  }
402
402
 
403
403
  //其他元素转为有序或者无序列表
404
- export const elementToList = function (element: AlexElement, ordered: boolean | undefined = false) {
404
+ export const elementToList = (element: AlexElement, ordered: boolean | undefined = false) => {
405
405
  //如果是列表则返回
406
406
  if (isList(element, ordered)) {
407
407
  return
@@ -417,7 +417,7 @@ export const elementToList = function (element: AlexElement, ordered: boolean |
417
417
  }
418
418
 
419
419
  //其他元素转为任务列表
420
- export const elementToTask = function (element: AlexElement) {
420
+ export const elementToTask = (element: AlexElement) => {
421
421
  //如果是任务列表则返回
422
422
  if (isTask(element)) {
423
423
  return
package/src/core/rule.ts CHANGED
@@ -1,4 +1,4 @@
1
- import AlexEditor, { AlexElement } from 'alex-editor'
1
+ import { AlexEditor, AlexElement } from 'alex-editor'
2
2
  import { LanguagesItemType, getHljsHtml } from '../hljs'
3
3
  import { getColNumbers } from './tool'
4
4
  import { isList, isTask } from './function'
package/src/core/tool.ts CHANGED
@@ -4,7 +4,7 @@ import { AlexElement } from 'alex-editor'
4
4
  import { ButtonOptionsItemType, ButtonTypeType } from '../components/button/props'
5
5
  import { LocaleType } from '../locale'
6
6
  import { InsertImageUploadErrorType } from '../components/insertImage/props'
7
- import { VNode } from 'vue'
7
+ import { ComponentInternalInstance, VNode } from 'vue'
8
8
  import Button from '../components/button/button.vue'
9
9
 
10
10
  export type ObjectType = {
@@ -39,7 +39,7 @@ export interface MenuDisplayButtonType extends MenuSelectButtonType {
39
39
  }
40
40
 
41
41
  export interface MenuImageButtonType extends MenuButtonType {
42
- accept?: string[]
42
+ allowedFileType?: string[]
43
43
  multiple?: boolean
44
44
  maxSize?: number | null
45
45
  minSize?: number | null
@@ -48,7 +48,7 @@ export interface MenuImageButtonType extends MenuButtonType {
48
48
  }
49
49
 
50
50
  export interface MenuVideoButtonType extends MenuButtonType {
51
- accept?: string[]
51
+ allowedFileType?: string[]
52
52
  multiple?: boolean
53
53
  maxSize?: number | null
54
54
  minSize?: number | null
@@ -77,9 +77,9 @@ export type MenuCustomButtonType = {
77
77
  onLayerShown?: (name: string, btnInstance: InstanceType<typeof Button>) => void
78
78
  onLayerHidden?: (name: string, btnInstance: InstanceType<typeof Button>) => void
79
79
  onOperate?: (name: string, value: string | number | undefined, btnInstance: InstanceType<typeof Button>) => void
80
- default?: () => VNode
81
- layer?: () => VNode
82
- option?: () => VNode
80
+ default?: (name: string, btnInstance: InstanceType<typeof Button>) => VNode
81
+ layer?: (name: string, btnInstance: InstanceType<typeof Button>) => VNode
82
+ option?: (name: string, btnInstance: InstanceType<typeof Button>) => VNode
83
83
  }
84
84
 
85
85
  export type CodeBlockToolbarType = {
@@ -151,6 +151,10 @@ export type MenuSequenceType = {
151
151
 
152
152
  export type MenuModeType = 'default' | 'inner' | 'fixed'
153
153
 
154
+ export type MenuExtendType = {
155
+ [name: string]: MenuCustomButtonType
156
+ }
157
+
154
158
  export type MenuConfigType = {
155
159
  use?: boolean
156
160
  tooltip?: boolean
@@ -191,11 +195,20 @@ export type MenuConfigType = {
191
195
  //全屏
192
196
  fullScreen?: MenuButtonType
193
197
  //拓展菜单,每个key表示拓展菜单的唯一名称,value是对象,包含type/title/rightBorder/leftBorder/disabled/active/width/maxHeight/options/value/hideScroll/onLayerShow/onLayerShown/onLayerHidden/onOperate/default/layer/option属性
194
- extends?: {
195
- [name: string]: MenuCustomButtonType
196
- }
198
+ extends?: MenuExtendType
197
199
  }
198
200
 
201
+ export type PluginResultType = {
202
+ menu?: MenuConfigType
203
+ updateView?: () => void
204
+ customParseNode?: (element: AlexElement) => AlexElement
205
+ renderRule?: (el: AlexElement) => void
206
+ pasteKeepStyles?: ObjectType
207
+ pasteKeepMarks?: ObjectType
208
+ }
209
+
210
+ export type PluginType = (editifyInstance: ComponentInternalInstance, color: string | null, editTrans: (key: string) => any) => PluginResultType
211
+
199
212
  //粘贴html时保留的数据
200
213
  export const pasteKeepData: ObjectType = {
201
214
  //粘贴html时元素保留的样式(全部元素)
@@ -1058,7 +1071,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
1058
1071
  //右侧边框是否显示
1059
1072
  rightBorder: false,
1060
1073
  //图片支持上传的类型,不区分大小写
1061
- accept: ['jpg', 'png', 'jpeg', 'webp', 'jfif', 'ico', 'gif', 'svg', 'psd'],
1074
+ allowedFileType: ['jpg', 'png', 'jpeg', 'webp', 'jfif', 'ico', 'gif', 'svg', 'psd'],
1062
1075
  //是否多选图片
1063
1076
  multiple: false,
1064
1077
  //单张图片的最大值,单位kb
@@ -1079,7 +1092,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
1079
1092
  //右侧边框是否显示
1080
1093
  rightBorder: false,
1081
1094
  //视频支持上传的类型,不区分大小写
1082
- accept: ['mp4', 'avi', 'mpg', 'wmv', 'mov', 'rm', 'swf', 'flv'],
1095
+ allowedFileType: ['mp4', 'avi', 'mpg', 'wmv', 'mov', 'rm', 'swf', 'flv'],
1083
1096
  //是否多选视频
1084
1097
  multiple: false,
1085
1098
  //单个视频的的最大值,单位kb
@@ -342,6 +342,33 @@
342
342
  }
343
343
  }
344
344
 
345
+ //附件样式
346
+ :deep(span[data-attachment]) {
347
+ display: inline-block;
348
+ width: 40px;
349
+ height: 40px;
350
+ background-color: @font-color-link;
351
+ transition: all 200ms;
352
+ position: relative;
353
+ border-radius: 4px;
354
+
355
+ &:hover {
356
+ background-color: @font-color-link-dark;
357
+ cursor: pointer;
358
+ }
359
+
360
+ &::before {
361
+ content: '';
362
+ position: absolute;
363
+ left: 8px;
364
+ top: 8px;
365
+ width: 24px;
366
+ height: 24px;
367
+ background: url(../plugins/attachment/images/attachment.png) no-repeat center;
368
+ background-size: cover;
369
+ }
370
+ }
371
+
345
372
  //禁用样式
346
373
  &.editify-disabled {
347
374
  cursor: auto !important;
@@ -22,7 +22,7 @@
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 } from '../core/tool'
25
+ import { pasteKeepData, mergeObject, getToolbarConfig, getMenuConfig, MenuConfigType, ObjectType, ToolbarConfigType, PluginResultType } from '../core/tool'
26
26
  import { parseList, orderdListHandle, mediaHandle, 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'
@@ -124,9 +124,26 @@ const showBorder = computed<boolean>(() => {
124
124
  const toolbarConfig = computed<ToolbarConfigType>(() => {
125
125
  return <ToolbarConfigType>mergeObject(getToolbarConfig($editTrans, props.locale), props.toolbar || {})
126
126
  })
127
+ //插件配置读取
128
+ const pluginResultList = computed<PluginResultType[]>(() => {
129
+ const pluginResultList: PluginResultType[] = []
130
+ props.plugins.forEach(plugin => {
131
+ let pluginResult = plugin(instance, props.color, $editTrans)
132
+ pluginResultList.push(pluginResult)
133
+ })
134
+ return pluginResultList
135
+ })
127
136
  //最终生效的菜单栏配置
128
137
  const menuConfig = computed<MenuConfigType>(() => {
129
- return <MenuConfigType>mergeObject(getMenuConfig($editTrans, props.locale), props.menu || {})
138
+ let menu: MenuConfigType = {}
139
+ //注册插件:自定义菜单栏
140
+ pluginResultList.value.forEach(pluginResult => {
141
+ menu = <MenuConfigType>mergeObject(menu, pluginResult.menu || {})
142
+ })
143
+ //加入自定义menu配置
144
+ menu = <MenuConfigType>mergeObject(menu, props.menu || {})
145
+ //返回最终配置
146
+ return <MenuConfigType>mergeObject(getMenuConfig($editTrans, props.locale), menu)
130
147
  })
131
148
 
132
149
  //编辑器内部修改值的方法
@@ -235,6 +252,13 @@ const handleToolbar = () => {
235
252
  }
236
253
  //初始创建编辑器
237
254
  const createEditor = () => {
255
+ //注册插件:自定义规则校验函数
256
+ let pluginRules: ((el: AlexElement) => void)[] = []
257
+ pluginResultList.value.forEach(pluginResult => {
258
+ if (pluginResult.renderRule) {
259
+ pluginRules.push(pluginResult.renderRule)
260
+ }
261
+ })
238
262
  //创建编辑器
239
263
  editor.value = new AlexEditor(contentRef.value!, {
240
264
  value: value.value,
@@ -258,6 +282,7 @@ const createEditor = () => {
258
282
  el => {
259
283
  specialInblockHandle(editor.value!, el)
260
284
  },
285
+ ...pluginRules,
261
286
  ...props.renderRules
262
287
  ],
263
288
  allowCopy: props.allowCopy,
@@ -418,8 +443,15 @@ const documentClick = (e: Event) => {
418
443
  }
419
444
  //重新定义编辑器粘贴html
420
445
  const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
421
- const keepStyles = Object.assign(pasteKeepData.styles, props.pasteKeepStyles || {})
422
- const keepMarks = Object.assign(pasteKeepData.marks, props.pasteKeepMarks || {})
446
+ let keepStyles = pasteKeepData.styles
447
+ let keepMarks = pasteKeepData.marks
448
+ //注册插件:自定义html粘贴保留
449
+ pluginResultList.value.forEach(pluginResult => {
450
+ keepStyles = Object.assign(keepStyles, pluginResult.pasteKeepStyles || {})
451
+ keepMarks = Object.assign(keepMarks, pluginResult.pasteKeepMarks || {})
452
+ })
453
+ keepStyles = Object.assign(keepStyles, props.pasteKeepStyles || {})
454
+ keepMarks = Object.assign(keepMarks, props.pasteKeepMarks || {})
423
455
  //粘贴html时过滤元素的样式和属性
424
456
  AlexElement.flatElements(elements).forEach(el => {
425
457
  let marks: ObjectType = {}
@@ -443,7 +475,7 @@ const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
443
475
  })
444
476
  //如果使用了自定义粘贴html的功能
445
477
  if (typeof props.customHtmlPaste == 'function') {
446
- await props.customHtmlPaste.apply(this, [elements])
478
+ await props.customHtmlPaste(elements)
447
479
  }
448
480
  //默认粘贴html
449
481
  else {
@@ -478,8 +510,14 @@ const handleCustomParseNode = (ele: AlexElement) => {
478
510
  ele.marks = marks
479
511
  }
480
512
  }
513
+ //注册插件:自定义元素转换处理
514
+ pluginResultList.value.forEach(pluginResult => {
515
+ if (pluginResult.customParseNode) {
516
+ ele = pluginResult.customParseNode(ele)
517
+ }
518
+ })
481
519
  if (typeof props.customParseNode == 'function') {
482
- ele = props.customParseNode.apply(instance.proxy, [ele])
520
+ ele = props.customParseNode(ele)
483
521
  }
484
522
  return ele
485
523
  }
@@ -646,15 +684,21 @@ const handleDeleteInStart = (element: AlexElement) => {
646
684
  }
647
685
  //编辑器删除完成后事件
648
686
  const handleDeleteComplete = () => {
649
- const uneditable = editor.value!.range!.anchor.element.getUneditableElement()
650
- if (uneditable) {
651
- uneditable.toEmpty()
652
- }
687
+ // const uneditable = editor.value!.range!.anchor.element.getUneditableElement()
688
+ // if (uneditable) {
689
+ // uneditable.toEmpty()
690
+ // }
653
691
  }
654
692
  //编辑器dom渲染
655
693
  const handleAfterRender = () => {
656
694
  //设定视频高度
657
695
  setVideoHeight()
696
+ //注册插件:自定义dom渲染后处理
697
+ pluginResultList.value.forEach(pluginResult => {
698
+ if (pluginResult.updateView) {
699
+ pluginResult.updateView()
700
+ }
701
+ })
658
702
  emits('updateview')
659
703
  }
660
704
  //api:光标设置到文档底部
@@ -1,6 +1,6 @@
1
1
  import { common as DapCommon } from 'dap-util'
2
2
  import { ExtractPublicPropTypes, PropType } from 'vue'
3
- import { MenuConfigType, ObjectType, ToolbarConfigType } from '../core/tool'
3
+ import { PluginType, MenuConfigType, ObjectType, ToolbarConfigType } from '../core/tool'
4
4
  import { AlexElement } from 'alex-editor'
5
5
  import { LocaleType } from '../locale'
6
6
 
@@ -68,7 +68,7 @@ export const EditifyProps = {
68
68
  },
69
69
  //主题色
70
70
  color: {
71
- type: String,
71
+ type: String as PropType<string | null>,
72
72
  default: '#03a8f3',
73
73
  validator(value: any) {
74
74
  return DapCommon.matchingText(value, 'hex')
@@ -150,6 +150,13 @@ export const EditifyProps = {
150
150
  tab: {
151
151
  type: Boolean,
152
152
  default: true
153
+ },
154
+ //插件数组
155
+ plugins: {
156
+ type: Array as PropType<PluginType[]>,
157
+ default: function () {
158
+ return []
159
+ }
153
160
  }
154
161
  }
155
162
 
@@ -1,3 +1,7 @@
1
+ .editify-icon-attachment:before {
2
+ content: '\e613';
3
+ }
4
+
1
5
  .editify-icon-full-screen:before {
2
6
  content: '\e62f';
3
7
  }
Binary file
Binary file
package/src/index.ts CHANGED
@@ -6,23 +6,28 @@ import Editify from './editify/editify.vue'
6
6
 
7
7
  //导出类型
8
8
  export type { ButtonTypeType, ButtonOptionsItemType, ButtonSelectConfigType, ButtonDisplayConfigType } from './components/button/props'
9
- export type { MenuButtonType, MenuSelectButtonType, MenuDisplayButtonType, MenuImageButtonType, MenuVideoButtonType, MenuTableButtonType, MenuCustomButtonType, CodeBlockToolbarType, TextToolbarType, ToolbarConfigType, MenuSequenceType, MenuModeType, MenuConfigType } from './core/tool'
10
9
  export type { InsertImageUploadErrorType } from './components/insertImage/props'
11
10
  export type { InsertVideoUploadErrorType } from './components/insertVideo/props'
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'
12
15
 
13
16
  //导出编辑器操作方法
14
17
  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'
15
18
 
16
- //导出AlexElement元素
17
- export { AlexElement } from 'alex-editor'
18
-
19
- //导出版本号
20
- export const version = '0.1.22'
21
-
22
19
  //安装函数
23
20
  const install: FunctionPlugin = (app: App) => {
24
21
  app.component(Editify.name!, Editify)
25
22
  }
23
+ //版本号
24
+ const version = '0.1.24'
25
+
26
+ //导出AlexElement元素
27
+ export { AlexElement } from 'alex-editor'
26
28
 
27
29
  //导出组件和安装函数
28
- export { install as default, install, Editify }
30
+ export { install as default, install, Editify, version }
31
+
32
+ //导出插件
33
+ export { attachment } from './plugins/attachment'