vue-editify 0.2.14 → 0.2.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. package/examples/App.vue +41 -88
  2. package/lib/components/button/button.vue.d.ts +62 -60
  3. package/lib/components/button/index.d.ts +4 -0
  4. package/lib/components/button/props.d.ts +12 -1
  5. package/lib/components/checkbox/checkbox.vue.d.ts +9 -9
  6. package/lib/components/checkbox/index.d.ts +4 -0
  7. package/lib/components/checkbox/props.d.ts +2 -2
  8. package/lib/components/colors/colors.vue.d.ts +4 -4
  9. package/lib/components/colors/index.d.ts +4 -0
  10. package/lib/components/colors/props.d.ts +2 -2
  11. package/lib/components/icon/index.d.ts +4 -0
  12. package/lib/components/insertAttachment/index.d.ts +4 -0
  13. package/lib/{plugins/attachment → components}/insertAttachment/insertAttachment.vue.d.ts +3 -3
  14. package/lib/{plugins/attachment → components}/insertAttachment/props.d.ts +1 -1
  15. package/lib/components/insertImage/index.d.ts +4 -0
  16. package/lib/components/insertImage/insertImage.vue.d.ts +3 -3
  17. package/lib/components/insertImage/props.d.ts +1 -1
  18. package/lib/components/insertLink/index.d.ts +4 -0
  19. package/lib/components/insertLink/insertLink.vue.d.ts +6 -6
  20. package/lib/components/insertLink/props.d.ts +3 -3
  21. package/lib/components/insertMathformula/index.d.ts +4 -0
  22. package/lib/{plugins/mathformula → components}/insertMathformula/insertMathformula.vue.d.ts +3 -3
  23. package/lib/{plugins/mathformula → components}/insertMathformula/props.d.ts +2 -2
  24. package/lib/components/insertTable/index.d.ts +4 -0
  25. package/lib/components/insertTable/insertTable.vue.d.ts +3 -3
  26. package/lib/components/insertTable/props.d.ts +2 -2
  27. package/lib/components/insertVideo/index.d.ts +4 -0
  28. package/lib/components/insertVideo/insertVideo.vue.d.ts +3 -3
  29. package/lib/components/insertVideo/props.d.ts +1 -1
  30. package/lib/components/layer/index.d.ts +4 -0
  31. package/lib/components/layer/layer.vue.d.ts +10 -8
  32. package/lib/components/tooltip/index.d.ts +4 -0
  33. package/lib/components/tooltip/tooltip.vue.d.ts +6 -4
  34. package/lib/components/triangle/index.d.ts +4 -0
  35. package/lib/components/triangle/triangle.vue.d.ts +1 -1
  36. package/lib/components/updateLink/index.d.ts +4 -0
  37. package/lib/components/updateLink/props.d.ts +17 -0
  38. package/lib/components/updateLink/updateLink.vue.d.ts +38 -0
  39. package/lib/core/function.d.ts +113 -36
  40. package/lib/core/rule.d.ts +20 -0
  41. package/lib/core/tool.d.ts +36 -34
  42. package/lib/editify/editify.vue.d.ts +18 -28
  43. package/lib/editify/menu/index.d.ts +4 -0
  44. package/lib/{components → editify}/menu/menu.vue.d.ts +3 -4
  45. package/lib/{components → editify}/menu/props.d.ts +1 -1
  46. package/lib/editify/props.d.ts +3 -7
  47. package/lib/editify/toolbar/index.d.ts +4 -0
  48. package/lib/{components → editify}/toolbar/props.d.ts +2 -2
  49. package/lib/{components → editify}/toolbar/toolbar.vue.d.ts +53 -53
  50. package/lib/editify.es.js +38964 -37727
  51. package/lib/editify.umd.js +2 -2
  52. package/lib/feature/align.d.ts +32 -0
  53. package/lib/feature/attachment.d.ts +18 -0
  54. package/lib/feature/backColor.d.ts +32 -0
  55. package/lib/feature/bold.d.ts +32 -0
  56. package/lib/feature/code.d.ts +32 -0
  57. package/lib/feature/codeBlock.d.ts +32 -0
  58. package/lib/feature/fontFamily.d.ts +32 -0
  59. package/lib/feature/fontSize.d.ts +32 -0
  60. package/lib/feature/foreColor.d.ts +32 -0
  61. package/lib/feature/formatClear.d.ts +32 -0
  62. package/lib/feature/fullScreen.d.ts +18 -0
  63. package/lib/feature/heading.d.ts +32 -0
  64. package/lib/feature/image.d.ts +32 -0
  65. package/lib/feature/indent.d.ts +18 -0
  66. package/lib/feature/infoBlock.d.ts +18 -0
  67. package/lib/feature/italic.d.ts +32 -0
  68. package/lib/feature/lineHeight.d.ts +32 -0
  69. package/lib/feature/link.d.ts +26 -0
  70. package/lib/feature/mathformula.d.ts +22 -0
  71. package/lib/feature/orderList.d.ts +32 -0
  72. package/lib/feature/panel.d.ts +18 -0
  73. package/lib/feature/quote.d.ts +18 -0
  74. package/lib/feature/redo.d.ts +18 -0
  75. package/lib/feature/separator.d.ts +18 -0
  76. package/lib/feature/sourceView.d.ts +18 -0
  77. package/lib/feature/strikethrough.d.ts +32 -0
  78. package/lib/feature/sub.d.ts +32 -0
  79. package/lib/feature/super.d.ts +32 -0
  80. package/lib/feature/table.d.ts +32 -0
  81. package/lib/feature/task.d.ts +32 -0
  82. package/lib/feature/underline.d.ts +32 -0
  83. package/lib/feature/undo.d.ts +18 -0
  84. package/lib/feature/unorderList.d.ts +32 -0
  85. package/lib/feature/video.d.ts +38 -0
  86. package/lib/index.d.ts +194 -202
  87. package/package.json +5 -5
  88. package/src/components/button/button.vue +21 -24
  89. package/src/components/button/index.ts +5 -0
  90. package/src/components/button/props.ts +14 -1
  91. package/src/components/checkbox/checkbox.vue +1 -1
  92. package/src/components/checkbox/index.ts +5 -0
  93. package/src/components/checkbox/props.ts +1 -1
  94. package/src/components/colors/colors.vue +3 -3
  95. package/src/components/colors/index.ts +5 -0
  96. package/src/components/colors/props.ts +2 -2
  97. package/src/components/icon/index.ts +5 -0
  98. package/src/components/insertAttachment/index.ts +5 -0
  99. package/src/{plugins/attachment → components}/insertAttachment/insertAttachment.vue +4 -2
  100. package/src/{plugins/attachment → components}/insertAttachment/props.ts +1 -1
  101. package/src/components/insertImage/index.ts +5 -0
  102. package/src/components/insertImage/insertImage.vue +5 -5
  103. package/src/components/insertImage/props.ts +1 -1
  104. package/src/components/insertLink/index.ts +5 -0
  105. package/src/components/insertLink/insertLink.vue +10 -10
  106. package/src/components/insertLink/props.ts +3 -3
  107. package/src/components/insertMathformula/index.ts +5 -0
  108. package/src/{plugins/mathformula → components}/insertMathformula/props.ts +2 -2
  109. package/src/components/insertTable/index.ts +5 -0
  110. package/src/components/insertTable/props.ts +2 -2
  111. package/src/components/insertVideo/index.ts +5 -0
  112. package/src/components/insertVideo/insertVideo.vue +2 -2
  113. package/src/components/insertVideo/props.ts +1 -1
  114. package/src/components/layer/index.ts +5 -0
  115. package/src/components/layer/layer.vue +42 -4
  116. package/src/components/tooltip/index.ts +5 -0
  117. package/src/components/tooltip/tooltip.vue +1 -1
  118. package/src/components/triangle/index.ts +5 -0
  119. package/src/components/triangle/triangle.vue +1 -1
  120. package/src/components/updateLink/index.ts +5 -0
  121. package/src/components/updateLink/props.ts +21 -0
  122. package/src/components/{toolbar/toolbar.less → updateLink/updateLink.less} +4 -20
  123. package/src/components/updateLink/updateLink.vue +74 -0
  124. package/src/core/function.ts +289 -97
  125. package/src/core/rule.ts +108 -29
  126. package/src/core/tool.ts +237 -81
  127. package/src/editify/editify.less +4 -0
  128. package/src/editify/editify.vue +183 -194
  129. package/src/editify/menu/index.ts +5 -0
  130. package/src/editify/menu/menu.vue +215 -0
  131. package/src/{components → editify}/menu/props.ts +1 -1
  132. package/src/editify/props.ts +7 -11
  133. package/src/editify/toolbar/index.ts +5 -0
  134. package/src/{components → editify}/toolbar/props.ts +1 -1
  135. package/src/editify/toolbar/toolbar.less +10 -0
  136. package/src/editify/toolbar/toolbar.vue +103 -0
  137. package/src/feature/align.ts +126 -0
  138. package/src/feature/attachment.ts +108 -0
  139. package/src/feature/backColor.ts +169 -0
  140. package/src/feature/bold.ts +134 -0
  141. package/src/feature/code.ts +134 -0
  142. package/src/feature/codeBlock.ts +201 -0
  143. package/src/feature/fontFamily.ts +138 -0
  144. package/src/feature/fontSize.ts +140 -0
  145. package/src/feature/foreColor.ts +171 -0
  146. package/src/feature/formatClear.ts +116 -0
  147. package/src/feature/fullScreen.ts +57 -0
  148. package/src/feature/heading.ts +152 -0
  149. package/src/feature/image.ts +222 -0
  150. package/src/feature/indent.ts +72 -0
  151. package/src/feature/infoBlock.ts +93 -0
  152. package/src/feature/italic.ts +134 -0
  153. package/src/feature/lineHeight.ts +163 -0
  154. package/src/feature/link.ts +146 -0
  155. package/src/feature/mathformula.ts +146 -0
  156. package/src/feature/orderList.ts +114 -0
  157. package/src/feature/panel.ts +107 -0
  158. package/src/feature/quote.ts +60 -0
  159. package/src/feature/redo.ts +56 -0
  160. package/src/feature/separator.ts +61 -0
  161. package/src/feature/sourceView.ts +59 -0
  162. package/src/feature/strikethrough.ts +134 -0
  163. package/src/feature/sub.ts +134 -0
  164. package/src/feature/super.ts +134 -0
  165. package/src/feature/table.ts +981 -0
  166. package/src/feature/task.ts +114 -0
  167. package/src/feature/underline.ts +134 -0
  168. package/src/feature/undo.ts +56 -0
  169. package/src/feature/unorderList.ts +114 -0
  170. package/src/feature/video.ts +335 -0
  171. package/src/hljs/index.ts +1 -1
  172. package/src/index.ts +82 -25
  173. package/src/locale/en_US.ts +3 -3
  174. package/src/locale/zh_CN.ts +3 -3
  175. package/lib/plugins/attachment/index.d.ts +0 -37
  176. package/lib/plugins/infoBlock/index.d.ts +0 -55
  177. package/lib/plugins/mathformula/index.d.ts +0 -49
  178. package/lib/plugins/panel/index.d.ts +0 -48
  179. package/src/components/menu/menu.vue +0 -1655
  180. package/src/components/toolbar/toolbar.vue +0 -1677
  181. package/src/plugins/attachment/index.ts +0 -237
  182. package/src/plugins/infoBlock/index.ts +0 -238
  183. package/src/plugins/mathformula/index.ts +0 -295
  184. package/src/plugins/panel/index.ts +0 -228
  185. package/tsconfig.json +0 -31
  186. package/tsconfig.node.json +0 -11
  187. /package/src/{plugins/attachment → components}/insertAttachment/insertAttachment.less +0 -0
  188. /package/src/{plugins/mathformula → components}/insertMathformula/insertMathformula.less +0 -0
  189. /package/src/{plugins/mathformula → components}/insertMathformula/insertMathformula.vue +0 -0
  190. /package/src/{components → editify}/menu/menu.less +0 -0
