vue-editify 0.1.22 → 0.1.23

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 (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 +576 -178
  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 +50 -6
  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 +121 -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
  }
@@ -655,6 +693,12 @@ const handleDeleteComplete = () => {
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.23'
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'
@@ -84,5 +84,13 @@ export const en_US: ObjectType = {
84
84
  alignJustify: 'Align justify',
85
85
  defaultLineHeight: 'Default',
86
86
  auto: 'auto',
87
- fullScreen: 'Full screen'
87
+ fullScreen: 'Full screen',
88
+
89
+ //插件语言配置
90
+ insertAttachment: 'Insert attachment',
91
+ uploadAttachment: 'Upload',
92
+ remoteAttachment: 'Remote',
93
+ attachmentUrlPlaceholder: 'Please enter the attachment address',
94
+ downloadAttachment: 'Click to download attachment',
95
+ attachmentDownloadName: 'attachment'
88
96
  }