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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-editify",
3
- "version": "0.1.36",
3
+ "version": "0.1.39",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "*.css"
@@ -17,12 +17,14 @@
17
17
  "lib": "vue-tsc && vite build"
18
18
  },
19
19
  "dependencies": {
20
- "alex-editor": "^1.3.36",
20
+ "alex-editor": "^1.4.6",
21
21
  "dap-util": "^1.5.4",
22
22
  "highlight.js": "^11.8.0",
23
+ "katex": "^0.16.10",
23
24
  "vue": "^3.4.19"
24
25
  },
25
26
  "devDependencies": {
27
+ "@types/katex": "^0.16.7",
26
28
  "@types/node": "^20.11.24",
27
29
  "@vitejs/plugin-vue": "^5.0.4",
28
30
  "less": "^3.0.4",
@@ -80,6 +80,7 @@
80
80
  background-color: transparent;
81
81
  outline: none;
82
82
  box-sizing: border-box;
83
+ font-family: inherit;
83
84
 
84
85
  &::-webkit-input-placeholder,
85
86
  &::placeholder {
@@ -28,6 +28,7 @@
28
28
  background-color: transparent;
29
29
  outline: none;
30
30
  box-sizing: border-box;
31
+ font-family: inherit;
31
32
 
32
33
  &::-webkit-input-placeholder,
33
34
  &::placeholder {
@@ -80,6 +80,7 @@
80
80
  background-color: transparent;
81
81
  outline: none;
82
82
  box-sizing: border-box;
83
+ font-family: inherit;
83
84
 
84
85
  &::-webkit-input-placeholder,
85
86
  &::placeholder {
@@ -14,7 +14,7 @@ import InsertVideo from '../insertVideo/insertVideo.vue'
14
14
  import InsertTable from '../insertTable/insertTable.vue'
15
15
  import { h, getCurrentInstance, ref, computed, inject, ComponentInternalInstance, Ref, ComputedRef, defineComponent } from 'vue'
16
16
  import { common as DapCommon } from 'dap-util'
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, hasImageInRange, hasVideoInRange } from '../../core/function'
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, hasImageInRange, hasVideoInRange, insertSeparator } from '../../core/function'
18
18
  import { MenuProps } from './props'
19
19
  import { MenuModeType, ObjectType, PluginResultType, MenuExtendType, MenuSequenceType, mergeObject } from '../../core/tool'
20
20
  import { AlexEditor, AlexElementsRangeType } from 'alex-editor'
@@ -88,6 +88,14 @@ const quoteConfig = ref<ObjectType>({
88
88
  active: false,
89
89
  disabled: false
90
90
  })
91
+ //分隔线按钮配置
92
+ const separatorConfig = ref<ObjectType>({
93
+ show: props.config.separator!.show,
94
+ leftBorder: props.config.separator!.leftBorder,
95
+ rightBorder: props.config.separator!.rightBorder,
96
+ active: false,
97
+ disabled: false
98
+ })
91
99
  //对齐方式按钮配置
92
100
  const alignConfig = ref<ObjectType>({
93
101
  show: props.config.align!.show,
@@ -440,6 +448,13 @@ const handleOperate = (name: string, val: any) => {
440
448
  editor.value.domRender()
441
449
  editor.value.rangeRender()
442
450
  }
451
+ //插入分隔线
452
+ else if (name == 'separator') {
453
+ insertSeparator(editor.value)
454
+ editor.value.formatElementStack()
455
+ editor.value.domRender()
456
+ editor.value.rangeRender()
457
+ }
443
458
  //设置对齐方式
444
459
  else if (name == 'align') {
445
460
  setAlign(editor.value, dataRangeCaches.value, <string>val)
@@ -1015,6 +1030,23 @@ const MenuItem = defineComponent(
1015
1030
  () => h(Icon, { value: 'quote' })
1016
1031
  )
1017
1032
  }
1033
+ //分隔线按钮
1034
+ if (itemProps.name == 'separator' && separatorConfig.value.show) {
1035
+ return h(
1036
+ Button,
1037
+ {
1038
+ ...itemProps,
1039
+ title: $editTrans('separator'),
1040
+ leftBorder: separatorConfig.value.leftBorder,
1041
+ rightBorder: separatorConfig.value.rightBorder,
1042
+ color: props.color,
1043
+ disabled: separatorConfig.value.disabled || selfProps.disabled || disabled.value,
1044
+ active: separatorConfig.value.active,
1045
+ onOperate: handleOperate
1046
+ },
1047
+ () => h(Icon, { value: 'separator' })
1048
+ )
1049
+ }
1018
1050
  //对齐方式按钮
1019
1051
  if (itemProps.name == 'align' && alignConfig.value.show) {
1020
1052
  return h(
@@ -8,8 +8,8 @@
8
8
 
9
9
  .editify-tooltip-content {
10
10
  display: block;
11
- padding: 6px 10px;
12
- font-size: @font-size;
11
+ padding: 4px 6px;
12
+ font-size: @font-size-small;
13
13
  white-space: nowrap;
14
14
  }
15
15
 
@@ -1250,12 +1250,8 @@ export const insertVideo = (editor: AlexEditor, value: string) => {
1250
1250
  null
1251
1251
  )
1252
1252
  editor.insertElement(video)
1253
- const leftSpace = AlexElement.getSpaceElement()
1254
- const rightSpace = AlexElement.getSpaceElement()
1255
- editor.addElementAfter(rightSpace, video)
1256
- editor.addElementBefore(leftSpace, video)
1257
- editor.range.anchor.moveToEnd(rightSpace)
1258
- editor.range.focus.moveToEnd(rightSpace)
1253
+ editor.range.anchor.moveToEnd(video)
1254
+ editor.range.focus.moveToEnd(video)
1259
1255
  }
1260
1256
 
1261
1257
  /**
@@ -1371,3 +1367,19 @@ export const insertCodeBlock = (editor: AlexEditor, dataRangeCaches: AlexElement
1371
1367
  }
1372
1368
  }
1373
1369
  }
1370
+
1371
+ /**
1372
+ * 插入分隔线
1373
+ * @param editor
1374
+ * @param dataRangeCaches
1375
+ * @returns
1376
+ */
1377
+ export const insertSeparator = (editor: AlexEditor) => {
1378
+ if (!editor.range) {
1379
+ return
1380
+ }
1381
+ const separator = new AlexElement('closed', 'hr', null, null, null)
1382
+ editor.insertElement(separator)
1383
+ editor.range.anchor.moveToEnd(separator)
1384
+ editor.range.focus.moveToEnd(separator)
1385
+ }
package/src/core/rule.ts CHANGED
@@ -75,10 +75,13 @@ export const parseList = (editor: AlexEditor, element: AlexElement) => {
75
75
  const newEl = el.clone()
76
76
  newEl.parsedom = 'div'
77
77
  newEl.type = element.type
78
- if (!newEl.hasMarks()) {
79
- newEl.marks = {}
78
+ if (newEl.hasMarks()) {
79
+ newEl.marks!['data-editify-list'] = element.parsedom
80
+ } else {
81
+ newEl.marks = {
82
+ 'data-editify-list': element.parsedom
83
+ }
80
84
  }
81
- newEl.marks!['data-editify-list'] = element.parsedom
82
85
  //插入到该元素之前
83
86
  editor.addElementBefore(newEl, element)
84
87
  })
@@ -110,11 +113,11 @@ export const orderdListHandle = function (editor: AlexEditor, element: AlexEleme
110
113
  }
111
114
 
112
115
  /**
113
- * 元素格式化时处理媒体元素和链接
116
+ * 元素格式化时处理常规元素(图片、视频、分隔线、行内代码)
114
117
  * @param editor
115
118
  * @param element
116
119
  */
117
- export const mediaHandle = function (editor: AlexEditor, element: AlexElement) {
120
+ export const commonElementHandle = function (editor: AlexEditor, element: AlexElement) {
118
121
  //图片、视频和链接设置marks
119
122
  if (element.parsedom == 'img' || element.parsedom == 'video' || element.parsedom == 'a') {
120
123
  const marks = {
@@ -127,20 +130,40 @@ export const mediaHandle = function (editor: AlexEditor, element: AlexElement) {
127
130
  }
128
131
  }
129
132
 
130
- //视频的特殊处理,两侧无元素时在两侧加上空白文本
131
- if (element.parsedom == 'video') {
133
+ //视频或者分隔线的特殊处理,两侧无元素时在两侧加上空白文本
134
+ if (element.parsedom == 'video' || element.parsedom == 'hr') {
132
135
  const previousElement = editor.getPreviousElement(element)
133
136
  const newTextElement = editor.getNextElement(element)
134
- //如果不存在前一个元素
135
- if (!previousElement || previousElement.isEmpty()) {
137
+ //如果不存在前一个元素或者前一个元素不是空白元素则设置空白元素
138
+ if (!previousElement || !previousElement.isSpaceText()) {
136
139
  const spaceText = AlexElement.getSpaceElement()
137
140
  editor.addElementBefore(spaceText, element)
138
141
  }
139
- //如果不存在后一个元素
140
- if (!newTextElement || newTextElement.isEmpty()) {
142
+ //如果不存在后一个元素或者后一个元素不是空白元素则设置空白元素
143
+ if (!newTextElement || !newTextElement.isSpaceText()) {
141
144
  const spaceText = AlexElement.getSpaceElement()
142
145
  editor.addElementAfter(spaceText, element)
143
146
  }
147
+ //如果光标在视频上则更新光标位置
148
+ if (editor.range && element.isContains(editor.range.anchor.element)) {
149
+ editor.range.anchor.moveToEnd(editor.getNextElement(element)!)
150
+ }
151
+ if (editor.range && element.isContains(editor.range.focus.element)) {
152
+ editor.range.focus.moveToEnd(editor.getNextElement(element)!)
153
+ }
154
+ }
155
+
156
+ //将code转为span[data-editify-code]
157
+ if (element.parsedom == 'code') {
158
+ element.parsedom = 'span'
159
+ const marks = {
160
+ 'data-editify-code': true
161
+ }
162
+ if (element.hasMarks()) {
163
+ Object.assign(element.marks!, marks)
164
+ } else {
165
+ element.marks = marks
166
+ }
144
167
  }
145
168
  }
146
169
 
package/src/core/tool.ts CHANGED
@@ -167,6 +167,7 @@ export type MenuConfigType = {
167
167
  heading?: MenuDisplayButtonType
168
168
  indent?: MenuSelectButtonType
169
169
  quote?: MenuButtonType
170
+ separator?: MenuButtonType
170
171
  align?: MenuSelectButtonType
171
172
  orderList?: MenuButtonType
172
173
  unorderList?: MenuButtonType
@@ -209,44 +210,14 @@ export type PluginResultType = {
209
210
  menu?: PluginMenuConfigType
210
211
  updateView?: () => void
211
212
  customParseNode?: (element: AlexElement) => AlexElement
213
+ extraKeepTags?: string[]
212
214
  renderRule?: (el: AlexElement) => void
213
- pasteKeepStyles?: ObjectType
214
- pasteKeepMarks?: ObjectType
215
+ pasteKeepMarks?: (el: AlexElement) => ObjectType
216
+ pasteKeepStyles?: (el: AlexElement) => ObjectType
215
217
  }
216
218
 
217
219
  export type PluginType = (editifyInstance: ComponentInternalInstance, editTrans: (key: string) => any) => PluginResultType
218
220
 
219
- /**
220
- * 粘贴html时保留的数据
221
- */
222
- export const pasteKeepData: ObjectType = {
223
- //粘贴html时元素保留的样式(全部元素)
224
- marks: {
225
- 'data-editify-list': ['div'],
226
- 'data-editify-value': ['div'],
227
- 'data-editify-code': ['span'],
228
- 'data-editify-task': ['div'],
229
- contenteditable: '*',
230
- src: ['img', 'video'],
231
- autoplay: ['video'],
232
- loop: ['video'],
233
- muted: ['video'],
234
- href: ['a'],
235
- target: ['a'],
236
- alt: ['img'],
237
- controls: ['video'],
238
- name: '*',
239
- disabled: '*',
240
- colspan: ['td']
241
- },
242
- //粘贴html时非文本元素保留的样式
243
- styles: {
244
- 'text-indent': '*',
245
- 'text-align': '*',
246
- 'line-height': '*'
247
- }
248
- }
249
-
250
221
  /**
251
222
  * 对象平替值方法
252
223
  * @param o1
@@ -825,30 +796,31 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
825
796
  heading: 2,
826
797
  indent: 3,
827
798
  quote: 4,
828
- align: 5,
829
- orderList: 6,
830
- unorderList: 7,
831
- task: 8,
832
- bold: 9,
833
- underline: 10,
834
- italic: 11,
835
- strikethrough: 12,
836
- code: 13,
837
- super: 14,
838
- sub: 15,
839
- formatClear: 16,
840
- fontSize: 17,
841
- fontFamily: 18,
842
- lineHeight: 19,
843
- foreColor: 20,
844
- backColor: 21,
845
- link: 22,
846
- image: 23,
847
- video: 24,
848
- table: 25,
849
- codeBlock: 26,
850
- sourceView: 27,
851
- fullScreen: 28
799
+ separator: 5,
800
+ align: 6,
801
+ orderList: 7,
802
+ unorderList: 8,
803
+ task: 9,
804
+ bold: 10,
805
+ underline: 11,
806
+ italic: 12,
807
+ strikethrough: 13,
808
+ code: 14,
809
+ super: 15,
810
+ sub: 16,
811
+ formatClear: 17,
812
+ fontSize: 18,
813
+ fontFamily: 19,
814
+ lineHeight: 20,
815
+ foreColor: 21,
816
+ backColor: 22,
817
+ link: 23,
818
+ image: 24,
819
+ video: 25,
820
+ table: 26,
821
+ codeBlock: 27,
822
+ sourceView: 28,
823
+ fullScreen: 29
852
824
  },
853
825
  //撤销按钮配置
854
826
  undo: {
@@ -900,7 +872,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
900
872
  //右侧边框是否显示
901
873
  rightBorder: false
902
874
  },
903
- //引用按钮配置
875
+ //引用
904
876
  quote: {
905
877
  //是否显示此按钮
906
878
  show: true,
@@ -909,6 +881,15 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
909
881
  //右侧边框是否显示
910
882
  rightBorder: false
911
883
  },
884
+ //分隔线
885
+ separator: {
886
+ //是否显示此按钮
887
+ show: true,
888
+ //左侧边框是否显示
889
+ leftBorder: false,
890
+ //右侧边框是否显示
891
+ rightBorder: false
892
+ },
912
893
  //对齐方式
913
894
  align: {
914
895
  //是否显示此工具
@@ -924,7 +905,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
924
905
  //右侧边框是否显示
925
906
  rightBorder: false
926
907
  },
927
- //有序列表按钮配置
908
+ //有序列表
928
909
  orderList: {
929
910
  //是否显示此按钮
930
911
  show: true,
@@ -933,7 +914,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
933
914
  //右侧边框是否显示
934
915
  rightBorder: false
935
916
  },
936
- //无序列表按钮配置
917
+ //无序列表
937
918
  unorderList: {
938
919
  //是否显示此按钮
939
920
  show: true,
@@ -942,7 +923,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
942
923
  //右侧边框是否显示
943
924
  rightBorder: false
944
925
  },
945
- //任务列表按钮配置
926
+ //任务列表
946
927
  task: {
947
928
  //是否显示此按钮
948
929
  show: true,
@@ -951,7 +932,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
951
932
  //右侧边框是否显示
952
933
  rightBorder: false
953
934
  },
954
- //粗体按钮配置
935
+ //粗体
955
936
  bold: {
956
937
  //是否显示此按钮
957
938
  show: true,
@@ -960,7 +941,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
960
941
  //右侧边框是否显示
961
942
  rightBorder: false
962
943
  },
963
- //下划线按钮配置
944
+ //下划线
964
945
  underline: {
965
946
  //是否显示此按钮
966
947
  show: true,
@@ -969,7 +950,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
969
950
  //右侧边框是否显示
970
951
  rightBorder: false
971
952
  },
972
- //斜体按钮配置
953
+ //斜体
973
954
  italic: {
974
955
  //是否显示此按钮
975
956
  show: true,
@@ -978,7 +959,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
978
959
  //右侧边框是否显示
979
960
  rightBorder: false
980
961
  },
981
- //删除线按钮配置
962
+ //删除线
982
963
  strikethrough: {
983
964
  //是否显示此按钮
984
965
  show: true,
@@ -987,7 +968,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
987
968
  //右侧边框是否显示
988
969
  rightBorder: false
989
970
  },
990
- //行内代码按钮配置
971
+ //行内代码
991
972
  code: {
992
973
  //是否显示此按钮
993
974
  show: true,
@@ -1174,7 +1155,7 @@ export const getMenuConfig = function (editTrans: (key: string) => any, editLoca
1174
1155
  //是否显示此工具
1175
1156
  show: false,
1176
1157
  //左侧边框是否显示
1177
- leftBorder: false,
1158
+ leftBorder: true,
1178
1159
  //右侧边框是否显示
1179
1160
  rightBorder: false
1180
1161
  },
package/src/css/base.less CHANGED
@@ -2,6 +2,8 @@
2
2
  @triangle-size: 6px;
3
3
  //编辑器内的默认字体大小
4
4
  @font-size: 14px;
5
+ //较小的字体(工具提示等)
6
+ @font-size-small: 12px;
5
7
  //字体颜色
6
8
  @font-color: #555;
7
9
  //较浅的字体颜色(副文本颜色)
@@ -156,7 +156,7 @@
156
156
  }
157
157
  }
158
158
  //代码样式
159
- :deep(span[data-editify-code]) {
159
+ :deep([data-editify-code]) {
160
160
  display: inline-block;
161
161
  padding: 3px 6px;
162
162
  margin: 0 4px;
@@ -285,6 +285,15 @@
285
285
  color: @font-color-light;
286
286
  border-radius: 0;
287
287
  }
288
+ //分隔线样式
289
+ :deep(hr) {
290
+ display: block;
291
+ width: 100%;
292
+ height: 1px;
293
+ background-color: @font-color-disabled;
294
+ border: none;
295
+ margin: 10px 0;
296
+ }
288
297
  //任务列表样式
289
298
  :deep(div[data-editify-task]) {
290
299
  margin-bottom: 15px;
@@ -343,7 +352,7 @@
343
352
  }
344
353
 
345
354
  //附件样式
346
- :deep(span[data-attachment]) {
355
+ :deep(span[data-editify-attachment]) {
347
356
  display: inline;
348
357
  color: @font-color-link;
349
358
  transition: all 200ms;
@@ -360,7 +369,7 @@
360
369
  }
361
370
  //附件名称
362
371
  &::after {
363
- content: attr(data-attachment-name);
372
+ content: attr(data-editify-attachment-name);
364
373
  margin-left: 6px;
365
374
  font-size: inherit;
366
375
  }