@@ -0,0 +1,5 @@
1
+ import Menu from './menu.vue'
2
+
3
+ export type * from './props'
4
+
5
+ export { Menu }
@@ -0,0 +1,215 @@
1
+ <template>
2
+ <div ref="menuRef" class="editify-menu" :class="{ 'editify-border': menuShowBorder, 'editify-source': isSourceView && menuMode == 'inner', 'editify-fullscreen': isFullScreen }" :data-editify-mode="menuMode" :style="{ zIndex: zIndex, ...(config.style || {}) }">
3
+ <template v-for="item in menuNames">
4
+ <!-- 内置菜单按钮 -->
5
+ <component v-if="!!currentDefaultMenu(item)" :is="currentDefaultMenu(item)" :color="color" :z-index="zIndex + 1" :config="(config as any)[item]" :disabled="isDisabled || !rangeKey" :tooltip="config.tooltip!"></component>
6
+ <!-- 拓展菜单按钮 -->
7
+ <ExtendMenuButton v-else :name="item" />
8
+ </template>
9
+ </div>
10
+ </template>
11
+ <script setup lang="ts">
12
+ import { ref, computed, inject, Ref, ComputedRef, onMounted, getCurrentInstance, onBeforeUnmount, shallowRef, defineComponent, h } from 'vue'
13
+ import { event as DapEvent } from 'dap-util'
14
+ import { MenuModeType } from '@/core/tool'
15
+ import { Button } from '@/components/button'
16
+ import { MenuProps } from './props'
17
+ import { UndoMenuButton } from '@/feature/undo'
18
+ import { RedoMenuButton } from '@/feature/redo'
19
+ import { HeadingMenuButton } from '@/feature/heading'
20
+ import { IndentMenuButton } from '@/feature/indent'
21
+ import { QuoteMenuButton } from '@/feature/quote'
22
+ import { SeparatorMenuButton } from '@/feature/separator'
23
+ import { AlignMenuButton } from '@/feature/align'
24
+ import { OrderListMenuButton } from '@/feature/orderList'
25
+ import { UnorderListMenuButton } from '@/feature/unorderList'
26
+ import { TaskMenuButton } from '@/feature/task'
27
+ import { BoldMenuButton } from '@/feature/bold'
28
+ import { UnderlineMenuButton } from '@/feature/underline'
29
+ import { ItalicMenuButton } from '@/feature/italic'
30
+ import { StrikethroughMenuButton } from '@/feature/strikethrough'
31
+ import { CodeMenuButton } from '@/feature/code'
32
+ import { SuperMenuButton } from '@/feature/super'
33
+ import { SubMenuButton } from '@/feature/sub'
34
+ import { FormatClearMenuButton } from '@/feature/formatClear'
35
+ import { FontSizeMenuButton } from '@/feature/fontSize'
36
+ import { FontFamilyMenuButton } from '@/feature/fontFamily'
37
+ import { LineHeightMenuButton } from '@/feature/lineHeight'
38
+ import { ForeColorMenuButton } from '@/feature/foreColor'
39
+ import { BackColorMenuButton } from '@/feature/backColor'
40
+ import { LinkMenuButton } from '@/feature/link'
41
+ import { ImageMenuButton } from '@/feature/image'
42
+ import { VideoMenuButton } from '@/feature/video'
43
+ import { TableMenuButton } from '@/feature/table'
44
+ import { CodeBlockMenuButton } from '@/feature/codeBlock'
45
+ import { SourceViewMenuButton } from '@/feature/sourceView'
46
+ import { FullScreenMenuButton } from '@/feature/fullScreen'
47
+ import { AttachmentMenuButton } from '@/feature/attachment'
48
+ import { MathformulaMenuButton } from '@/feature/mathformula'
49
+ import { PanelMenuButton } from '@/feature/panel'
50
+ import { InfoBlockMenuButton } from '@/feature/infoBlock'
51
+
52
+ defineOptions({
53
+ name: 'Menu'
54
+ })
55
+ //内部实例
56
+ const instance = getCurrentInstance()!
57
+ //属性
58
+ const props = defineProps(MenuProps)
59
+ //是否源码视图
60
+ const isSourceView = inject<Ref<boolean>>('isSourceView')!
61
+ //是否全屏
62
+ const isFullScreen = inject<Ref<boolean>>('isFullScreen')!
63
+ //光标更新标记
64
+ const rangeKey = inject<Ref<number | null>>('rangeKey')!
65
+ //编辑器是否显示边框
66
+ const showBorder = inject<ComputedRef<boolean>>('showBorder')!
67
+ //编辑器是否外部禁用
68
+ const isDisabled = inject<ComputedRef<boolean>>('isDisabled')!
69
+ //编辑器是否自适应高度
70
+ const isAutoHeight = inject<ComputedRef<boolean>>('isAutoHeight')!
71
+
72
+ //菜单dom
73
+ const menuRef = ref<HTMLElement | null>(null)
74
+ //菜单高度
75
+ const height = ref<number>(0)
76
+
77
+ //菜单名称数组(包括内置的和拓展的)
78
+ const menuNames = computed<string[]>(() => {
79
+ return Object.keys(props.config.sequence!).sort((a, b) => {
80
+ if (props.config.sequence![a]! > props.config.sequence![b]!) {
81
+ return 1
82
+ }
83
+ return -1
84
+ })
85
+ })
86
+ //内置菜单组件的数组
87
+ const defaultMenus = shallowRef([UndoMenuButton, RedoMenuButton, HeadingMenuButton, IndentMenuButton, QuoteMenuButton, SeparatorMenuButton, AlignMenuButton, OrderListMenuButton, UnorderListMenuButton, TaskMenuButton, BoldMenuButton, UnderlineMenuButton, ItalicMenuButton, StrikethroughMenuButton, CodeMenuButton, SuperMenuButton, SubMenuButton, FormatClearMenuButton, FontSizeMenuButton, FontFamilyMenuButton, LineHeightMenuButton, ForeColorMenuButton, BackColorMenuButton, LinkMenuButton, ImageMenuButton, VideoMenuButton, TableMenuButton, CodeBlockMenuButton, SourceViewMenuButton, FullScreenMenuButton, AttachmentMenuButton, MathformulaMenuButton, PanelMenuButton, InfoBlockMenuButton])
88
+ //根据菜单名称获取对应的内置菜单组件
89
+ const currentDefaultMenu = computed(() => {
90
+ return (name: string) => defaultMenus.value.find(item => item.name == `_${name}`)
91
+ })
92
+ //菜单显示模式
93
+ const menuMode = computed<MenuModeType>(() => {
94
+ //如果是全屏状态下或者高度自适应状态下
95
+ if (isFullScreen.value || isAutoHeight.value) {
96
+ //fixed模式改为默认模式
97
+ if (props.config.mode == 'fixed') {
98
+ return 'default'
99
+ }
100
+ }
101
+ return props.config.mode!
102
+ })
103
+ //菜单栏是否显示边框
104
+ const menuShowBorder = computed<boolean>(() => {
105
+ //fixed模式下不显示边框
106
+ if (menuMode.value == 'fixed') {
107
+ return false
108
+ }
109
+ //由编辑器的border属性来决定
110
+ return showBorder.value
111
+ })
112
+
113
+ //拓展菜单组件
114
+ const ExtendMenuButton = defineComponent(
115
+ extendProps => {
116
+ //按钮实例
117
+ const btnRef = ref<InstanceType<typeof Button> | null>(null)
118
+ //拓展菜单配置
119
+ const configuration = props.config.extends![extendProps.name]
120
+ return () => {
121
+ return configuration
122
+ ? h(
123
+ Button,
124
+ {
125
+ name: extendProps.name,
126
+ tooltip: props.config.tooltip,
127
+ color: props.color,
128
+ zIndex: props.zIndex + 1,
129
+ ref: btnRef,
130
+ type: configuration.type || 'default',
131
+ title: configuration.title || '',
132
+ leftBorder: configuration.leftBorder || false,
133
+ rightBorder: configuration.rightBorder || false,
134
+ hideScroll: configuration.hideScroll || false,
135
+ disabled: isDisabled.value || !rangeKey.value || configuration.disabled,
136
+ active: configuration.active || false,
137
+ selectConfig: {
138
+ width: configuration.width,
139
+ maxHeight: configuration.maxHeight,
140
+ options: configuration.options
141
+ },
142
+ displayConfig: {
143
+ width: configuration.width,
144
+ maxHeight: configuration.maxHeight,
145
+ value: configuration.value,
146
+ options: configuration.options
147
+ },
148
+ onLayerShow: () => {
149
+ if (typeof configuration.onLayerShow == 'function') {
150
+ configuration.onLayerShow(extendProps.name, btnRef.value!)
151
+ }
152
+ },
153
+ onLayerShown: () => {
154
+ if (typeof configuration.onLayerShown == 'function') {
155
+ configuration.onLayerShown(extendProps.name, btnRef.value!)
156
+ }
157
+ },
158
+ onLayerHidden: () => {
159
+ if (typeof configuration.onLayerHidden == 'function') {
160
+ configuration.onLayerHidden(extendProps.name, btnRef.value!)
161
+ }
162
+ },
163
+ onOperate: (name, val) => {
164
+ if (typeof configuration.onOperate == 'function') {
165
+ configuration.onOperate(name, val, btnRef.value!)
166
+ }
167
+ }
168
+ },
169
+ {
170
+ default: () => {
171
+ if (configuration.default) {
172
+ return configuration.default(extendProps.name, btnRef.value!)
173
+ }
174
+ return null
175
+ },
176
+ layer: () => {
177
+ if (configuration.layer) {
178
+ return configuration.layer(extendProps.name, btnRef.value!)
179
+ }
180
+ return null
181
+ },
182
+ option: () => {
183
+ if (configuration.option) {
184
+ return configuration.option(extendProps.name, btnRef.value!)
185
+ }
186
+ return null
187
+ }
188
+ }
189
+ )
190
+ : null
191
+ }
192
+ },
193
+ {
194
+ props: {
195
+ name: String
196
+ }
197
+ }
198
+ )
199
+
200
+ onMounted(() => {
201
+ height.value = menuRef.value!.offsetHeight
202
+ DapEvent.on(window, `resize.editify_menu_${instance.uid}`, () => {
203
+ height.value = menuRef.value!.offsetHeight
204
+ })
205
+ })
206
+
207
+ onBeforeUnmount(() => {
208
+ DapEvent.off(window, `resize.editify_menu_${instance.uid}`)
209
+ })
210
+
211
+ defineExpose({
212
+ height
213
+ })
214
+ </script>
215
+ <style scoped src="./menu.less"></style>
@@ -9,7 +9,7 @@ export const MenuProps = {
9
9
  },
