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.
- package/examples/App.vue +41 -88
- package/lib/components/button/button.vue.d.ts +62 -60
- package/lib/components/button/index.d.ts +4 -0
- package/lib/components/button/props.d.ts +12 -1
- package/lib/components/checkbox/checkbox.vue.d.ts +9 -9
- package/lib/components/checkbox/index.d.ts +4 -0
- package/lib/components/checkbox/props.d.ts +2 -2
- package/lib/components/colors/colors.vue.d.ts +4 -4
- package/lib/components/colors/index.d.ts +4 -0
- package/lib/components/colors/props.d.ts +2 -2
- package/lib/components/icon/index.d.ts +4 -0
- package/lib/components/insertAttachment/index.d.ts +4 -0
- package/lib/{plugins/attachment → components}/insertAttachment/insertAttachment.vue.d.ts +3 -3
- package/lib/{plugins/attachment → components}/insertAttachment/props.d.ts +1 -1
- package/lib/components/insertImage/index.d.ts +4 -0
- package/lib/components/insertImage/insertImage.vue.d.ts +3 -3
- package/lib/components/insertImage/props.d.ts +1 -1
- package/lib/components/insertLink/index.d.ts +4 -0
- package/lib/components/insertLink/insertLink.vue.d.ts +6 -6
- package/lib/components/insertLink/props.d.ts +3 -3
- package/lib/components/insertMathformula/index.d.ts +4 -0
- package/lib/{plugins/mathformula → components}/insertMathformula/insertMathformula.vue.d.ts +3 -3
- package/lib/{plugins/mathformula → components}/insertMathformula/props.d.ts +2 -2
- package/lib/components/insertTable/index.d.ts +4 -0
- package/lib/components/insertTable/insertTable.vue.d.ts +3 -3
- package/lib/components/insertTable/props.d.ts +2 -2
- package/lib/components/insertVideo/index.d.ts +4 -0
- package/lib/components/insertVideo/insertVideo.vue.d.ts +3 -3
- package/lib/components/insertVideo/props.d.ts +1 -1
- package/lib/components/layer/index.d.ts +4 -0
- package/lib/components/layer/layer.vue.d.ts +10 -8
- package/lib/components/tooltip/index.d.ts +4 -0
- package/lib/components/tooltip/tooltip.vue.d.ts +6 -4
- package/lib/components/triangle/index.d.ts +4 -0
- package/lib/components/triangle/triangle.vue.d.ts +1 -1
- package/lib/components/updateLink/index.d.ts +4 -0
- package/lib/components/updateLink/props.d.ts +17 -0
- package/lib/components/updateLink/updateLink.vue.d.ts +38 -0
- package/lib/core/function.d.ts +113 -36
- package/lib/core/rule.d.ts +20 -0
- package/lib/core/tool.d.ts +36 -34
- package/lib/editify/editify.vue.d.ts +18 -28
- package/lib/editify/menu/index.d.ts +4 -0
- package/lib/{components → editify}/menu/menu.vue.d.ts +3 -4
- package/lib/{components → editify}/menu/props.d.ts +1 -1
- package/lib/editify/props.d.ts +3 -7
- package/lib/editify/toolbar/index.d.ts +4 -0
- package/lib/{components → editify}/toolbar/props.d.ts +2 -2
- package/lib/{components → editify}/toolbar/toolbar.vue.d.ts +53 -53
- package/lib/editify.es.js +38964 -37727
- package/lib/editify.umd.js +2 -2
- package/lib/feature/align.d.ts +32 -0
- package/lib/feature/attachment.d.ts +18 -0
- package/lib/feature/backColor.d.ts +32 -0
- package/lib/feature/bold.d.ts +32 -0
- package/lib/feature/code.d.ts +32 -0
- package/lib/feature/codeBlock.d.ts +32 -0
- package/lib/feature/fontFamily.d.ts +32 -0
- package/lib/feature/fontSize.d.ts +32 -0
- package/lib/feature/foreColor.d.ts +32 -0
- package/lib/feature/formatClear.d.ts +32 -0
- package/lib/feature/fullScreen.d.ts +18 -0
- package/lib/feature/heading.d.ts +32 -0
- package/lib/feature/image.d.ts +32 -0
- package/lib/feature/indent.d.ts +18 -0
- package/lib/feature/infoBlock.d.ts +18 -0
- package/lib/feature/italic.d.ts +32 -0
- package/lib/feature/lineHeight.d.ts +32 -0
- package/lib/feature/link.d.ts +26 -0
- package/lib/feature/mathformula.d.ts +22 -0
- package/lib/feature/orderList.d.ts +32 -0
- package/lib/feature/panel.d.ts +18 -0
- package/lib/feature/quote.d.ts +18 -0
- package/lib/feature/redo.d.ts +18 -0
- package/lib/feature/separator.d.ts +18 -0
- package/lib/feature/sourceView.d.ts +18 -0
- package/lib/feature/strikethrough.d.ts +32 -0
- package/lib/feature/sub.d.ts +32 -0
- package/lib/feature/super.d.ts +32 -0
- package/lib/feature/table.d.ts +32 -0
- package/lib/feature/task.d.ts +32 -0
- package/lib/feature/underline.d.ts +32 -0
- package/lib/feature/undo.d.ts +18 -0
- package/lib/feature/unorderList.d.ts +32 -0
- package/lib/feature/video.d.ts +38 -0
- package/lib/index.d.ts +194 -202
- package/package.json +5 -5
- package/src/components/button/button.vue +21 -24
- package/src/components/button/index.ts +5 -0
- package/src/components/button/props.ts +14 -1
- package/src/components/checkbox/checkbox.vue +1 -1
- package/src/components/checkbox/index.ts +5 -0
- package/src/components/checkbox/props.ts +1 -1
- package/src/components/colors/colors.vue +3 -3
- package/src/components/colors/index.ts +5 -0
- package/src/components/colors/props.ts +2 -2
- package/src/components/icon/index.ts +5 -0
- package/src/components/insertAttachment/index.ts +5 -0
- package/src/{plugins/attachment → components}/insertAttachment/insertAttachment.vue +4 -2
- package/src/{plugins/attachment → components}/insertAttachment/props.ts +1 -1
- package/src/components/insertImage/index.ts +5 -0
- package/src/components/insertImage/insertImage.vue +5 -5
- package/src/components/insertImage/props.ts +1 -1
- package/src/components/insertLink/index.ts +5 -0
- package/src/components/insertLink/insertLink.vue +10 -10
- package/src/components/insertLink/props.ts +3 -3
- package/src/components/insertMathformula/index.ts +5 -0
- package/src/{plugins/mathformula → components}/insertMathformula/props.ts +2 -2
- package/src/components/insertTable/index.ts +5 -0
- package/src/components/insertTable/props.ts +2 -2
- package/src/components/insertVideo/index.ts +5 -0
- package/src/components/insertVideo/insertVideo.vue +2 -2
- package/src/components/insertVideo/props.ts +1 -1
- package/src/components/layer/index.ts +5 -0
- package/src/components/layer/layer.vue +42 -4
- package/src/components/tooltip/index.ts +5 -0
- package/src/components/tooltip/tooltip.vue +1 -1
- package/src/components/triangle/index.ts +5 -0
- package/src/components/triangle/triangle.vue +1 -1
- package/src/components/updateLink/index.ts +5 -0
- package/src/components/updateLink/props.ts +21 -0
- package/src/components/{toolbar/toolbar.less → updateLink/updateLink.less} +4 -20
- package/src/components/updateLink/updateLink.vue +74 -0
- package/src/core/function.ts +289 -97
- package/src/core/rule.ts +108 -29
- package/src/core/tool.ts +237 -81
- package/src/editify/editify.less +4 -0
- package/src/editify/editify.vue +183 -194
- package/src/editify/menu/index.ts +5 -0
- package/src/editify/menu/menu.vue +215 -0
- package/src/{components → editify}/menu/props.ts +1 -1
- package/src/editify/props.ts +7 -11
- package/src/editify/toolbar/index.ts +5 -0
- package/src/{components → editify}/toolbar/props.ts +1 -1
- package/src/editify/toolbar/toolbar.less +10 -0
- package/src/editify/toolbar/toolbar.vue +103 -0
- package/src/feature/align.ts +126 -0
- package/src/feature/attachment.ts +108 -0
- package/src/feature/backColor.ts +169 -0
- package/src/feature/bold.ts +134 -0
- package/src/feature/code.ts +134 -0
- package/src/feature/codeBlock.ts +201 -0
- package/src/feature/fontFamily.ts +138 -0
- package/src/feature/fontSize.ts +140 -0
- package/src/feature/foreColor.ts +171 -0
- package/src/feature/formatClear.ts +116 -0
- package/src/feature/fullScreen.ts +57 -0
- package/src/feature/heading.ts +152 -0
- package/src/feature/image.ts +222 -0
- package/src/feature/indent.ts +72 -0
- package/src/feature/infoBlock.ts +93 -0
- package/src/feature/italic.ts +134 -0
- package/src/feature/lineHeight.ts +163 -0
- package/src/feature/link.ts +146 -0
- package/src/feature/mathformula.ts +146 -0
- package/src/feature/orderList.ts +114 -0
- package/src/feature/panel.ts +107 -0
- package/src/feature/quote.ts +60 -0
- package/src/feature/redo.ts +56 -0
- package/src/feature/separator.ts +61 -0
- package/src/feature/sourceView.ts +59 -0
- package/src/feature/strikethrough.ts +134 -0
- package/src/feature/sub.ts +134 -0
- package/src/feature/super.ts +134 -0
- package/src/feature/table.ts +981 -0
- package/src/feature/task.ts +114 -0
- package/src/feature/underline.ts +134 -0
- package/src/feature/undo.ts +56 -0
- package/src/feature/unorderList.ts +114 -0
- package/src/feature/video.ts +335 -0
- package/src/hljs/index.ts +1 -1
- package/src/index.ts +82 -25
- package/src/locale/en_US.ts +3 -3
- package/src/locale/zh_CN.ts +3 -3
- package/lib/plugins/attachment/index.d.ts +0 -37
- package/lib/plugins/infoBlock/index.d.ts +0 -55
- package/lib/plugins/mathformula/index.d.ts +0 -49
- package/lib/plugins/panel/index.d.ts +0 -48
- package/src/components/menu/menu.vue +0 -1655
- package/src/components/toolbar/toolbar.vue +0 -1677
- package/src/plugins/attachment/index.ts +0 -237
- package/src/plugins/infoBlock/index.ts +0 -238
- package/src/plugins/mathformula/index.ts +0 -295
- package/src/plugins/panel/index.ts +0 -228
- package/tsconfig.json +0 -31
- package/tsconfig.node.json +0 -11
- /package/src/{plugins/attachment → components}/insertAttachment/insertAttachment.less +0 -0
- /package/src/{plugins/mathformula → components}/insertMathformula/insertMathformula.less +0 -0
- /package/src/{plugins/mathformula → components}/insertMathformula/insertMathformula.vue +0 -0
- /package/src/{components → editify}/menu/menu.less +0 -0
@@ -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>
|
package/src/editify/props.ts
CHANGED
@@ -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 {
|
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
|
71
|
+
type: String,
|
72
72
|
default: '#03a8f3',
|
73
|
-
validator(value:
|
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,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
|
+
)
|