10
10
  //主题色
11
11
  color: {
12
- type: String as PropType<string | null>,
12
+ type: String,
13
13
  default: ''
14
14
  },
15
15
  //层级
@@ -1,7 +1,7 @@
1
- import { common as DapCommon } from 'dap-util'
2
1
  import { ExtractPublicPropTypes, PropType } from 'vue'
2
+ import { common as DapCommon } from 'dap-util'
3
3
  import { AlexElement } from 'alex-editor'
4
- import { PluginType, MenuConfigType, ObjectType, ToolbarConfigType } from '@/core/tool'
4
+ import { MenuConfigType, ObjectType, ToolbarConfigType } from '@/core/tool'
5
5
  import { LocaleType } from '@/locale'
6
6
 
7
7
  export type EditifyResizeParamsType = {
@@ -68,9 +68,12 @@ export const EditifyProps = {
68
68
  },
69
69
  //主题色
70
70
  color: {
71
- type: String as PropType<string | null>,
71
+ type: String,
72
72
  default: '#03a8f3',
73
- validator(value: any) {
73
+ validator(value: string) {
74
+ if (!value) {
75
+ return true
76
+ }
74
77
  return DapCommon.matchingText(value, 'hex')
75
78
  }
76
79
  },
@@ -158,13 +161,6 @@ export const EditifyProps = {
158
161
  type: Boolean,
159
162
  default: true
160
163
  },
161
- //插件数组
162
- plugins: {
163
- type: Array as PropType<PluginType[]>,
164
- default: function () {
165
- return []
166
- }
167
- },
168
164
  //是否使用深色模式
169
165
  dark: {
170
166
  type: Boolean,
@@ -0,0 +1,5 @@
1
+ import Toolbar from './toolbar.vue'
2
+
3
+ export type * from './props'
4
+
5
+ export { Toolbar }
@@ -32,7 +32,7 @@ export const ToolbarProps = {
32
32
  },
33
33
  //主题色
34
34
  color: {
35
- type: String as PropType<string | null>,
35
+ type: String,
36
36
  default: ''
37
37
  },
38
38
  //层级
@@ -0,0 +1,10 @@
1
+ .editify-toolbar {
2
+ display: flex;
3
+ justify-content: flex-start;
4
+ align-items: center;
5
+ padding: 4px;
6
+ }
7
+
8
+ :deep(.editify-icon-rotate) {
9
+ transform: rotate(180deg);
10
+ }
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <Layer v-model="show" ref="layerRef" :node="node" :scroll-node="scrollNode" border placement="bottom-start" :useRange="type == 'text'" :z-index="zIndex" :inside-elements="insideElements">
3
+ <div class="editify-toolbar" :style="config.style">
4
+ <!-- 链接工具条 -->
5
+ <linkToolbar v-if="type == 'link'" :color="color" />
6
+ <!-- 图片工具条 -->
7
+ <ImageToolbar v-else-if="type == 'image'" @reset-toolbar="layerRef!.setPosition()" :tooltip="config.tooltip!" :color="color" :z-index="zIndex + 1" />
8
+ <!-- 视频工具条 -->
9
+ <VideoToolbar v-else-if="type == 'video'" @reset-toolbar="layerRef!.setPosition()" :tooltip="config.tooltip!" :color="color" :z-index="zIndex + 1" />
10
+ <!-- 表格工具条 -->
11
+ <TableToolbar v-else-if="type == 'table'" @reset-toolbar="layerRef!.setPosition()" :tooltip="config.tooltip!" :color="color" :z-index="zIndex + 1" />
12
+ <!-- 代码块工具条 -->
13
+ <CodeBlockToolbar v-else-if="type == 'codeBlock'" ref="codeBlockToolbarRef" :language="config.codeBlock!.languages!" :tooltip="config.tooltip!" :color="color" :z-index="zIndex + 1" />
14
+ <!-- 文本工具条 -->
15
+ <template v-else-if="type == 'text'">
16
+ <component v-for="(btn, index) in textToolbarBtns" :ref="el => (textToolbarBtnRefs[index] = (el as BtnComponentPublicInstance))" :is="btn" :color="color" :z-index="zIndex + 1" :config="textButtonConfig(btn.name)" :tooltip="config.tooltip!" />
17
+ </template>
18
+ </div>
19
+ </Layer>
20
+ </template>
21
+ <script setup lang="ts">
22
+ import { ComponentPublicInstance, computed, ref, shallowRef } from 'vue'
23
+ import { Layer } from '@/components/layer'
24
+ import { Button } from '@/components/button'
25
+ import { ToolbarProps } from './props'
26
+ import { linkToolbar } from '@/feature/link'
27
+ import { ImageToolbar } from '@/feature/image'
28
+ import { VideoToolbar } from '@/feature/video'
29
+ import { TableToolbar } from '@/feature/table'
30
+ import { CodeBlockToolbar } from '@/feature/codeBlock'
31
+ import { HeadingToolbarButton } from '@/feature/heading'
32
+ import { AlignToolbarButton } from '@/feature/align'
33
+ import { OrderListToolbarButton } from '@/feature/orderList'
34
+ import { UnorderListToolbarButton } from '@/feature/unorderList'
35
+ import { TaskToolbarButton } from '@/feature/task'
36
+ import { BoldToolbarButton } from '@/feature/bold'
37
+ import { ItalicToolbarButton } from '@/feature/italic'
38
+ import { StrikethroughToolbarButton } from '@/feature/strikethrough'
39
+ import { UnderlineToolbarButton } from '@/feature/underline'
40
+ import { CodeToolbarButton } from '@/feature/code'
41
+ import { SuperToolbarButton } from '@/feature/super'
42
+ import { SubToolbarButton } from '@/feature/sub'
43
+ import { FontSizeToolbarButton } from '@/feature/fontSize'
44
+ import { FontFamilyToolbarButton } from '@/feature/fontFamily'
45
+ import { LineHeightToolbarButton } from '@/feature/lineHeight'
46
+ import { ForeColorToolbarButton } from '@/feature/foreColor'
47
+ import { BackColorToolbarButton } from '@/feature/backColor'
48
+ import { FormatClearToolbarButton } from '@/feature/formatClear'
49
+
50
+ defineOptions({
51
+ name: 'Toolbar'
52
+ })
53
+ //属性
54
+ const props = defineProps(ToolbarProps)
55
+ //事件
56
+ const emits = defineEmits(['update:modelValue'])
57
+
58
+ //工具条浮层组件实例
59
+ const layerRef = ref<InstanceType<typeof Layer> | null>(null)
60
+ //文本按钮实例类型
61
+ type BtnComponentPublicInstance = ComponentPublicInstance & { btnRef: InstanceType<typeof Button> }
62
+ //代码块语言选择按钮实例
63
+ const codeBlockToolbarRef = ref<BtnComponentPublicInstance | null>(null)
64
+ //文本工具条按钮数组
65
+ const textToolbarBtns = shallowRef([HeadingToolbarButton, AlignToolbarButton, OrderListToolbarButton, UnorderListToolbarButton, TaskToolbarButton, BoldToolbarButton, ItalicToolbarButton, StrikethroughToolbarButton, UnderlineToolbarButton, CodeToolbarButton, SuperToolbarButton, SubToolbarButton, FontSizeToolbarButton, FontFamilyToolbarButton, LineHeightToolbarButton, ForeColorToolbarButton, BackColorToolbarButton, FormatClearToolbarButton])
66
+ //文本工具条按钮实例
67
+ const textToolbarBtnRefs = ref<BtnComponentPublicInstance[]>([])
68
+
69
+ //是否显示工具条
70
+ const show = computed<boolean>({
71
+ get() {
72
+ return props.modelValue
73
+ },
74
+ set(val) {
75
+ emits('update:modelValue', val)
76
+ }
77
+ })
78
+ //点击不关闭工具条浮层的元素(算在工具条浮层元素范围内)
79
+ const insideElements = computed<HTMLElement[]>(() => {
80
+ let elements: HTMLElement[] = []
81
+ //语言选择浮层元素
82
+ if (codeBlockToolbarRef.value && codeBlockToolbarRef.value.btnRef && codeBlockToolbarRef.value.btnRef.layerRef && codeBlockToolbarRef.value.btnRef.layerRef.elRef) {
83
+ elements.push(codeBlockToolbarRef.value.btnRef.layerRef.elRef)
84
+ }
85
+ textToolbarBtnRefs.value.forEach(el => {
86
+ if (el && el.btnRef && el.btnRef.layerRef && el.btnRef.layerRef.elRef) {
87
+ elements.push(el.btnRef.layerRef.elRef)
88
+ }
89
+ })
90
+ return elements
91
+ })
92
+ //文本按钮配置
93
+ const textButtonConfig = computed<any>(() => {
94
+ return (name: string) => {
95
+ return (props.config.text as any)[name.replace('_', '')]
96
+ }
97
+ })
98
+
99
+ defineExpose({
100
+ layerRef
101
+ })
102
+ </script>
103
+ <style scoped src="./toolbar.less"></style>
@@ -0,0 +1,126 @@
1
+ import { defineComponent, h, inject, PropType, Ref, ref } from 'vue'
2
+ import { AlexElementsRangeType, AlexEditor } from 'alex-editor'
3
+ import { MenuSelectButtonType } from '@/core/tool'
4
+ import { hasPreInRange, setAlign } from '@/core/function'
5
+ import { Button } from '@/components/button'
6
+ import { Icon } from '@/components/icon'
7
+
8
+ /**
9
+ * feature名称
10
+ */
11
+ const FEATURE_NAME = 'align'
12
+
13
+ /**
14
+ * 工具栏 - 对齐方式
15
+ */
16
+ export const AlignToolbarButton = defineComponent(
17
+ (props, { expose }) => {
18
+ const editor = inject<Ref<AlexEditor>>('editor')!
19
+ const dataRangeCaches = inject<Ref<AlexElementsRangeType>>('dataRangeCaches')!
20
+ const $editTrans = inject<(key: string) => any>('$editTrans')!
21
+
22
+ const btnRef = ref<InstanceType<typeof Button> | null>(null)
23
+
24
+ expose({
25
+ btnRef
26
+ })
27
+
28
+ return () => {
29
+ return props.config.show
30
+ ? h(
31
+ Button,
32
+ {
33
+ ref: btnRef,
34
+ name: FEATURE_NAME,
35
+ type: 'select',
36
+ title: $editTrans('align'),
37
+ tooltip: props.tooltip,
38
+ color: props.color,
39
+ zIndex: props.zIndex,
40
+ leftBorder: props.config.leftBorder,
41
+ rightBorder: props.config.rightBorder,
42
+ active: false,
43
+ disabled: props.config.disabled,
44
+ selectConfig: {
45
+ options: props.config.options,
46
+ width: props.config.width,
47
+ maxHeight: props.config.maxHeight
48
+ },
49
+ onOperate: (_name: string, val: 'left' | 'right' | 'center' | 'justify') => {
50
+ setAlign(editor.value, dataRangeCaches.value, val)
51
+ editor.value.domRender()
52
+ editor.value.rangeRender()
53
+ }
54
+ },
55
+ {
56
+ default: () => h(Icon, { value: 'align-left' })
57
+ }
58
+ )
59
+ : null
60
+ }
61
+ },
62
+ {
63
+ name: `_${FEATURE_NAME}`,
64
+ props: {
65
+ color: String,
66
+ zIndex: Number,
67
+ config: Object as PropType<MenuSelectButtonType>,
68
+ tooltip: Boolean
69
+ }
70
+ }
71
+ )
72
+
73
+ /**
74
+ * 菜单栏 - 对齐方式
75
+ */
76
+ export const AlignMenuButton = defineComponent(
77
+ props => {
78
+ const editor = inject<Ref<AlexEditor>>('editor')!
79
+ const dataRangeCaches = inject<Ref<AlexElementsRangeType>>('dataRangeCaches')!
80
+ const $editTrans = inject<(key: string) => any>('$editTrans')!
81
+ const isSourceView = inject<Ref<boolean>>('isSourceView')!
82
+
83
+ return () => {
84
+ return props.config.show
85
+ ? h(
86
+ Button,
87
+ {
88
+ name: FEATURE_NAME,
89
+ tooltip: props.tooltip,
90
+ color: props.color,
91
+ zIndex: props.zIndex,
92
+ type: 'select',
93
+ title: $editTrans('align'),
94
+ selectConfig: {
95
+ options: props.config.options,
96
+ width: props.config.width,
97
+ maxHeight: props.config.maxHeight
98
+ },
99
+ leftBorder: props.config.leftBorder,
100
+ rightBorder: props.config.rightBorder,
101
+ active: false,
102
+ disabled: props.disabled || isSourceView.value || hasPreInRange(editor.value, dataRangeCaches.value) || props.config.disabled,
103
+ onOperate: (_name, val: 'left' | 'right' | 'center' | 'justify') => {
104
+ setAlign(editor.value, dataRangeCaches.value, val)
105
+ editor.value.domRender()
106
+ editor.value.rangeRender()
107
+ }
108
+ },
109
+ {
110
+ default: () => h(Icon, { value: 'align-left' })
111
+ }
112
+ )
113
+ : null
114
+ }
115
+ },
116
+ {
117
+ name: `_${FEATURE_NAME}`,
118
+ props: {
119
+ color: String,
120
+ zIndex: Number,
121
+ config: Object as PropType<MenuSelectButtonType>,
122
+ tooltip: Boolean,
123
+ disabled: Boolean
124
+ }
125
+ }
126
+ )
@@ -0,0 +1,108 @@
1
+ import { defineComponent, h, inject, PropType, ref, Ref } from 'vue'
2
+ import { AlexEditor, AlexElement, AlexElementsRangeType } from 'alex-editor'
3
+ import { MenuAttachmentButtonType, ObjectType } from '@/core/tool'
4
+ import { Button } from '@/components/button'
5
+ import { hasMathformulaInRange, hasPreInRange } from '@/core/function'
6
+ import { Icon } from '@/components/icon'
7
+ import { InsertAttachment } from '@/components/insertAttachment'
8
+
9
+ /**
10
+ * feature名称
11
+ */
12
+ const FEATURE_NAME = 'attachment'
13
+
14
+ /**
15
+ * 菜单栏 - 插入附件
16
+ */
17
+ export const AttachmentMenuButton = defineComponent(
18
+ props => {
19
+ const editor = inject<Ref<AlexEditor>>('editor')!
20
+ const dataRangeCaches = inject<Ref<AlexElementsRangeType>>('dataRangeCaches')!
21
+ const $editTrans = inject<(key: string) => any>('$editTrans')!
22
+ const isSourceView = inject<Ref<boolean>>('isSourceView')!
23
+
24
+ const btnRef = ref<InstanceType<typeof Button> | null>(null)
25
+
26
+ return () => {
27
+ return props.config.show
28
+ ? h(
29
+ Button,
30
+ {
31
+ ref: btnRef,
32
+ name: FEATURE_NAME,
33
+ tooltip: props.tooltip,
34
+ color: props.color,
35
+ zIndex: props.zIndex,
36
+ type: 'select',
37
+ hideScroll: true,
38
+ title: $editTrans('insertAttachment'),
39
+ leftBorder: props.config.leftBorder,
40
+ rightBorder: props.config.rightBorder,
41
+ active: false,
42
+ disabled: props.disabled || isSourceView.value || hasPreInRange(editor.value, dataRangeCaches.value) || hasMathformulaInRange(editor.value, dataRangeCaches.value) || props.config.disabled
43
+ },
44
+ {
45
+ default: () =>
46
+ h(Icon, {
47
+ value: 'attachment'
48
+ }),
49
+ layer: () =>
50
+ h(InsertAttachment, {
51
+ color: props.color,
52
+ accept: props.config.accept,
53
+ allowedFileType: props.config.allowedFileType,
54
+ multiple: props.config.multiple,
55
+ maxSize: props.config.maxSize,
56
+ minSize: props.config.minSize,
57
+ customUpload: props.config.customUpload,
58
+ handleError: props.config.handleError,
59
+ onChange: () => btnRef.value!.layerRef!.setPosition(),
60
+ onInsert: (name: string, urls: string[]) => {
61
+ //过滤掉空的地址
62
+ urls = urls.filter(url => {
63
+ return !!url
64
+ })
65
+ //如果有地址存在
66
+ if (urls.length) {
67
+ //遍历地址数组
68
+ urls.forEach(url => {
69
+ const marks: ObjectType = {
70
+ 'data-editify-attachment': url,
71
+ 'data-editify-attachment-name': name || $editTrans('attachmentDefaultName')
72
+ }
73
+ //创建元素
74
+ const attachmentElement = AlexElement.create({
75
+ type: 'closed',
76
+ parsedom: 'span',
77
+ marks
78
+ })
79
+ //插入编辑器
80
+ editor.value.insertElement(attachmentElement)
81
+ //移动光标到新插入的元素
82
+ editor.value.range!.anchor.moveToEnd(attachmentElement)
83
+ editor.value.range!.focus.moveToEnd(attachmentElement)
84
+ })
85
+ //渲染
86
+ editor.value.domRender()
87
+ editor.value.rangeRender()
88
+ }
89
+ //关闭浮层
90
+ btnRef.value!.show = false
91
+ }
92
+ })
93
+ }
94
+ )
95
+ : null
96
+ }
97
+ },
98
+ {
99
+ name: `_${FEATURE_NAME}`,
100
+ props: {
101
+ color: String,
102
+ zIndex: Number,
103
+ config: Object as PropType<MenuAttachmentButtonType>,
104
+ tooltip: Boolean,
105
+ disabled: Boolean
106
+ }
107
+ }
108
+ )