vue-editify 0.1.17 → 0.1.19

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 (80) hide show
  1. package/README.md +3 -3
  2. package/examples/App.vue +62 -53
  3. package/examples/main.ts +4 -4
  4. package/lib/components/button/button.vue.d.ts +11 -11
  5. package/lib/components/checkbox/checkbox.vue.d.ts +8 -8
  6. package/lib/components/colors/colors.vue.d.ts +4 -4
  7. package/lib/components/icon/icon.vue.d.ts +1 -1
  8. package/lib/components/insertImage/insertImage.vue.d.ts +9 -9
  9. package/lib/components/insertLink/insertLink.vue.d.ts +2 -2
  10. package/lib/components/insertTable/insertTable.vue.d.ts +2 -2
  11. package/lib/components/insertVideo/insertVideo.vue.d.ts +9 -9
  12. package/lib/components/layer/layer.vue.d.ts +9 -9
  13. package/lib/components/menu/menu.vue.d.ts +4 -4
  14. package/lib/components/toolbar/toolbar.vue.d.ts +9 -9
  15. package/lib/components/tooltip/tooltip.vue.d.ts +1 -1
  16. package/lib/components/triangle/triangle.vue.d.ts +4 -4
  17. package/lib/editify/editify.vue.d.ts +88 -70
  18. package/lib/editify/props.d.ts +11 -3
  19. package/lib/editify.es.js +65 -46
  20. package/lib/editify.umd.js +1 -1
  21. package/lib/index.d.ts +1 -1
  22. package/lib/style.css +1 -1
  23. package/package.json +45 -45
  24. package/src/components/button/button.less +145 -145
  25. package/src/components/button/button.vue +197 -197
  26. package/src/components/button/props.ts +95 -95
  27. package/src/components/checkbox/checkbox.less +84 -84
  28. package/src/components/checkbox/checkbox.vue +68 -68
  29. package/src/components/checkbox/props.ts +49 -49
  30. package/src/components/colors/colors.less +75 -75
  31. package/src/components/colors/colors.vue +36 -36
  32. package/src/components/colors/props.ts +29 -29
  33. package/src/components/icon/icon.less +14 -14
  34. package/src/components/icon/icon.vue +12 -12
  35. package/src/components/icon/props.ts +11 -11
  36. package/src/components/insertImage/insertImage.less +135 -135
  37. package/src/components/insertImage/insertImage.vue +146 -146
  38. package/src/components/insertImage/props.ts +43 -43
  39. package/src/components/insertLink/insertLink.less +64 -64
  40. package/src/components/insertLink/insertLink.vue +58 -58
  41. package/src/components/insertLink/props.ts +16 -16
  42. package/src/components/insertTable/insertTable.less +54 -54
  43. package/src/components/insertTable/insertTable.vue +85 -85
  44. package/src/components/insertTable/props.ts +27 -27
  45. package/src/components/insertVideo/insertVideo.less +135 -135
  46. package/src/components/insertVideo/insertVideo.vue +146 -146
  47. package/src/components/insertVideo/props.ts +43 -43
  48. package/src/components/layer/layer.less +49 -49
  49. package/src/components/layer/layer.vue +598 -598
  50. package/src/components/layer/props.ts +71 -71
  51. package/src/components/menu/menu.less +63 -63
  52. package/src/components/menu/menu.vue +1569 -1569
  53. package/src/components/menu/props.ts +17 -17
  54. package/src/components/toolbar/props.ts +35 -35
  55. package/src/components/toolbar/toolbar.less +89 -89
  56. package/src/components/toolbar/toolbar.vue +1101 -1101
  57. package/src/components/tooltip/props.ts +21 -21
  58. package/src/components/tooltip/tooltip.less +23 -23
  59. package/src/components/tooltip/tooltip.vue +37 -37
  60. package/src/components/triangle/props.ts +26 -26
  61. package/src/components/triangle/triangle.less +79 -79
  62. package/src/components/triangle/triangle.vue +65 -65
  63. package/src/core/function.ts +1144 -1144
  64. package/src/core/rule.ts +259 -259
  65. package/src/core/tool.ts +1137 -1137
  66. package/src/css/base.less +30 -30
  67. package/src/css/hljs.less +54 -54
  68. package/src/editify/editify.less +404 -403
  69. package/src/editify/editify.vue +803 -792
  70. package/src/editify/props.ts +156 -146
  71. package/src/hljs/index.ts +197 -197
  72. package/src/icon/iconfont.css +219 -219
  73. package/src/index.ts +32 -32
  74. package/src/locale/en_US.ts +88 -88
  75. package/src/locale/index.ts +12 -12
  76. package/src/locale/zh_CN.ts +88 -88
  77. package/tsconfig.json +27 -27
  78. package/tsconfig.node.json +11 -11
  79. package/vite-env.d.ts +1 -1
  80. package/vite.config.ts +42 -42
@@ -1,1101 +1,1101 @@
1
- <template>
2
- <Layer v-model="show" ref="layerRef" :node="node" border placement="bottom-start" @show="layerShow" :useRange="type == 'text'" :z-index="10">
3
- <div class="editify-toolbar" ref="toolbarRef" :style="config.style">
4
- <!-- 链接工具条 -->
5
- <template v-if="type == 'link'">
6
- <div class="editify-toolbar-link">
7
- <div class="editify-toolbar-link-label">{{ $editTrans('linkAddress') }}</div>
8
- <input @change="modifyLink" @focus="handleInputFocus" @blur="handleInputBlur" :placeholder="$editTrans('linkUrlEnterPlaceholder')" v-model.trim="linkConfig.url" type="url" />
9
- <div class="editify-toolbar-link-footer">
10
- <Checkbox @change="modifyLink" v-model="linkConfig.newOpen" :label="$editTrans('newWindowOpen')" :color="color" :size="10"></Checkbox>
11
- <div class="editify-toolbar-link-operations">
12
- <span @click="removeLink">{{ $editTrans('removeLink') }}</span>
13
- <a :href="linkConfig.url" target="_blank" :style="{ color: color }">{{ $editTrans('viewLink') }}</a>
14
- </div>
15
- </div>
16
- </div>
17
- </template>
18
- <!-- 图片工具条 -->
19
- <template v-else-if="type == 'image'">
20
- <!-- 设置宽度30% -->
21
- <Button @operate="setWidth('30%')" name="set30Width" :title="$editTrans('width30')" :tooltip="config.tooltip" :color="color"> 30% </Button>
22
- <!-- 设置宽度50% -->
23
- <Button @operate="setWidth('50%')" name="set50Width" :title="$editTrans('width50')" :tooltip="config.tooltip" :color="color"> 50% </Button>
24
- <!-- 设置宽度100% -->
25
- <Button rightBorder @operate="setWidth('100%')" name="set100Width" :title="$editTrans('width100')" :tooltip="config.tooltip" :color="color"> 100% </Button>
26
- <!-- 设置宽度auto -->
27
- <Button @operate="setWidth('auto')" name="setAutoWidth" :title="$editTrans('auto')" :tooltip="config.tooltip" :color="color">
28
- <Icon value="auto-width"></Icon>
29
- </Button>
30
- <!-- 删除图片 -->
31
- <Button @operate="deleteElement('img')" name="deleteImage" :title="$editTrans('deleteImage')" :tooltip="config.tooltip" :color="color">
32
- <Icon value="delete"></Icon>
33
- </Button>
34
- </template>
35
- <!-- 视频工具条 -->
36
- <template v-else-if="type == 'video'">
37
- <!-- 设置宽度30% -->
38
- <Button @operate="setWidth('30%')" name="set30Width" :title="$editTrans('width30')" :tooltip="config.tooltip" :color="color"> 30% </Button>
39
- <!-- 设置宽度50% -->
40
- <Button @operate="setWidth('50%')" name="set50Width" :title="$editTrans('width50')" :tooltip="config.tooltip" :color="color"> 50% </Button>
41
- <!-- 设置宽度100% -->
42
- <Button @operate="setWidth('100%')" name="set100Width" :title="$editTrans('width100')" :tooltip="config.tooltip" :color="color"> 100% </Button>
43
- <!-- 设置宽度auto -->
44
- <Button rightBorder @operate="setWidth('auto')" name="setAutoWidth" :title="$editTrans('auto')" :tooltip="config.tooltip" :color="color">
45
- <Icon value="auto-width"></Icon>
46
- </Button>
47
- <!-- 自动播放 -->
48
- <Button @operate="setVideo" name="autoplay" :title="videoConfig.autoplay ? $editTrans('disabledAutoplay') : $editTrans('autoplay')" :tooltip="config.tooltip" :color="color">
49
- <Icon :value="videoConfig.autoplay ? 'autoplay' : 'stop'"></Icon>
50
- </Button>
51
- <!-- 循环播放 -->
52
- <Button @operate="setVideo" name="loop" :title="videoConfig.loop ? $editTrans('disabledLoop') : $editTrans('loop')" :tooltip="config.tooltip" :color="color">
53
- <Icon :value="videoConfig.loop ? 'loop' : 'single'"></Icon>
54
- </Button>
55
- <!-- 是否静音 -->
56
- <Button @operate="setVideo" name="muted" :title="videoConfig.muted ? $editTrans('unmuted') : $editTrans('muted')" :tooltip="config.tooltip" :color="color">
57
- <Icon :value="videoConfig.muted ? 'muted' : 'unmuted'"></Icon>
58
- </Button>
59
- <!-- 是否显示控制器 -->
60
- <Button leftBorder @operate="setVideo" name="controls" :title="$editTrans('controls')" :tooltip="config.tooltip" :color="color">
61
- <Icon value="controls"></Icon>
62
- </Button>
63
- <!-- 删除视频 -->
64
- <Button @operate="deleteElement('video')" name="deleteVideo" :title="$editTrans('deleteVideo')" :tooltip="config.tooltip" :color="color">
65
- <Icon value="delete"></Icon>
66
- </Button>
67
- </template>
68
- <!-- 表格工具条 -->
69
- <template v-else-if="type == 'table'">
70
- <!-- 表格前插入段落 -->
71
- <Button @operate="insertParagraphWithTable('up')" name="textWrapUp" :title="$editTrans('textWrapUp')" :tooltip="config.tooltip" :color="color">
72
- <Icon value="text-wrap" class="editify-icon-rotate"></Icon>
73
- </Button>
74
- <!-- 表格后插入段落 -->
75
- <Button @operate="insertParagraphWithTable('down')" rightBorder name="textWrapDown" :title="$editTrans('textWrapDown')" :tooltip="config.tooltip" :color="color">
76
- <Icon value="text-wrap"></Icon>
77
- </Button>
78
- <!-- 向前插入行 -->
79
- <Button @operate="insertTableRow('up')" name="insertRowTop" :title="$editTrans('insertRowTop')" :tooltip="config.tooltip" :color="color">
80
- <Icon value="insert-row-top"></Icon>
81
- </Button>
82
- <!-- 向后插入行 -->
83
- <Button @operate="insertTableRow('down')" name="insertRowBottom" :title="$editTrans('insertRowBottom')" :tooltip="config.tooltip" :color="color">
84
- <Icon value="insert-row-bottom"></Icon>
85
- </Button>
86
- <!-- 删除行 -->
87
- <Button @operate="deleteTableRow" rightBorder name="deleteRow" :title="$editTrans('deleteRow')" :tooltip="config.tooltip" :color="color">
88
- <Icon value="delete-row"></Icon>
89
- </Button>
90
- <!-- 向前插入列 -->
91
- <Button @operate="insertTableColumn('left')" name="insertColumnLeft" :title="$editTrans('insertColumnLeft')" :tooltip="config.tooltip" :color="color">
92
- <Icon value="insert-column-left"></Icon>
93
- </Button>
94
- <!-- 向后插入列 -->
95
- <Button @operate="insertTableColumn('right')" name="insertColumnRight" :title="$editTrans('insertColumnRight')" :tooltip="config.tooltip" :color="color">
96
- <Icon value="insert-column-right"></Icon>
97
- </Button>
98
- <!-- 删除列 -->
99
- <Button @operate="deleteTableColumn" rightBorder name="deleteColumn" :title="$editTrans('deleteColumn')" :tooltip="config.tooltip" :color="color">
100
- <Icon value="delete-column"></Icon>
101
- </Button>
102
- <!-- 删除表格 -->
103
- <Button @operate="deleteElement('table')" name="deleteTable" :title="$editTrans('deleteTable')" :tooltip="config.tooltip" :color="color">
104
- <Icon value="delete-table"></Icon>
105
- </Button>
106
- </template>
107
- <!-- 代码块工具条 -->
108
- <template v-if="type == 'codeBlock'">
109
- <!-- 代码块前插入段落 -->
110
- <Button @operate="insertParagraphWithPre('up')" name="textWrapUp" :title="$editTrans('textWrapUp')" :tooltip="config.tooltip" :color="color">
111
- <Icon value="text-wrap" class="editify-icon-rotate"></Icon>
112
- </Button>
113
- <!-- 代码块后插入段落 -->
114
- <Button @operate="insertParagraphWithPre('down')" name="textWrapDown" :title="$editTrans('textWrapDown')" :tooltip="config.tooltip" :color="color">
115
- <Icon value="text-wrap"></Icon>
116
- </Button>
117
- <!-- 代码块语言选择 -->
118
- <Button v-if="languageConfig.show" name="languages" type="display" :title="$editTrans('selectLanguages')" :tooltip="config.tooltip" :leftBorder="languageConfig.leftBorder" :rightBorder="languageConfig.rightBorder" :display-config="languageConfig.displayConfig" :color="color" :active="languageConfig.active" :disabled="languageConfig.disabled" @operate="selectLanguage"></Button>
119
- </template>
120
- <!-- 文本工具条 -->
121
- <template v-else-if="type == 'text'">
122
- <!-- 设置段落和标题 -->
123
- <Button v-if="headingConfig.show" name="heading" type="display" :title="$editTrans('heading')" :tooltip="config.tooltip" :display-config="headingConfig.displayConfig" :leftBorder="headingConfig.leftBorder" :rightBorder="headingConfig.rightBorder" :color="color" :active="headingConfig.active" :disabled="headingConfig.disabled" @operate="_setHeading"></Button>
124
- <!-- 对齐方式 -->
125
- <Button v-if="alignConfig.show" name="align" type="select" :title="$editTrans('align')" :tooltip="config.tooltip" :select-config="alignConfig.selectConfig" :leftBorder="alignConfig.leftBorder" :rightBorder="alignConfig.rightBorder" :color="color" :active="alignConfig.active" :disabled="alignConfig.disabled" @operate="_setAlign">
126
- <Icon value="align-left"></Icon>
127
- </Button>
128
- <!-- 有序列表 -->
129
- <Button v-if="orderListConfig.show" name="orderList" :title="$editTrans('orderList')" :tooltip="config.tooltip" :leftBorder="orderListConfig.leftBorder" :rightBorder="orderListConfig.rightBorder" :color="color" :active="orderListConfig.active" :disabled="orderListConfig.disabled" @operate="_setList">
130
- <Icon value="list-ordered"></Icon>
131
- </Button>
132
- <!-- 无序列表 -->
133
- <Button v-if="unorderListConfig.show" name="unorderList" :title="$editTrans('unorderList')" :tooltip="config.tooltip" :leftBorder="unorderListConfig.leftBorder" :rightBorder="unorderListConfig.rightBorder" :color="color" :active="unorderListConfig.active" :disabled="unorderListConfig.disabled" @operate="_setList">
134
- <Icon value="list-unordered"></Icon>
135
- </Button>
136
- <!-- 任务列表 -->
137
- <Button v-if="taskConfig.show" name="task" :title="$editTrans('task')" :tooltip="config.tooltip" :leftBorder="taskConfig.leftBorder" :rightBorder="taskConfig.rightBorder" :color="color" :active="taskConfig.active" :disabled="taskConfig.disabled" @operate="_setTask">
138
- <Icon value="task"></Icon>
139
- </Button>
140
- <!-- 加粗 -->
141
- <Button v-if="boldConfig.show" name="bold" :title="$editTrans('bold')" :tooltip="config.tooltip" :leftBorder="boldConfig.leftBorder" :rightBorder="boldConfig.rightBorder" :color="color" :active="boldConfig.active" :disabled="boldConfig.disabled" @operate="setBold">
142
- <Icon value="bold"></Icon>
143
- </Button>
144
- <!-- 斜体 -->
145
- <Button v-if="italicConfig.show" name="italic" :title="$editTrans('italic')" :tooltip="config.tooltip" :leftBorder="italicConfig.leftBorder" :rightBorder="italicConfig.rightBorder" :color="color" :active="italicConfig.active" :disabled="italicConfig.disabled" @operate="setItalic">
146
- <Icon value="italic"></Icon>
147
- </Button>
148
- <!-- 删除线 -->
149
- <Button v-if="strikethroughConfig.show" name="strikethrough" :title="$editTrans('strikethrough')" :tooltip="config.tooltip" :leftBorder="strikethroughConfig.leftBorder" :rightBorder="strikethroughConfig.rightBorder" :color="color" :active="strikethroughConfig.active" :disabled="strikethroughConfig.disabled" @operate="setStrikethrough">
150
- <Icon value="strikethrough"></Icon>
151
- </Button>
152
- <!-- 下划线 -->
153
- <Button v-if="underlineConfig.show" name="underline" :title="$editTrans('underline')" :tooltip="config.tooltip" :leftBorder="underlineConfig.leftBorder" :rightBorder="underlineConfig.rightBorder" :color="color" :active="underlineConfig.active" :disabled="underlineConfig.disabled" @operate="setUnderline">
154
- <Icon value="underline"></Icon>
155
- </Button>
156
- <!-- 行内代码块 -->
157
- <Button v-if="codeConfig.show" name="code" :title="$editTrans('code')" :tooltip="config.tooltip" :leftBorder="codeConfig.leftBorder" :rightBorder="codeConfig.rightBorder" :color="color" :active="codeConfig.active" :disabled="codeConfig.disabled" @operate="setCodeStyle">
158
- <Icon value="code"></Icon>
159
- </Button>
160
- <!-- 上标 -->
161
- <Button v-if="superConfig.show" name="superscript" :title="$editTrans('superscript')" :tooltip="config.tooltip" :leftBorder="superConfig.leftBorder" :rightBorder="superConfig.rightBorder" :color="color" :active="superConfig.active" :disabled="superConfig.disabled" @operate="setSuperscript">
162
- <Icon value="superscript"></Icon>
163
- </Button>
164
- <!-- 下标 -->
165
- <Button v-if="subConfig.show" name="subscript" :title="$editTrans('subscript')" :tooltip="config.tooltip" :leftBorder="subConfig.leftBorder" :rightBorder="subConfig.rightBorder" :color="color" :active="subConfig.active" :disabled="subConfig.disabled" @operate="setSubscript">
166
- <Icon value="subscript"></Icon>
167
- </Button>
168
- <!-- 字号大小 -->
169
- <Button v-if="fontSizeConfig.show" name="fontSize" type="display" :title="$editTrans('fontSize')" :tooltip="config.tooltip" :display-config="fontSizeConfig.displayConfig" :leftBorder="fontSizeConfig.leftBorder" :rightBorder="fontSizeConfig.rightBorder" :color="color" :active="fontSizeConfig.active" :disabled="fontSizeConfig.disabled" @operate="setFontSize"></Button>
170
- <!-- 字体 -->
171
- <Button v-if="fontFamilyConfig.show" name="fontFamily" type="display" :title="$editTrans('fontFamily')" :tooltip="config.tooltip" :display-config="fontFamilyConfig.displayConfig" :leftBorder="fontFamilyConfig.leftBorder" :rightBorder="fontFamilyConfig.rightBorder" :color="color" :active="fontFamilyConfig.active" :disabled="fontFamilyConfig.disabled" @operate="setFontFamily"></Button>
172
- <!-- 行高 -->
173
- <Button v-if="lineHeightConfig.show" name="lineHeight" type="display" :title="$editTrans('lineHeight')" :tooltip="config.tooltip" :display-config="lineHeightConfig.displayConfig" :leftBorder="lineHeightConfig.leftBorder" :rightBorder="lineHeightConfig.rightBorder" :color="color" :active="lineHeightConfig.active" :disabled="lineHeightConfig.disabled" @operate="_setLineHeight"></Button>
174
- <!-- 前景色 -->
175
- <Button v-if="foreColorConfig.show" name="foreColor" type="select" :title="$editTrans('foreColor')" :tooltip="config.tooltip" :select-config="foreColorConfig.selectConfig" :leftBorder="foreColorConfig.leftBorder" :rightBorder="foreColorConfig.rightBorder" :color="color" :active="foreColorConfig.active" :disabled="foreColorConfig.disabled" hideScroll ref="foreColorRef">
176
- <Icon value="font-color"></Icon>
177
- <template #layer="{ options }">
178
- <Colors :tooltip="config.tooltip" :color="color" :value="foreColorConfig.value" @change="setForeColor" :data="options"></Colors>
179
- </template>
180
- </Button>
181
- <!-- 背景色 -->
182
- <Button v-if="backColorConfig.show" name="backColor" type="select" :title="$editTrans('backColor')" :tooltip="config.tooltip" :select-config="backColorConfig.selectConfig" :leftBorder="backColorConfig.leftBorder" :rightBorder="backColorConfig.rightBorder" :color="color" :active="backColorConfig.active" :disabled="backColorConfig.disabled" hideScroll ref="backColorRef">
183
- <Icon value="brush"></Icon>
184
- <template #layer="{ options }">
185
- <Colors :tooltip="config.tooltip" :color="color" :value="backColorConfig.value" @change="setBackColor" :data="options"></Colors>
186
- </template>
187
- </Button>
188
- <!-- 清除样式 -->
189
- <Button v-if="formatClearConfig.show" name="formatClear" :title="$editTrans('formatClear')" :tooltip="config.tooltip" :leftBorder="formatClearConfig.leftBorder" :rightBorder="formatClearConfig.rightBorder" :color="color" :active="formatClearConfig.active" :disabled="formatClearConfig.disabled" @operate="clearFormat">
190
- <Icon value="format-clear"></Icon>
191
- </Button>
192
- </template>
193
- </div>
194
- </Layer>
195
- </template>
196
- <script setup lang="ts">
197
- import Layer from '../layer/layer.vue'
198
- import Button from '../button/button.vue'
199
- import Icon from '../icon/icon.vue'
200
- import Checkbox from '../checkbox/checkbox.vue'
201
- import Colors from '../colors/colors.vue'
202
- import { AlexEditor, AlexElement, AlexElementsRangeType } from 'alex-editor'
203
- import { common as DapCommon } from 'dap-util'
204
- import { getCurrentParsedomElement, removeTextStyle, removeTextMark, setTextStyle, setLineHeight, setTextMark, setList, setTask, setHeading, setAlign, isRangeInList, isRangeInTask, queryTextStyle, queryTextMark } from '../../core/function'
205
- import { ToolbarProps } from './props'
206
- import { ComponentInternalInstance, Ref, computed, inject, ref } from 'vue'
207
- import { ObjectType } from '../../core/tool'
208
- import { ButtonOptionsItemType } from '../button/props'
209
-
210
- defineOptions({
211
- name: 'Toolbar'
212
- })
213
- const props = defineProps(ToolbarProps)
214
- const emits = defineEmits(['update:modelValue'])
215
-
216
- const editify = inject<ComponentInternalInstance>('editify')!
217
- const editor = inject<Ref<AlexEditor>>('editor')!
218
- const dataRangeCaches = inject<Ref<AlexElementsRangeType>>('dataRangeCaches')!
219
- const $editTrans = inject<(key: string) => any>('$editTrans')!
220
-
221
- const layerRef = ref<InstanceType<typeof Layer> | null>(null)
222
- const toolbarRef = ref<HTMLElement | null>(null)
223
- const foreColorRef = ref<InstanceType<typeof Button> | null>(null)
224
- const backColorRef = ref<InstanceType<typeof Button> | null>(null)
225
-
226
- //链接参数配置
227
- const linkConfig = ref<ObjectType>({
228
- //链接地址
229
- url: '',
230
- //链接是否新窗口打开
231
- newOpen: false
232
- })
233
- //视频参数配置
234
- const videoConfig = ref<ObjectType>({
235
- //是否显示控制器
236
- controls: false,
237
- //是否循环
238
- loop: false,
239
- //是否自动播放
240
- autoplay: false,
241
- //是否静音
242
- muted: false
243
- })
244
- //代码块选择语言按钮配置
245
- const languageConfig = ref<ObjectType>({
246
- show: props.config.codeBlock!.languages!.show,
247
- displayConfig: {
248
- options: props.config.codeBlock!.languages!.options,
249
- value: '',
250
- width: props.config.codeBlock!.languages!.width,
251
- maxHeight: props.config.codeBlock!.languages!.maxHeight
252
- },
253
- leftBorder: props.config.codeBlock!.languages!.leftBorder,
254
- rightBorder: props.config.codeBlock!.languages!.rightBorder,
255
- active: false,
256
- disabled: false
257
- })
258
- //标题按钮配置
259
- const headingConfig = ref<ObjectType>({
260
- show: props.config.text!.heading!.show,
261
- displayConfig: {
262
- options: props.config.text!.heading!.options,
263
- value: '',
264
- width: props.config.text!.heading!.width,
265
- maxHeight: props.config.text!.heading!.maxHeight
266
- },
267
- defaultValue: props.config.text!.heading!.defaultValue,
268
- leftBorder: props.config.text!.heading!.leftBorder,
269
- rightBorder: props.config.text!.heading!.rightBorder,
270
- active: false,
271
- disabled: false
272
- })
273
- //对齐方式按钮配置
274
- const alignConfig = ref<ObjectType>({
275
- show: props.config.text!.align!.show,
276
- selectConfig: {
277
- options: props.config.text!.align!.options,
278
- width: props.config.text!.align!.width,
279
- maxHeight: props.config.text!.align!.maxHeight
280
- },
281
- leftBorder: props.config.text!.align!.leftBorder,
282
- rightBorder: props.config.text!.align!.rightBorder,
283
- active: false,
284
- disabled: false
285
- })
286
- //有序列表按钮配置
287
- const orderListConfig = ref<ObjectType>({
288
- show: props.config.text!.orderList!.show,
289
- leftBorder: props.config.text!.orderList!.leftBorder,
290
- rightBorder: props.config.text!.orderList!.rightBorder,
291
- active: false,
292
- disabled: false
293
- })
294
- //无序列表按钮配置
295
- const unorderListConfig = ref<ObjectType>({
296
- show: props.config.text!.unorderList!.show,
297
- leftBorder: props.config.text!.unorderList!.leftBorder,
298
- rightBorder: props.config.text!.unorderList!.rightBorder,
299
- active: false,
300
- disabled: false
301
- })
302
- //任务列表按钮配置
303
- const taskConfig = ref<ObjectType>({
304
- show: props.config.text!.task!.show,
305
- leftBorder: props.config.text!.task!.leftBorder,
306
- rightBorder: props.config.text!.task!.rightBorder,
307
- active: false,
308
- disabled: false
309
- })
310
- //粗体按钮配置
311
- const boldConfig = ref<ObjectType>({
312
- show: props.config.text!.bold!.show,
313
- leftBorder: props.config.text!.bold!.leftBorder,
314
- rightBorder: props.config.text!.bold!.rightBorder,
315
- active: false,
316
- disabled: false
317
- })
318
- //斜体按钮配置
319
- const italicConfig = ref<ObjectType>({
320
- show: props.config.text!.italic!.show,
321
- leftBorder: props.config.text!.italic!.leftBorder,
322
- rightBorder: props.config.text!.italic!.rightBorder,
323
- active: false,
324
- disabled: false
325
- })
326
- //删除线按钮配置
327
- const strikethroughConfig = ref<ObjectType>({
328
- show: props.config.text!.strikethrough!.show,
329
- leftBorder: props.config.text!.strikethrough!.leftBorder,
330
- rightBorder: props.config.text!.strikethrough!.rightBorder,
331
- active: false,
332
- disabled: false
333
- })
334
- //下划线按钮配置
335
- const underlineConfig = ref<ObjectType>({
336
- show: props.config.text!.underline!.show,
337
- leftBorder: props.config.text!.underline!.leftBorder,
338
- rightBorder: props.config.text!.underline!.rightBorder,
339
- active: false,
340
- disabled: false
341
- })
342
- //行内代码块按钮配置
343
- const codeConfig = ref<ObjectType>({
344
- show: props.config.text!.code!.show,
345
- leftBorder: props.config.text!.code!.leftBorder,
346
- rightBorder: props.config.text!.code!.rightBorder,
347
- active: false,
348
- disabled: false
349
- })
350
- //上标按钮配置
351
- const superConfig = ref<ObjectType>({
352
- show: props.config.text!.super!.show,
353
- leftBorder: props.config.text!.super!.leftBorder,
354
- rightBorder: props.config.text!.super!.rightBorder,
355
- active: false,
356
- disabled: false
357
- })
358
- //下标按钮配置
359
- const subConfig = ref<ObjectType>({
360
- show: props.config.text!.sub!.show,
361
- leftBorder: props.config.text!.sub!.leftBorder,
362
- rightBorder: props.config.text!.sub!.rightBorder,
363
- active: false,
364
- disabled: false
365
- })
366
- //字号按钮配置
367
- const fontSizeConfig = ref<ObjectType>({
368
- show: props.config.text!.fontSize!.show,
369
- displayConfig: {
370
- options: props.config.text!.fontSize!.options,
371
- value: '',
372
- width: props.config.text!.fontSize!.width,
373
- maxHeight: props.config.text!.fontSize!.maxHeight
374
- },
375
- defaultValue: props.config.text!.fontSize!.defaultValue,
376
- leftBorder: props.config.text!.fontSize!.leftBorder,
377
- rightBorder: props.config.text!.fontSize!.rightBorder,
378
- active: false,
379
- disabled: false
380
- })
381
- //字体按钮配置
382
- const fontFamilyConfig = ref<ObjectType>({
383
- show: props.config.text!.fontFamily!.show,
384
- displayConfig: {
385
- options: props.config.text!.fontFamily!.options,
386
- value: '',
387
- width: props.config.text!.fontFamily!.width,
388
- maxHeight: props.config.text!.fontFamily!.maxHeight
389
- },
390
- defaultValue: props.config.text!.fontFamily!.defaultValue,
391
- leftBorder: props.config.text!.fontFamily!.leftBorder,
392
- rightBorder: props.config.text!.fontFamily!.rightBorder,
393
- active: false,
394
- disabled: false
395
- })
396
- //行高按钮配置
397
- const lineHeightConfig = ref<ObjectType>({
398
- show: props.config.text!.lineHeight!.show,
399
- displayConfig: {
400
- options: props.config.text!.lineHeight!.options,
401
- value: '',
402
- width: props.config.text!.lineHeight!.width,
403
- maxHeight: props.config.text!.lineHeight!.maxHeight
404
- },
405
- defaultValue: props.config.text!.lineHeight!.defaultValue,
406
- leftBorder: props.config.text!.lineHeight!.leftBorder,
407
- rightBorder: props.config.text!.lineHeight!.rightBorder,
408
- active: false,
409
- disabled: false
410
- })
411
- //前景颜色按钮配置
412
- const foreColorConfig = ref<ObjectType>({
413
- show: props.config.text!.foreColor!.show,
414
- selectConfig: {
415
- options: props.config.text!.foreColor!.options
416
- },
417
- leftBorder: props.config.text!.foreColor!.leftBorder,
418
- rightBorder: props.config.text!.foreColor!.rightBorder,
419
- value: '', //选择的颜色值
420
- active: false,
421
- disabled: false
422
- })
423
- //背景颜色按钮配置
424
- const backColorConfig = ref<ObjectType>({
425
- show: props.config.text!.backColor!.show,
426
- selectConfig: {
427
- options: props.config.text!.backColor!.options
428
- },
429
- leftBorder: props.config.text!.backColor!.leftBorder,
430
- rightBorder: props.config.text!.backColor!.rightBorder,
431
- value: '', //选择的颜色值
432
- active: false,
433
- disabled: false
434
- })
435
- //清除格式按钮配置
436
- const formatClearConfig = ref<ObjectType>({
437
- show: props.config.text!.formatClear!.show,
438
- leftBorder: props.config.text!.formatClear!.leftBorder,
439
- rightBorder: props.config.text!.formatClear!.rightBorder,
440
- active: false,
441
- disabled: false
442
- })
443
-
444
- //是否显示
445
- const show = computed<boolean>({
446
- get() {
447
- return props.modelValue
448
- },
449
- set(val) {
450
- emits('update:modelValue', val)
451
- }
452
- })
453
-
454
- //输入框获取焦点
455
- const handleInputFocus = (e: Event) => {
456
- if (props.color) {
457
- ;(<HTMLInputElement>e.currentTarget).style.borderColor = props.color
458
- }
459
- }
460
- //输入框失去焦点
461
- const handleInputBlur = (e: Event) => {
462
- ;(<HTMLInputElement>e.currentTarget).style.borderColor = ''
463
- }
464
- //清除格式
465
- const clearFormat = () => {
466
- removeTextStyle(editor.value, dataRangeCaches.value)
467
- removeTextMark(editor.value, dataRangeCaches.value)
468
- editor.value.formatElementStack()
469
- editor.value.domRender()
470
- editor.value.rangeRender()
471
- }
472
- //设置背景色
473
- const setBackColor = (value: string) => {
474
- setTextStyle(editor.value, dataRangeCaches.value, {
475
- 'background-color': value
476
- })
477
- backColorRef.value!.show = false
478
- editor.value.formatElementStack()
479
- editor.value.domRender()
480
- editor.value.rangeRender()
481
- }
482
- //设置前景色
483
- const setForeColor = (value: string) => {
484
- setTextStyle(editor.value, dataRangeCaches.value, {
485
- color: value
486
- })
487
- foreColorRef.value!.show = false
488
- editor.value.formatElementStack()
489
- editor.value.domRender()
490
- editor.value.rangeRender()
491
- }
492
- //设置行高
493
- const _setLineHeight = (_name: string, value: string | number) => {
494
- setLineHeight(editor.value, dataRangeCaches.value, value)
495
- editor.value.formatElementStack()
496
- editor.value.domRender()
497
- editor.value.rangeRender()
498
- }
499
- //设置字体
500
- const setFontFamily = (_name: string, value: string | number) => {
501
- setTextStyle(editor.value, dataRangeCaches.value, {
502
- 'font-family': value
503
- })
504
- editor.value.formatElementStack()
505
- editor.value.domRender()
506
- editor.value.rangeRender()
507
- }
508
- //设置字号
509
- const setFontSize = (_name: string, value: string | number) => {
510
- setTextStyle(editor.value, dataRangeCaches.value, {
511
- 'font-size': value
512
- })
513
- editor.value.formatElementStack()
514
- editor.value.domRender()
515
- editor.value.rangeRender()
516
- }
517
- //设置上标
518
- const setSuperscript = () => {
519
- if (queryTextStyle(editor.value, dataRangeCaches.value, 'vertical-align', 'super')) {
520
- removeTextStyle(editor.value, dataRangeCaches.value, ['vertical-align'])
521
- } else {
522
- setTextStyle(editor.value, dataRangeCaches.value, {
523
- 'vertical-align': 'super'
524
- })
525
- }
526
- editor.value.formatElementStack()
527
- editor.value.domRender()
528
- editor.value.rangeRender()
529
- }
530
- //设置下标
531
- const setSubscript = () => {
532
- if (queryTextStyle(editor.value, dataRangeCaches.value, 'vertical-align', 'sub')) {
533
- removeTextStyle(editor.value, dataRangeCaches.value, ['vertical-align'])
534
- } else {
535
- setTextStyle(editor.value, dataRangeCaches.value, {
536
- 'vertical-align': 'sub'
537
- })
538
- }
539
- editor.value.formatElementStack()
540
- editor.value.domRender()
541
- editor.value.rangeRender()
542
- }
543
- //设置行内代码样式
544
- const setCodeStyle = () => {
545
- if (queryTextMark(editor.value, dataRangeCaches.value, 'data-editify-code')) {
546
- removeTextMark(editor.value, dataRangeCaches.value, ['data-editify-code'])
547
- } else {
548
- setTextMark(editor.value, dataRangeCaches.value, {
549
- 'data-editify-code': true
550
- })
551
- }
552
- editor.value.formatElementStack()
553
- editor.value.domRender()
554
- editor.value.rangeRender()
555
- }
556
- //设置下划线
557
- const setUnderline = () => {
558
- if (queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration', 'underline') || queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration-line', 'underline')) {
559
- removeTextStyle(editor.value, dataRangeCaches.value, ['text-decoration', 'text-decoration-line'])
560
- } else {
561
- setTextStyle(editor.value, dataRangeCaches.value, {
562
- 'text-decoration': 'underline'
563
- })
564
- }
565
- editor.value.formatElementStack()
566
- editor.value.domRender()
567
- editor.value.rangeRender()
568
- }
569
- //设置删除线
570
- const setStrikethrough = () => {
571
- if (queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration', 'line-through') || queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration-line', 'line-through')) {
572
- removeTextStyle(editor.value, dataRangeCaches.value, ['text-decoration', 'text-decoration-line'])
573
- } else {
574
- setTextStyle(editor.value, dataRangeCaches.value, {
575
- 'text-decoration': 'line-through'
576
- })
577
- }
578
- editor.value.formatElementStack()
579
- editor.value.domRender()
580
- editor.value.rangeRender()
581
- }
582
- //设置列表
583
- const _setList = (name: string) => {
584
- setList(editor.value, dataRangeCaches.value, name == 'orderList')
585
- editor.value.formatElementStack()
586
- editor.value.domRender()
587
- editor.value.rangeRender()
588
- }
589
- //设置任务列表
590
- const _setTask = () => {
591
- setTask(editor.value, dataRangeCaches.value)
592
- editor.value.formatElementStack()
593
- editor.value.domRender()
594
- editor.value.rangeRender()
595
- }
596
- //斜体
597
- const setItalic = () => {
598
- if (queryTextStyle(editor.value, dataRangeCaches.value, 'font-style', 'italic')) {
599
- removeTextStyle(editor.value, dataRangeCaches.value, ['font-style'])
600
- } else {
601
- setTextStyle(editor.value, dataRangeCaches.value, {
602
- 'font-style': 'italic'
603
- })
604
- }
605
- editor.value.formatElementStack()
606
- editor.value.domRender()
607
- editor.value.rangeRender()
608
- }
609
- //加粗
610
- const setBold = () => {
611
- if (queryTextStyle(editor.value, dataRangeCaches.value, 'font-weight', 'bold') || queryTextStyle(editor.value, dataRangeCaches.value, 'font-weight', '700')) {
612
- removeTextStyle(editor.value, dataRangeCaches.value, ['font-weight'])
613
- } else {
614
- setTextStyle(editor.value, dataRangeCaches.value, {
615
- 'font-weight': 'bold'
616
- })
617
- }
618
- editor.value.formatElementStack()
619
- editor.value.domRender()
620
- editor.value.rangeRender()
621
- }
622
- //设置标题
623
- const _setHeading = (_name: string, value: string) => {
624
- setHeading(editor.value, dataRangeCaches.value, $editTrans, value)
625
- editor.value.formatElementStack()
626
- editor.value.domRender()
627
- editor.value.rangeRender()
628
- }
629
- //设置对齐方式
630
- const _setAlign = (_name: string, value: string) => {
631
- setAlign(editor.value, dataRangeCaches.value, value)
632
- editor.value.formatElementStack()
633
- editor.value.domRender()
634
- editor.value.rangeRender()
635
- }
636
- //设置视频属性
637
- const setVideo = (prop: string) => {
638
- const element = editor.value.range!.anchor.element
639
- //当前是拥有该属性
640
- if (videoConfig.value[prop]) {
641
- delete element.marks![prop]
642
- }
643
- //当前无该属性
644
- else {
645
- element.marks![prop] = true
646
- }
647
- videoConfig.value[prop] = !videoConfig.value[prop]
648
- editor.value.formatElementStack()
649
- editor.value.domRender()
650
- editor.value.rangeRender()
651
- }
652
- //设置图片或者视频宽度
653
- const setWidth = (value: string) => {
654
- const element = editor.value.range!.anchor.element
655
- if (element) {
656
- const styles = {
657
- width: value
658
- }
659
- if (element.hasStyles()) {
660
- element.styles = Object.assign(element.styles!, styles)
661
- } else {
662
- element.styles = styles
663
- }
664
- editor.value.formatElementStack()
665
- editor.value.domRender()
666
- editor.value.rangeRender()
667
- //更新工具条位置
668
- setTimeout(() => {
669
- layerRef.value!.setPosition()
670
- }, 0)
671
- }
672
- }
673
- //修改链接
674
- const modifyLink = () => {
675
- if (!linkConfig.value.url) {
676
- return
677
- }
678
- const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
679
- if (link) {
680
- link.marks!.href = linkConfig.value.url
681
- if (linkConfig.value.newOpen) {
682
- link.marks!.target = '_blank'
683
- } else {
684
- delete link.marks!.target
685
- }
686
- }
687
- editor.value.formatElementStack()
688
- editor.value.domRender()
689
- }
690
- //移除链接
691
- const removeLink = () => {
692
- const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
693
- if (link) {
694
- link.parsedom = AlexElement.TEXT_NODE
695
- delete link.marks!['target']
696
- delete link.marks!['href']
697
- delete link.marks!['data-editify-element']
698
- }
699
- editor.value.formatElementStack()
700
- editor.value.domRender()
701
- editor.value.rangeRender()
702
- }
703
- //选择代码语言
704
- const selectLanguage = (_name: string, value: string) => {
705
- const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
706
- if (pre) {
707
- Object.assign(pre.marks!, {
708
- 'data-editify-hljs': value
709
- })
710
- editor.value.formatElementStack()
711
- editor.value.domRender()
712
- editor.value.rangeRender()
713
- }
714
- }
715
- //代码块前后插入段落
716
- const insertParagraphWithPre = (type: string | undefined = 'up') => {
717
- if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
718
- editor.value.range!.anchor.element = editor.value.range!.focus.element
719
- editor.value.range!.anchor.offset = editor.value.range!.focus.offset
720
- }
721
- const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
722
- if (pre) {
723
- const paragraph = new AlexElement('block', AlexElement.BLOCK_NODE, null, null, null)
724
- const breakEl = new AlexElement('closed', 'br', null, null, null)
725
- editor.value.addElementTo(breakEl, paragraph)
726
- if (type == 'up') {
727
- editor.value.addElementBefore(paragraph, pre)
728
- } else {
729
- editor.value.addElementAfter(paragraph, pre)
730
- }
731
- editor.value.range!.anchor.moveToEnd(paragraph)
732
- editor.value.range!.focus.moveToEnd(paragraph)
733
- editor.value.formatElementStack()
734
- editor.value.domRender()
735
- editor.value.rangeRender()
736
- }
737
- }
738
- //表格前后插入列
739
- const insertTableColumn = (type: string | undefined = 'left') => {
740
- if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
741
- editor.value.range!.anchor.element = editor.value.range!.focus.element
742
- editor.value.range!.anchor.offset = editor.value.range!.focus.offset
743
- }
744
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
745
- const column = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'td')
746
- const tbody = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tbody')
747
- if (column && table && tbody) {
748
- const rows = tbody.children
749
- const index = column.parent!.children!.findIndex(item => {
750
- return item.isEqual(column)
751
- })
752
- //插入列
753
- rows!.forEach(row => {
754
- const newColumn = column.clone(false)
755
- const breakEl = new AlexElement('closed', 'br', null, null, null)
756
- editor.value.addElementTo(breakEl, newColumn)
757
- if (type == 'left') {
758
- editor.value.addElementTo(newColumn, row, index)
759
- } else {
760
- editor.value.addElementTo(newColumn, row, index + 1)
761
- }
762
- })
763
- //插入col
764
- const colgroup = table.children!.find(item => {
765
- return item.parsedom == 'colgroup'
766
- })!
767
- const col = new AlexElement('closed', 'col', null, null, null)
768
- if (type == 'left') {
769
- editor.value.addElementTo(col, colgroup, index)
770
- } else {
771
- editor.value.addElementTo(col, colgroup, index + 1)
772
- }
773
- //渲染
774
- editor.value.formatElementStack()
775
- if (type == 'left') {
776
- const previousColumn = editor.value.getPreviousElement(column)!
777
- editor.value.range!.anchor.moveToStart(previousColumn)
778
- editor.value.range!.focus.moveToStart(previousColumn)
779
- } else {
780
- const nextColumn = editor.value.getNextElement(column)!
781
- editor.value.range!.anchor.moveToStart(nextColumn)
782
- editor.value.range!.focus.moveToStart(nextColumn)
783
- }
784
- editor.value.domRender()
785
- editor.value.rangeRender()
786
- }
787
- }
788
- //表格前后插入行
789
- const insertTableRow = (type: string | undefined = 'up') => {
790
- if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
791
- editor.value.range!.anchor.element = editor.value.range!.focus.element
792
- editor.value.range!.anchor.offset = editor.value.range!.focus.offset
793
- }
794
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
795
- const row = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tr')
796
- if (table && row) {
797
- const newRow = row.clone()
798
- newRow.children!.forEach(column => {
799
- column.children = []
800
- const breakEl = new AlexElement('closed', 'br', null, null, null)
801
- editor.value.addElementTo(breakEl, column)
802
- })
803
- if (type == 'up') {
804
- editor.value.addElementBefore(newRow, row)
805
- } else {
806
- editor.value.addElementAfter(newRow, row)
807
- }
808
- editor.value.formatElementStack()
809
- editor.value.range!.anchor.moveToStart(newRow)
810
- editor.value.range!.focus.moveToStart(newRow)
811
- editor.value.domRender()
812
- editor.value.rangeRender()
813
- //更新工具条位置
814
- setTimeout(() => {
815
- layerRef.value!.setPosition()
816
- }, 0)
817
- }
818
- }
819
- //表格前后插入段落
820
- const insertParagraphWithTable = (type: string | undefined = 'up') => {
821
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
822
- if (table) {
823
- const paragraph = new AlexElement('block', AlexElement.BLOCK_NODE, null, null, null)
824
- const breakEl = new AlexElement('closed', 'br', null, null, null)
825
- editor.value.addElementTo(breakEl, paragraph)
826
- if (type == 'up') {
827
- editor.value.addElementBefore(paragraph, table)
828
- } else {
829
- editor.value.addElementAfter(paragraph, table)
830
- }
831
- editor.value.range!.anchor.moveToEnd(paragraph)
832
- editor.value.range!.focus.moveToEnd(paragraph)
833
- editor.value.formatElementStack()
834
- editor.value.domRender()
835
- editor.value.rangeRender()
836
- }
837
- }
838
- //删除元素
839
- const deleteElement = (parsedom: string) => {
840
- const element = getCurrentParsedomElement(editor.value, dataRangeCaches.value, parsedom)
841
- if (element) {
842
- element.toEmpty()
843
- editor.value.formatElementStack()
844
- editor.value.domRender()
845
- editor.value.rangeRender()
846
- }
847
- }
848
- //删除表格行
849
- const deleteTableRow = () => {
850
- if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
851
- editor.value.range!.anchor.element = editor.value.range!.focus.element
852
- editor.value.range!.anchor.offset = editor.value.range!.focus.offset
853
- }
854
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
855
- const row = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tr')
856
- if (table && row) {
857
- const parent = row.parent!
858
- if (parent.children!.length == 1) {
859
- deleteElement('table')
860
- return
861
- }
862
- const previousRow = editor.value.getPreviousElement(row)!
863
- const nextRow = editor.value.getNextElement(row)!
864
- row.toEmpty()
865
- editor.value.formatElementStack()
866
- if (previousRow) {
867
- editor.value.range!.anchor.moveToEnd(previousRow.children![0])
868
- editor.value.range!.focus.moveToEnd(previousRow.children![0])
869
- } else {
870
- editor.value.range!.anchor.moveToEnd(nextRow.children![0])
871
- editor.value.range!.focus.moveToEnd(nextRow.children![0])
872
- }
873
- editor.value.domRender()
874
- editor.value.rangeRender()
875
- //更新工具条位置
876
- setTimeout(() => {
877
- layerRef.value!.setPosition()
878
- }, 0)
879
- }
880
- }
881
- //删除表格列
882
- const deleteTableColumn = () => {
883
- if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
884
- editor.value.range!.anchor.element = editor.value.range!.focus.element
885
- editor.value.range!.anchor.offset = editor.value.range!.focus.offset
886
- }
887
- const column = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'td')
888
- const tbody = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tbody')
889
- const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
890
- if (column && table && tbody) {
891
- const rows = tbody.children!
892
- const parent = column.parent!
893
- if (parent.children!.length == 1) {
894
- deleteElement('table')
895
- return
896
- }
897
- const previousColumn = editor.value.getPreviousElement(column)!
898
- const nextColumn = editor.value.getNextElement(column)!
899
- const index = column.parent!.children!.findIndex(item => {
900
- return item.isEqual(column)
901
- })
902
- //删除列
903
- rows.forEach(row => {
904
- row.children![index].toEmpty()
905
- })
906
- //删除col
907
- const colgroup = table.children!.find(item => {
908
- return item.parsedom == 'colgroup'
909
- })!
910
- colgroup.children![index].toEmpty()
911
- //渲染
912
- editor.value.formatElementStack()
913
- if (previousColumn) {
914
- editor.value.range!.anchor.moveToEnd(previousColumn)
915
- editor.value.range!.focus.moveToEnd(previousColumn)
916
- } else {
917
- editor.value.range!.anchor.moveToEnd(nextColumn)
918
- editor.value.range!.focus.moveToEnd(nextColumn)
919
- }
920
- editor.value.domRender()
921
- editor.value.rangeRender()
922
- }
923
- }
924
- //浮层显示时
925
- const layerShow = () => {
926
- //代码块初始化展示设置
927
- if (props.type == 'codeBlock') {
928
- const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
929
- if (pre) {
930
- languageConfig.value.displayConfig.value = pre.marks!['data-editify-hljs'] || ''
931
- }
932
- }
933
- //链接初始化展示
934
- else if (props.type == 'link') {
935
- const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
936
- if (link) {
937
- linkConfig.value.url = link.marks!['href']
938
- linkConfig.value.newOpen = link.marks!['target'] == '_blank'
939
- }
940
- }
941
- //视频初始化显示
942
- else if (props.type == 'video') {
943
- const video = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'video')
944
- if (video) {
945
- videoConfig.value.autoplay = !!video.marks!['autoplay']
946
- videoConfig.value.loop = !!video.marks!['loop']
947
- videoConfig.value.controls = !!video.marks!['controls']
948
- videoConfig.value.muted = !!video.marks!['muted']
949
- }
950
- }
951
- //文本工具条初始化显示
952
- else if (props.type == 'text') {
953
- //额外禁用判定
954
- const extraDisabled = (name: string) => {
955
- if (typeof props.config.extraDisabled == 'function') {
956
- return props.config.extraDisabled.apply(editify.proxy!, [name]) || false
957
- }
958
- return false
959
- }
960
- //显示已设置标题
961
- const findHeadingItem = headingConfig.value.displayConfig.options.find((item: string | number | ButtonOptionsItemType) => {
962
- let val: string | number | ButtonOptionsItemType = item
963
- if (DapCommon.isObject(item)) {
964
- val = (<ButtonOptionsItemType>item).value!
965
- }
966
- return dataRangeCaches.value.list.every(el => {
967
- if (el.element.isBlock()) {
968
- return el.element.parsedom == val
969
- }
970
- return el.element.getBlock().parsedom == val
971
- })
972
- })
973
- headingConfig.value.displayConfig.value = findHeadingItem ? (DapCommon.isObject(findHeadingItem) ? findHeadingItem.value : findHeadingItem) : headingConfig.value.defaultValue
974
- //标题禁用
975
- headingConfig.value.disabled = extraDisabled('heading')
976
-
977
- //对齐方式禁用
978
- alignConfig.value.disabled = extraDisabled('align')
979
-
980
- //有序列表按钮激活
981
- orderListConfig.value.active = isRangeInList(editor.value, dataRangeCaches.value, true)
982
- //有序列表按钮禁用
983
- orderListConfig.value.disabled = extraDisabled('orderList')
984
-
985
- //无序列表按钮激活
986
- unorderListConfig.value.active = isRangeInList(editor.value, dataRangeCaches.value, false)
987
- //无序列表按钮禁用
988
- unorderListConfig.value.disabled = extraDisabled('unorderList')
989
-
990
- //任务列表按钮激活
991
- taskConfig.value.active = isRangeInTask(editor.value, dataRangeCaches.value)
992
- //任务列表按钮禁用
993
- taskConfig.value.disabled = extraDisabled('task')
994
-
995
- //粗体按钮激活
996
- boldConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'font-weight', 'bold') || queryTextStyle(editor.value, dataRangeCaches.value, 'font-weight', '700')
997
- //粗体按钮禁用
998
- boldConfig.value.disabled = extraDisabled('bold')
999
-
1000
- //斜体按钮激活
1001
- italicConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'font-style', 'italic')
1002
- //斜体按钮禁用
1003
- italicConfig.value.disabled = extraDisabled('italic')
1004
-
1005
- //删除线按钮激活
1006
- strikethroughConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration', 'line-through') || queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration-line', 'line-through')
1007
- //删除线按钮禁用
1008
- strikethroughConfig.value.disabled = extraDisabled('strikethrough')
1009
-
1010
- //下划线按钮激活
1011
- underlineConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration', 'underline') || queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration-line', 'underline')
1012
- //下划线按钮禁用
1013
- underlineConfig.value.disabled = extraDisabled('underline')
1014
-
1015
- //行内代码按钮激活
1016
- codeConfig.value.active = queryTextMark(editor.value, dataRangeCaches.value, 'data-editify-code')
1017
- //行内代码按钮禁用
1018
- codeConfig.value.disabled = extraDisabled('code')
1019
-
1020
- //上标按钮激活
1021
- superConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'vertical-align', 'super')
1022
- //上标按钮禁用
1023
- superConfig.value.disabled = extraDisabled('super')
1024
-
1025
- //下标按钮激活
1026
- subConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'vertical-align', 'sub')
1027
- //下标按钮禁用
1028
- subConfig.value.disabled = extraDisabled('sub')
1029
-
1030
- //显示已选择字号
1031
- const findFontItem = fontSizeConfig.value.displayConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1032
- if (DapCommon.isObject(item)) {
1033
- return queryTextStyle(editor.value, dataRangeCaches.value, 'font-size', (<ButtonOptionsItemType>item).value)
1034
- }
1035
- return queryTextStyle(editor.value, dataRangeCaches.value, 'font-size', <string | number>item)
1036
- })
1037
- fontSizeConfig.value.displayConfig.value = findFontItem ? (DapCommon.isObject(findFontItem) ? findFontItem.value : findFontItem) : fontSizeConfig.value.defaultValue
1038
- //字号按钮禁用
1039
- fontSizeConfig.value.disabled = extraDisabled('fontSize')
1040
-
1041
- //显示已选择字体
1042
- const findFamilyItem = fontFamilyConfig.value.displayConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1043
- if (DapCommon.isObject(item)) {
1044
- return queryTextStyle(editor.value, dataRangeCaches.value, 'font-family', (<ButtonOptionsItemType>item).value)
1045
- }
1046
- return queryTextStyle(editor.value, dataRangeCaches.value, 'font-family', <string | number>item)
1047
- })
1048
- fontFamilyConfig.value.displayConfig.value = findFamilyItem ? (DapCommon.isObject(findFamilyItem) ? findFamilyItem.value : findFamilyItem) : fontFamilyConfig.value.defaultValue
1049
- //字体按钮禁用
1050
- fontFamilyConfig.value.disabled = extraDisabled('fontFamily')
1051
-
1052
- //显示已设置行高
1053
- const findHeightItem = lineHeightConfig.value.displayConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1054
- let val: string | number | ButtonOptionsItemType = item
1055
- if (DapCommon.isObject(item)) {
1056
- val = (<ButtonOptionsItemType>item).value!
1057
- }
1058
- return dataRangeCaches.value.list.every(el => {
1059
- if (el.element.isBlock() || el.element.isInblock()) {
1060
- return el.element.hasStyles() && el.element.styles!['line-height'] == val
1061
- }
1062
- const block = el.element.getBlock()
1063
- const inblock = el.element.getInblock()
1064
- if (inblock) {
1065
- return inblock.hasStyles() && inblock.styles!['line-height'] == val
1066
- }
1067
- return block.hasStyles() && block.styles!['line-height'] == val
1068
- })
1069
- })
1070
- lineHeightConfig.value.displayConfig.value = findHeightItem ? (DapCommon.isObject(findHeightItem) ? findHeightItem.value : findHeightItem) : lineHeightConfig.value.defaultValue
1071
- //行高按钮禁用
1072
- lineHeightConfig.value.disabled = extraDisabled('lineHeight')
1073
-
1074
- //显示已选择的前景色
1075
- const findForeColorItem = foreColorConfig.value.selectConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1076
- if (DapCommon.isObject(item)) {
1077
- return queryTextStyle(editor.value, dataRangeCaches.value, 'color', (<ButtonOptionsItemType>item).value)
1078
- }
1079
- return queryTextStyle(editor.value, dataRangeCaches.value, 'color', <string | number>item)
1080
- })
1081
- foreColorConfig.value.value = findForeColorItem ? (DapCommon.isObject(findForeColorItem) ? findForeColorItem.value : findForeColorItem) : ''
1082
- //前景色按钮禁用
1083
- foreColorConfig.value.disabled = extraDisabled('foreColor')
1084
-
1085
- //显示已选择的背景色
1086
- const findBackColorItem = backColorConfig.value.selectConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1087
- if (DapCommon.isObject(item)) {
1088
- return queryTextStyle(editor.value, dataRangeCaches.value, 'background-color', (<ButtonOptionsItemType>item).value)
1089
- }
1090
- return queryTextStyle(editor.value, dataRangeCaches.value, 'background-color', <string | number>item)
1091
- })
1092
- backColorConfig.value.value = findBackColorItem ? (DapCommon.isObject(findBackColorItem) ? findBackColorItem.value : findBackColorItem) : ''
1093
- //背景色按钮禁用
1094
- backColorConfig.value.disabled = extraDisabled('backColor')
1095
-
1096
- //清除格式按钮禁用
1097
- formatClearConfig.value.disabled = extraDisabled('formatClear')
1098
- }
1099
- }
1100
- </script>
1101
- <style scoped src="./toolbar.less"></style>
1
+ <template>
2
+ <Layer v-model="show" ref="layerRef" :node="node" border placement="bottom-start" @show="layerShow" :useRange="type == 'text'" :z-index="10">
3
+ <div class="editify-toolbar" ref="toolbarRef" :style="config.style">
4
+ <!-- 链接工具条 -->
5
+ <template v-if="type == 'link'">
6
+ <div class="editify-toolbar-link">
7
+ <div class="editify-toolbar-link-label">{{ $editTrans('linkAddress') }}</div>
8
+ <input @change="modifyLink" @focus="handleInputFocus" @blur="handleInputBlur" :placeholder="$editTrans('linkUrlEnterPlaceholder')" v-model.trim="linkConfig.url" type="url" />
9
+ <div class="editify-toolbar-link-footer">
10
+ <Checkbox @change="modifyLink" v-model="linkConfig.newOpen" :label="$editTrans('newWindowOpen')" :color="color" :size="10"></Checkbox>
11
+ <div class="editify-toolbar-link-operations">
12
+ <span @click="removeLink">{{ $editTrans('removeLink') }}</span>
13
+ <a :href="linkConfig.url" target="_blank" :style="{ color: color }">{{ $editTrans('viewLink') }}</a>
14
+ </div>
15
+ </div>
16
+ </div>
17
+ </template>
18
+ <!-- 图片工具条 -->
19
+ <template v-else-if="type == 'image'">
20
+ <!-- 设置宽度30% -->
21
+ <Button @operate="setWidth('30%')" name="set30Width" :title="$editTrans('width30')" :tooltip="config.tooltip" :color="color"> 30% </Button>
22
+ <!-- 设置宽度50% -->
23
+ <Button @operate="setWidth('50%')" name="set50Width" :title="$editTrans('width50')" :tooltip="config.tooltip" :color="color"> 50% </Button>
24
+ <!-- 设置宽度100% -->
25
+ <Button rightBorder @operate="setWidth('100%')" name="set100Width" :title="$editTrans('width100')" :tooltip="config.tooltip" :color="color"> 100% </Button>
26
+ <!-- 设置宽度auto -->
27
+ <Button @operate="setWidth('auto')" name="setAutoWidth" :title="$editTrans('auto')" :tooltip="config.tooltip" :color="color">
28
+ <Icon value="auto-width"></Icon>
29
+ </Button>
30
+ <!-- 删除图片 -->
31
+ <Button @operate="deleteElement('img')" name="deleteImage" :title="$editTrans('deleteImage')" :tooltip="config.tooltip" :color="color">
32
+ <Icon value="delete"></Icon>
33
+ </Button>
34
+ </template>
35
+ <!-- 视频工具条 -->
36
+ <template v-else-if="type == 'video'">
37
+ <!-- 设置宽度30% -->
38
+ <Button @operate="setWidth('30%')" name="set30Width" :title="$editTrans('width30')" :tooltip="config.tooltip" :color="color"> 30% </Button>
39
+ <!-- 设置宽度50% -->
40
+ <Button @operate="setWidth('50%')" name="set50Width" :title="$editTrans('width50')" :tooltip="config.tooltip" :color="color"> 50% </Button>
41
+ <!-- 设置宽度100% -->
42
+ <Button @operate="setWidth('100%')" name="set100Width" :title="$editTrans('width100')" :tooltip="config.tooltip" :color="color"> 100% </Button>
43
+ <!-- 设置宽度auto -->
44
+ <Button rightBorder @operate="setWidth('auto')" name="setAutoWidth" :title="$editTrans('auto')" :tooltip="config.tooltip" :color="color">
45
+ <Icon value="auto-width"></Icon>
46
+ </Button>
47
+ <!-- 自动播放 -->
48
+ <Button @operate="setVideo" name="autoplay" :title="videoConfig.autoplay ? $editTrans('disabledAutoplay') : $editTrans('autoplay')" :tooltip="config.tooltip" :color="color">
49
+ <Icon :value="videoConfig.autoplay ? 'autoplay' : 'stop'"></Icon>
50
+ </Button>
51
+ <!-- 循环播放 -->
52
+ <Button @operate="setVideo" name="loop" :title="videoConfig.loop ? $editTrans('disabledLoop') : $editTrans('loop')" :tooltip="config.tooltip" :color="color">
53
+ <Icon :value="videoConfig.loop ? 'loop' : 'single'"></Icon>
54
+ </Button>
55
+ <!-- 是否静音 -->
56
+ <Button @operate="setVideo" name="muted" :title="videoConfig.muted ? $editTrans('unmuted') : $editTrans('muted')" :tooltip="config.tooltip" :color="color">
57
+ <Icon :value="videoConfig.muted ? 'muted' : 'unmuted'"></Icon>
58
+ </Button>
59
+ <!-- 是否显示控制器 -->
60
+ <Button leftBorder @operate="setVideo" name="controls" :title="$editTrans('controls')" :tooltip="config.tooltip" :color="color">
61
+ <Icon value="controls"></Icon>
62
+ </Button>
63
+ <!-- 删除视频 -->
64
+ <Button @operate="deleteElement('video')" name="deleteVideo" :title="$editTrans('deleteVideo')" :tooltip="config.tooltip" :color="color">
65
+ <Icon value="delete"></Icon>
66
+ </Button>
67
+ </template>
68
+ <!-- 表格工具条 -->
69
+ <template v-else-if="type == 'table'">
70
+ <!-- 表格前插入段落 -->
71
+ <Button @operate="insertParagraphWithTable('up')" name="textWrapUp" :title="$editTrans('textWrapUp')" :tooltip="config.tooltip" :color="color">
72
+ <Icon value="text-wrap" class="editify-icon-rotate"></Icon>
73
+ </Button>
74
+ <!-- 表格后插入段落 -->
75
+ <Button @operate="insertParagraphWithTable('down')" rightBorder name="textWrapDown" :title="$editTrans('textWrapDown')" :tooltip="config.tooltip" :color="color">
76
+ <Icon value="text-wrap"></Icon>
77
+ </Button>
78
+ <!-- 向前插入行 -->
79
+ <Button @operate="insertTableRow('up')" name="insertRowTop" :title="$editTrans('insertRowTop')" :tooltip="config.tooltip" :color="color">
80
+ <Icon value="insert-row-top"></Icon>
81
+ </Button>
82
+ <!-- 向后插入行 -->
83
+ <Button @operate="insertTableRow('down')" name="insertRowBottom" :title="$editTrans('insertRowBottom')" :tooltip="config.tooltip" :color="color">
84
+ <Icon value="insert-row-bottom"></Icon>
85
+ </Button>
86
+ <!-- 删除行 -->
87
+ <Button @operate="deleteTableRow" rightBorder name="deleteRow" :title="$editTrans('deleteRow')" :tooltip="config.tooltip" :color="color">
88
+ <Icon value="delete-row"></Icon>
89
+ </Button>
90
+ <!-- 向前插入列 -->
91
+ <Button @operate="insertTableColumn('left')" name="insertColumnLeft" :title="$editTrans('insertColumnLeft')" :tooltip="config.tooltip" :color="color">
92
+ <Icon value="insert-column-left"></Icon>
93
+ </Button>
94
+ <!-- 向后插入列 -->
95
+ <Button @operate="insertTableColumn('right')" name="insertColumnRight" :title="$editTrans('insertColumnRight')" :tooltip="config.tooltip" :color="color">
96
+ <Icon value="insert-column-right"></Icon>
97
+ </Button>
98
+ <!-- 删除列 -->
99
+ <Button @operate="deleteTableColumn" rightBorder name="deleteColumn" :title="$editTrans('deleteColumn')" :tooltip="config.tooltip" :color="color">
100
+ <Icon value="delete-column"></Icon>
101
+ </Button>
102
+ <!-- 删除表格 -->
103
+ <Button @operate="deleteElement('table')" name="deleteTable" :title="$editTrans('deleteTable')" :tooltip="config.tooltip" :color="color">
104
+ <Icon value="delete-table"></Icon>
105
+ </Button>
106
+ </template>
107
+ <!-- 代码块工具条 -->
108
+ <template v-if="type == 'codeBlock'">
109
+ <!-- 代码块前插入段落 -->
110
+ <Button @operate="insertParagraphWithPre('up')" name="textWrapUp" :title="$editTrans('textWrapUp')" :tooltip="config.tooltip" :color="color">
111
+ <Icon value="text-wrap" class="editify-icon-rotate"></Icon>
112
+ </Button>
113
+ <!-- 代码块后插入段落 -->
114
+ <Button @operate="insertParagraphWithPre('down')" name="textWrapDown" :title="$editTrans('textWrapDown')" :tooltip="config.tooltip" :color="color">
115
+ <Icon value="text-wrap"></Icon>
116
+ </Button>
117
+ <!-- 代码块语言选择 -->
118
+ <Button v-if="languageConfig.show" name="languages" type="display" :title="$editTrans('selectLanguages')" :tooltip="config.tooltip" :leftBorder="languageConfig.leftBorder" :rightBorder="languageConfig.rightBorder" :display-config="languageConfig.displayConfig" :color="color" :active="languageConfig.active" :disabled="languageConfig.disabled" @operate="selectLanguage"></Button>
119
+ </template>
120
+ <!-- 文本工具条 -->
121
+ <template v-else-if="type == 'text'">
122
+ <!-- 设置段落和标题 -->
123
+ <Button v-if="headingConfig.show" name="heading" type="display" :title="$editTrans('heading')" :tooltip="config.tooltip" :display-config="headingConfig.displayConfig" :leftBorder="headingConfig.leftBorder" :rightBorder="headingConfig.rightBorder" :color="color" :active="headingConfig.active" :disabled="headingConfig.disabled" @operate="_setHeading"></Button>
124
+ <!-- 对齐方式 -->
125
+ <Button v-if="alignConfig.show" name="align" type="select" :title="$editTrans('align')" :tooltip="config.tooltip" :select-config="alignConfig.selectConfig" :leftBorder="alignConfig.leftBorder" :rightBorder="alignConfig.rightBorder" :color="color" :active="alignConfig.active" :disabled="alignConfig.disabled" @operate="_setAlign">
126
+ <Icon value="align-left"></Icon>
127
+ </Button>
128
+ <!-- 有序列表 -->
129
+ <Button v-if="orderListConfig.show" name="orderList" :title="$editTrans('orderList')" :tooltip="config.tooltip" :leftBorder="orderListConfig.leftBorder" :rightBorder="orderListConfig.rightBorder" :color="color" :active="orderListConfig.active" :disabled="orderListConfig.disabled" @operate="_setList">
130
+ <Icon value="list-ordered"></Icon>
131
+ </Button>
132
+ <!-- 无序列表 -->
133
+ <Button v-if="unorderListConfig.show" name="unorderList" :title="$editTrans('unorderList')" :tooltip="config.tooltip" :leftBorder="unorderListConfig.leftBorder" :rightBorder="unorderListConfig.rightBorder" :color="color" :active="unorderListConfig.active" :disabled="unorderListConfig.disabled" @operate="_setList">
134
+ <Icon value="list-unordered"></Icon>
135
+ </Button>
136
+ <!-- 任务列表 -->
137
+ <Button v-if="taskConfig.show" name="task" :title="$editTrans('task')" :tooltip="config.tooltip" :leftBorder="taskConfig.leftBorder" :rightBorder="taskConfig.rightBorder" :color="color" :active="taskConfig.active" :disabled="taskConfig.disabled" @operate="_setTask">
138
+ <Icon value="task"></Icon>
139
+ </Button>
140
+ <!-- 加粗 -->
141
+ <Button v-if="boldConfig.show" name="bold" :title="$editTrans('bold')" :tooltip="config.tooltip" :leftBorder="boldConfig.leftBorder" :rightBorder="boldConfig.rightBorder" :color="color" :active="boldConfig.active" :disabled="boldConfig.disabled" @operate="setBold">
142
+ <Icon value="bold"></Icon>
143
+ </Button>
144
+ <!-- 斜体 -->
145
+ <Button v-if="italicConfig.show" name="italic" :title="$editTrans('italic')" :tooltip="config.tooltip" :leftBorder="italicConfig.leftBorder" :rightBorder="italicConfig.rightBorder" :color="color" :active="italicConfig.active" :disabled="italicConfig.disabled" @operate="setItalic">
146
+ <Icon value="italic"></Icon>
147
+ </Button>
148
+ <!-- 删除线 -->
149
+ <Button v-if="strikethroughConfig.show" name="strikethrough" :title="$editTrans('strikethrough')" :tooltip="config.tooltip" :leftBorder="strikethroughConfig.leftBorder" :rightBorder="strikethroughConfig.rightBorder" :color="color" :active="strikethroughConfig.active" :disabled="strikethroughConfig.disabled" @operate="setStrikethrough">
150
+ <Icon value="strikethrough"></Icon>
151
+ </Button>
152
+ <!-- 下划线 -->
153
+ <Button v-if="underlineConfig.show" name="underline" :title="$editTrans('underline')" :tooltip="config.tooltip" :leftBorder="underlineConfig.leftBorder" :rightBorder="underlineConfig.rightBorder" :color="color" :active="underlineConfig.active" :disabled="underlineConfig.disabled" @operate="setUnderline">
154
+ <Icon value="underline"></Icon>
155
+ </Button>
156
+ <!-- 行内代码块 -->
157
+ <Button v-if="codeConfig.show" name="code" :title="$editTrans('code')" :tooltip="config.tooltip" :leftBorder="codeConfig.leftBorder" :rightBorder="codeConfig.rightBorder" :color="color" :active="codeConfig.active" :disabled="codeConfig.disabled" @operate="setCodeStyle">
158
+ <Icon value="code"></Icon>
159
+ </Button>
160
+ <!-- 上标 -->
161
+ <Button v-if="superConfig.show" name="superscript" :title="$editTrans('superscript')" :tooltip="config.tooltip" :leftBorder="superConfig.leftBorder" :rightBorder="superConfig.rightBorder" :color="color" :active="superConfig.active" :disabled="superConfig.disabled" @operate="setSuperscript">
162
+ <Icon value="superscript"></Icon>
163
+ </Button>
164
+ <!-- 下标 -->
165
+ <Button v-if="subConfig.show" name="subscript" :title="$editTrans('subscript')" :tooltip="config.tooltip" :leftBorder="subConfig.leftBorder" :rightBorder="subConfig.rightBorder" :color="color" :active="subConfig.active" :disabled="subConfig.disabled" @operate="setSubscript">
166
+ <Icon value="subscript"></Icon>
167
+ </Button>
168
+ <!-- 字号大小 -->
169
+ <Button v-if="fontSizeConfig.show" name="fontSize" type="display" :title="$editTrans('fontSize')" :tooltip="config.tooltip" :display-config="fontSizeConfig.displayConfig" :leftBorder="fontSizeConfig.leftBorder" :rightBorder="fontSizeConfig.rightBorder" :color="color" :active="fontSizeConfig.active" :disabled="fontSizeConfig.disabled" @operate="setFontSize"></Button>
170
+ <!-- 字体 -->
171
+ <Button v-if="fontFamilyConfig.show" name="fontFamily" type="display" :title="$editTrans('fontFamily')" :tooltip="config.tooltip" :display-config="fontFamilyConfig.displayConfig" :leftBorder="fontFamilyConfig.leftBorder" :rightBorder="fontFamilyConfig.rightBorder" :color="color" :active="fontFamilyConfig.active" :disabled="fontFamilyConfig.disabled" @operate="setFontFamily"></Button>
172
+ <!-- 行高 -->
173
+ <Button v-if="lineHeightConfig.show" name="lineHeight" type="display" :title="$editTrans('lineHeight')" :tooltip="config.tooltip" :display-config="lineHeightConfig.displayConfig" :leftBorder="lineHeightConfig.leftBorder" :rightBorder="lineHeightConfig.rightBorder" :color="color" :active="lineHeightConfig.active" :disabled="lineHeightConfig.disabled" @operate="_setLineHeight"></Button>
174
+ <!-- 前景色 -->
175
+ <Button v-if="foreColorConfig.show" name="foreColor" type="select" :title="$editTrans('foreColor')" :tooltip="config.tooltip" :select-config="foreColorConfig.selectConfig" :leftBorder="foreColorConfig.leftBorder" :rightBorder="foreColorConfig.rightBorder" :color="color" :active="foreColorConfig.active" :disabled="foreColorConfig.disabled" hideScroll ref="foreColorRef">
176
+ <Icon value="font-color"></Icon>
177
+ <template #layer="{ options }">
178
+ <Colors :tooltip="config.tooltip" :color="color" :value="foreColorConfig.value" @change="setForeColor" :data="options"></Colors>
179
+ </template>
180
+ </Button>
181
+ <!-- 背景色 -->
182
+ <Button v-if="backColorConfig.show" name="backColor" type="select" :title="$editTrans('backColor')" :tooltip="config.tooltip" :select-config="backColorConfig.selectConfig" :leftBorder="backColorConfig.leftBorder" :rightBorder="backColorConfig.rightBorder" :color="color" :active="backColorConfig.active" :disabled="backColorConfig.disabled" hideScroll ref="backColorRef">
183
+ <Icon value="brush"></Icon>
184
+ <template #layer="{ options }">
185
+ <Colors :tooltip="config.tooltip" :color="color" :value="backColorConfig.value" @change="setBackColor" :data="options"></Colors>
186
+ </template>
187
+ </Button>
188
+ <!-- 清除样式 -->
189
+ <Button v-if="formatClearConfig.show" name="formatClear" :title="$editTrans('formatClear')" :tooltip="config.tooltip" :leftBorder="formatClearConfig.leftBorder" :rightBorder="formatClearConfig.rightBorder" :color="color" :active="formatClearConfig.active" :disabled="formatClearConfig.disabled" @operate="clearFormat">
190
+ <Icon value="format-clear"></Icon>
191
+ </Button>
192
+ </template>
193
+ </div>
194
+ </Layer>
195
+ </template>
196
+ <script setup lang="ts">
197
+ import Layer from '../layer/layer.vue'
198
+ import Button from '../button/button.vue'
199
+ import Icon from '../icon/icon.vue'
200
+ import Checkbox from '../checkbox/checkbox.vue'
201
+ import Colors from '../colors/colors.vue'
202
+ import { AlexEditor, AlexElement, AlexElementsRangeType } from 'alex-editor'
203
+ import { common as DapCommon } from 'dap-util'
204
+ import { getCurrentParsedomElement, removeTextStyle, removeTextMark, setTextStyle, setLineHeight, setTextMark, setList, setTask, setHeading, setAlign, isRangeInList, isRangeInTask, queryTextStyle, queryTextMark } from '../../core/function'
205
+ import { ToolbarProps } from './props'
206
+ import { ComponentInternalInstance, Ref, computed, inject, ref } from 'vue'
207
+ import { ObjectType } from '../../core/tool'
208
+ import { ButtonOptionsItemType } from '../button/props'
209
+
210
+ defineOptions({
211
+ name: 'Toolbar'
212
+ })
213
+ const props = defineProps(ToolbarProps)
214
+ const emits = defineEmits(['update:modelValue'])
215
+
216
+ const editify = inject<ComponentInternalInstance>('editify')!
217
+ const editor = inject<Ref<AlexEditor>>('editor')!
218
+ const dataRangeCaches = inject<Ref<AlexElementsRangeType>>('dataRangeCaches')!
219
+ const $editTrans = inject<(key: string) => any>('$editTrans')!
220
+
221
+ const layerRef = ref<InstanceType<typeof Layer> | null>(null)
222
+ const toolbarRef = ref<HTMLElement | null>(null)
223
+ const foreColorRef = ref<InstanceType<typeof Button> | null>(null)
224
+ const backColorRef = ref<InstanceType<typeof Button> | null>(null)
225
+
226
+ //链接参数配置
227
+ const linkConfig = ref<ObjectType>({
228
+ //链接地址
229
+ url: '',
230
+ //链接是否新窗口打开
231
+ newOpen: false
232
+ })
233
+ //视频参数配置
234
+ const videoConfig = ref<ObjectType>({
235
+ //是否显示控制器
236
+ controls: false,
237
+ //是否循环
238
+ loop: false,
239
+ //是否自动播放
240
+ autoplay: false,
241
+ //是否静音
242
+ muted: false
243
+ })
244
+ //代码块选择语言按钮配置
245
+ const languageConfig = ref<ObjectType>({
246
+ show: props.config.codeBlock!.languages!.show,
247
+ displayConfig: {
248
+ options: props.config.codeBlock!.languages!.options,
249
+ value: '',
250
+ width: props.config.codeBlock!.languages!.width,
251
+ maxHeight: props.config.codeBlock!.languages!.maxHeight
252
+ },
253
+ leftBorder: props.config.codeBlock!.languages!.leftBorder,
254
+ rightBorder: props.config.codeBlock!.languages!.rightBorder,
255
+ active: false,
256
+ disabled: false
257
+ })
258
+ //标题按钮配置
259
+ const headingConfig = ref<ObjectType>({
260
+ show: props.config.text!.heading!.show,
261
+ displayConfig: {
262
+ options: props.config.text!.heading!.options,
263
+ value: '',
264
+ width: props.config.text!.heading!.width,
265
+ maxHeight: props.config.text!.heading!.maxHeight
266
+ },
267
+ defaultValue: props.config.text!.heading!.defaultValue,
268
+ leftBorder: props.config.text!.heading!.leftBorder,
269
+ rightBorder: props.config.text!.heading!.rightBorder,
270
+ active: false,
271
+ disabled: false
272
+ })
273
+ //对齐方式按钮配置
274
+ const alignConfig = ref<ObjectType>({
275
+ show: props.config.text!.align!.show,
276
+ selectConfig: {
277
+ options: props.config.text!.align!.options,
278
+ width: props.config.text!.align!.width,
279
+ maxHeight: props.config.text!.align!.maxHeight
280
+ },
281
+ leftBorder: props.config.text!.align!.leftBorder,
282
+ rightBorder: props.config.text!.align!.rightBorder,
283
+ active: false,
284
+ disabled: false
285
+ })
286
+ //有序列表按钮配置
287
+ const orderListConfig = ref<ObjectType>({
288
+ show: props.config.text!.orderList!.show,
289
+ leftBorder: props.config.text!.orderList!.leftBorder,
290
+ rightBorder: props.config.text!.orderList!.rightBorder,
291
+ active: false,
292
+ disabled: false
293
+ })
294
+ //无序列表按钮配置
295
+ const unorderListConfig = ref<ObjectType>({
296
+ show: props.config.text!.unorderList!.show,
297
+ leftBorder: props.config.text!.unorderList!.leftBorder,
298
+ rightBorder: props.config.text!.unorderList!.rightBorder,
299
+ active: false,
300
+ disabled: false
301
+ })
302
+ //任务列表按钮配置
303
+ const taskConfig = ref<ObjectType>({
304
+ show: props.config.text!.task!.show,
305
+ leftBorder: props.config.text!.task!.leftBorder,
306
+ rightBorder: props.config.text!.task!.rightBorder,
307
+ active: false,
308
+ disabled: false
309
+ })
310
+ //粗体按钮配置
311
+ const boldConfig = ref<ObjectType>({
312
+ show: props.config.text!.bold!.show,
313
+ leftBorder: props.config.text!.bold!.leftBorder,
314
+ rightBorder: props.config.text!.bold!.rightBorder,
315
+ active: false,
316
+ disabled: false
317
+ })
318
+ //斜体按钮配置
319
+ const italicConfig = ref<ObjectType>({
320
+ show: props.config.text!.italic!.show,
321
+ leftBorder: props.config.text!.italic!.leftBorder,
322
+ rightBorder: props.config.text!.italic!.rightBorder,
323
+ active: false,
324
+ disabled: false
325
+ })
326
+ //删除线按钮配置
327
+ const strikethroughConfig = ref<ObjectType>({
328
+ show: props.config.text!.strikethrough!.show,
329
+ leftBorder: props.config.text!.strikethrough!.leftBorder,
330
+ rightBorder: props.config.text!.strikethrough!.rightBorder,
331
+ active: false,
332
+ disabled: false
333
+ })
334
+ //下划线按钮配置
335
+ const underlineConfig = ref<ObjectType>({
336
+ show: props.config.text!.underline!.show,
337
+ leftBorder: props.config.text!.underline!.leftBorder,
338
+ rightBorder: props.config.text!.underline!.rightBorder,
339
+ active: false,
340
+ disabled: false
341
+ })
342
+ //行内代码块按钮配置
343
+ const codeConfig = ref<ObjectType>({
344
+ show: props.config.text!.code!.show,
345
+ leftBorder: props.config.text!.code!.leftBorder,
346
+ rightBorder: props.config.text!.code!.rightBorder,
347
+ active: false,
348
+ disabled: false
349
+ })
350
+ //上标按钮配置
351
+ const superConfig = ref<ObjectType>({
352
+ show: props.config.text!.super!.show,
353
+ leftBorder: props.config.text!.super!.leftBorder,
354
+ rightBorder: props.config.text!.super!.rightBorder,
355
+ active: false,
356
+ disabled: false
357
+ })
358
+ //下标按钮配置
359
+ const subConfig = ref<ObjectType>({
360
+ show: props.config.text!.sub!.show,
361
+ leftBorder: props.config.text!.sub!.leftBorder,
362
+ rightBorder: props.config.text!.sub!.rightBorder,
363
+ active: false,
364
+ disabled: false
365
+ })
366
+ //字号按钮配置
367
+ const fontSizeConfig = ref<ObjectType>({
368
+ show: props.config.text!.fontSize!.show,
369
+ displayConfig: {
370
+ options: props.config.text!.fontSize!.options,
371
+ value: '',
372
+ width: props.config.text!.fontSize!.width,
373
+ maxHeight: props.config.text!.fontSize!.maxHeight
374
+ },
375
+ defaultValue: props.config.text!.fontSize!.defaultValue,
376
+ leftBorder: props.config.text!.fontSize!.leftBorder,
377
+ rightBorder: props.config.text!.fontSize!.rightBorder,
378
+ active: false,
379
+ disabled: false
380
+ })
381
+ //字体按钮配置
382
+ const fontFamilyConfig = ref<ObjectType>({
383
+ show: props.config.text!.fontFamily!.show,
384
+ displayConfig: {
385
+ options: props.config.text!.fontFamily!.options,
386
+ value: '',
387
+ width: props.config.text!.fontFamily!.width,
388
+ maxHeight: props.config.text!.fontFamily!.maxHeight
389
+ },
390
+ defaultValue: props.config.text!.fontFamily!.defaultValue,
391
+ leftBorder: props.config.text!.fontFamily!.leftBorder,
392
+ rightBorder: props.config.text!.fontFamily!.rightBorder,
393
+ active: false,
394
+ disabled: false
395
+ })
396
+ //行高按钮配置
397
+ const lineHeightConfig = ref<ObjectType>({
398
+ show: props.config.text!.lineHeight!.show,
399
+ displayConfig: {
400
+ options: props.config.text!.lineHeight!.options,
401
+ value: '',
402
+ width: props.config.text!.lineHeight!.width,
403
+ maxHeight: props.config.text!.lineHeight!.maxHeight
404
+ },
405
+ defaultValue: props.config.text!.lineHeight!.defaultValue,
406
+ leftBorder: props.config.text!.lineHeight!.leftBorder,
407
+ rightBorder: props.config.text!.lineHeight!.rightBorder,
408
+ active: false,
409
+ disabled: false
410
+ })
411
+ //前景颜色按钮配置
412
+ const foreColorConfig = ref<ObjectType>({
413
+ show: props.config.text!.foreColor!.show,
414
+ selectConfig: {
415
+ options: props.config.text!.foreColor!.options
416
+ },
417
+ leftBorder: props.config.text!.foreColor!.leftBorder,
418
+ rightBorder: props.config.text!.foreColor!.rightBorder,
419
+ value: '', //选择的颜色值
420
+ active: false,
421
+ disabled: false
422
+ })
423
+ //背景颜色按钮配置
424
+ const backColorConfig = ref<ObjectType>({
425
+ show: props.config.text!.backColor!.show,
426
+ selectConfig: {
427
+ options: props.config.text!.backColor!.options
428
+ },
429
+ leftBorder: props.config.text!.backColor!.leftBorder,
430
+ rightBorder: props.config.text!.backColor!.rightBorder,
431
+ value: '', //选择的颜色值
432
+ active: false,
433
+ disabled: false
434
+ })
435
+ //清除格式按钮配置
436
+ const formatClearConfig = ref<ObjectType>({
437
+ show: props.config.text!.formatClear!.show,
438
+ leftBorder: props.config.text!.formatClear!.leftBorder,
439
+ rightBorder: props.config.text!.formatClear!.rightBorder,
440
+ active: false,
441
+ disabled: false
442
+ })
443
+
444
+ //是否显示
445
+ const show = computed<boolean>({
446
+ get() {
447
+ return props.modelValue
448
+ },
449
+ set(val) {
450
+ emits('update:modelValue', val)
451
+ }
452
+ })
453
+
454
+ //输入框获取焦点
455
+ const handleInputFocus = (e: Event) => {
456
+ if (props.color) {
457
+ ;(<HTMLInputElement>e.currentTarget).style.borderColor = props.color
458
+ }
459
+ }
460
+ //输入框失去焦点
461
+ const handleInputBlur = (e: Event) => {
462
+ ;(<HTMLInputElement>e.currentTarget).style.borderColor = ''
463
+ }
464
+ //清除格式
465
+ const clearFormat = () => {
466
+ removeTextStyle(editor.value, dataRangeCaches.value)
467
+ removeTextMark(editor.value, dataRangeCaches.value)
468
+ editor.value.formatElementStack()
469
+ editor.value.domRender()
470
+ editor.value.rangeRender()
471
+ }
472
+ //设置背景色
473
+ const setBackColor = (value: string) => {
474
+ setTextStyle(editor.value, dataRangeCaches.value, {
475
+ 'background-color': value
476
+ })
477
+ backColorRef.value!.show = false
478
+ editor.value.formatElementStack()
479
+ editor.value.domRender()
480
+ editor.value.rangeRender()
481
+ }
482
+ //设置前景色
483
+ const setForeColor = (value: string) => {
484
+ setTextStyle(editor.value, dataRangeCaches.value, {
485
+ color: value
486
+ })
487
+ foreColorRef.value!.show = false
488
+ editor.value.formatElementStack()
489
+ editor.value.domRender()
490
+ editor.value.rangeRender()
491
+ }
492
+ //设置行高
493
+ const _setLineHeight = (_name: string, value: string | number) => {
494
+ setLineHeight(editor.value, dataRangeCaches.value, value)
495
+ editor.value.formatElementStack()
496
+ editor.value.domRender()
497
+ editor.value.rangeRender()
498
+ }
499
+ //设置字体
500
+ const setFontFamily = (_name: string, value: string | number) => {
501
+ setTextStyle(editor.value, dataRangeCaches.value, {
502
+ 'font-family': value
503
+ })
504
+ editor.value.formatElementStack()
505
+ editor.value.domRender()
506
+ editor.value.rangeRender()
507
+ }
508
+ //设置字号
509
+ const setFontSize = (_name: string, value: string | number) => {
510
+ setTextStyle(editor.value, dataRangeCaches.value, {
511
+ 'font-size': value
512
+ })
513
+ editor.value.formatElementStack()
514
+ editor.value.domRender()
515
+ editor.value.rangeRender()
516
+ }
517
+ //设置上标
518
+ const setSuperscript = () => {
519
+ if (queryTextStyle(editor.value, dataRangeCaches.value, 'vertical-align', 'super')) {
520
+ removeTextStyle(editor.value, dataRangeCaches.value, ['vertical-align'])
521
+ } else {
522
+ setTextStyle(editor.value, dataRangeCaches.value, {
523
+ 'vertical-align': 'super'
524
+ })
525
+ }
526
+ editor.value.formatElementStack()
527
+ editor.value.domRender()
528
+ editor.value.rangeRender()
529
+ }
530
+ //设置下标
531
+ const setSubscript = () => {
532
+ if (queryTextStyle(editor.value, dataRangeCaches.value, 'vertical-align', 'sub')) {
533
+ removeTextStyle(editor.value, dataRangeCaches.value, ['vertical-align'])
534
+ } else {
535
+ setTextStyle(editor.value, dataRangeCaches.value, {
536
+ 'vertical-align': 'sub'
537
+ })
538
+ }
539
+ editor.value.formatElementStack()
540
+ editor.value.domRender()
541
+ editor.value.rangeRender()
542
+ }
543
+ //设置行内代码样式
544
+ const setCodeStyle = () => {
545
+ if (queryTextMark(editor.value, dataRangeCaches.value, 'data-editify-code')) {
546
+ removeTextMark(editor.value, dataRangeCaches.value, ['data-editify-code'])
547
+ } else {
548
+ setTextMark(editor.value, dataRangeCaches.value, {
549
+ 'data-editify-code': true
550
+ })
551
+ }
552
+ editor.value.formatElementStack()
553
+ editor.value.domRender()
554
+ editor.value.rangeRender()
555
+ }
556
+ //设置下划线
557
+ const setUnderline = () => {
558
+ if (queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration', 'underline') || queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration-line', 'underline')) {
559
+ removeTextStyle(editor.value, dataRangeCaches.value, ['text-decoration', 'text-decoration-line'])
560
+ } else {
561
+ setTextStyle(editor.value, dataRangeCaches.value, {
562
+ 'text-decoration': 'underline'
563
+ })
564
+ }
565
+ editor.value.formatElementStack()
566
+ editor.value.domRender()
567
+ editor.value.rangeRender()
568
+ }
569
+ //设置删除线
570
+ const setStrikethrough = () => {
571
+ if (queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration', 'line-through') || queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration-line', 'line-through')) {
572
+ removeTextStyle(editor.value, dataRangeCaches.value, ['text-decoration', 'text-decoration-line'])
573
+ } else {
574
+ setTextStyle(editor.value, dataRangeCaches.value, {
575
+ 'text-decoration': 'line-through'
576
+ })
577
+ }
578
+ editor.value.formatElementStack()
579
+ editor.value.domRender()
580
+ editor.value.rangeRender()
581
+ }
582
+ //设置列表
583
+ const _setList = (name: string) => {
584
+ setList(editor.value, dataRangeCaches.value, name == 'orderList')
585
+ editor.value.formatElementStack()
586
+ editor.value.domRender()
587
+ editor.value.rangeRender()
588
+ }
589
+ //设置任务列表
590
+ const _setTask = () => {
591
+ setTask(editor.value, dataRangeCaches.value)
592
+ editor.value.formatElementStack()
593
+ editor.value.domRender()
594
+ editor.value.rangeRender()
595
+ }
596
+ //斜体
597
+ const setItalic = () => {
598
+ if (queryTextStyle(editor.value, dataRangeCaches.value, 'font-style', 'italic')) {
599
+ removeTextStyle(editor.value, dataRangeCaches.value, ['font-style'])
600
+ } else {
601
+ setTextStyle(editor.value, dataRangeCaches.value, {
602
+ 'font-style': 'italic'
603
+ })
604
+ }
605
+ editor.value.formatElementStack()
606
+ editor.value.domRender()
607
+ editor.value.rangeRender()
608
+ }
609
+ //加粗
610
+ const setBold = () => {
611
+ if (queryTextStyle(editor.value, dataRangeCaches.value, 'font-weight', 'bold') || queryTextStyle(editor.value, dataRangeCaches.value, 'font-weight', '700')) {
612
+ removeTextStyle(editor.value, dataRangeCaches.value, ['font-weight'])
613
+ } else {
614
+ setTextStyle(editor.value, dataRangeCaches.value, {
615
+ 'font-weight': 'bold'
616
+ })
617
+ }
618
+ editor.value.formatElementStack()
619
+ editor.value.domRender()
620
+ editor.value.rangeRender()
621
+ }
622
+ //设置标题
623
+ const _setHeading = (_name: string, value: string) => {
624
+ setHeading(editor.value, dataRangeCaches.value, $editTrans, value)
625
+ editor.value.formatElementStack()
626
+ editor.value.domRender()
627
+ editor.value.rangeRender()
628
+ }
629
+ //设置对齐方式
630
+ const _setAlign = (_name: string, value: string) => {
631
+ setAlign(editor.value, dataRangeCaches.value, value)
632
+ editor.value.formatElementStack()
633
+ editor.value.domRender()
634
+ editor.value.rangeRender()
635
+ }
636
+ //设置视频属性
637
+ const setVideo = (prop: string) => {
638
+ const element = editor.value.range!.anchor.element
639
+ //当前是拥有该属性
640
+ if (videoConfig.value[prop]) {
641
+ delete element.marks![prop]
642
+ }
643
+ //当前无该属性
644
+ else {
645
+ element.marks![prop] = true
646
+ }
647
+ videoConfig.value[prop] = !videoConfig.value[prop]
648
+ editor.value.formatElementStack()
649
+ editor.value.domRender()
650
+ editor.value.rangeRender()
651
+ }
652
+ //设置图片或者视频宽度
653
+ const setWidth = (value: string) => {
654
+ const element = editor.value.range!.anchor.element
655
+ if (element) {
656
+ const styles = {
657
+ width: value
658
+ }
659
+ if (element.hasStyles()) {
660
+ element.styles = Object.assign(element.styles!, styles)
661
+ } else {
662
+ element.styles = styles
663
+ }
664
+ editor.value.formatElementStack()
665
+ editor.value.domRender()
666
+ editor.value.rangeRender()
667
+ //更新工具条位置
668
+ setTimeout(() => {
669
+ layerRef.value!.setPosition()
670
+ }, 0)
671
+ }
672
+ }
673
+ //修改链接
674
+ const modifyLink = () => {
675
+ if (!linkConfig.value.url) {
676
+ return
677
+ }
678
+ const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
679
+ if (link) {
680
+ link.marks!.href = linkConfig.value.url
681
+ if (linkConfig.value.newOpen) {
682
+ link.marks!.target = '_blank'
683
+ } else {
684
+ delete link.marks!.target
685
+ }
686
+ }
687
+ editor.value.formatElementStack()
688
+ editor.value.domRender()
689
+ }
690
+ //移除链接
691
+ const removeLink = () => {
692
+ const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
693
+ if (link) {
694
+ link.parsedom = AlexElement.TEXT_NODE
695
+ delete link.marks!['target']
696
+ delete link.marks!['href']
697
+ delete link.marks!['data-editify-element']
698
+ }
699
+ editor.value.formatElementStack()
700
+ editor.value.domRender()
701
+ editor.value.rangeRender()
702
+ }
703
+ //选择代码语言
704
+ const selectLanguage = (_name: string, value: string) => {
705
+ const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
706
+ if (pre) {
707
+ Object.assign(pre.marks!, {
708
+ 'data-editify-hljs': value
709
+ })
710
+ editor.value.formatElementStack()
711
+ editor.value.domRender()
712
+ editor.value.rangeRender()
713
+ }
714
+ }
715
+ //代码块前后插入段落
716
+ const insertParagraphWithPre = (type: string | undefined = 'up') => {
717
+ if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
718
+ editor.value.range!.anchor.element = editor.value.range!.focus.element
719
+ editor.value.range!.anchor.offset = editor.value.range!.focus.offset
720
+ }
721
+ const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
722
+ if (pre) {
723
+ const paragraph = new AlexElement('block', AlexElement.BLOCK_NODE, null, null, null)
724
+ const breakEl = new AlexElement('closed', 'br', null, null, null)
725
+ editor.value.addElementTo(breakEl, paragraph)
726
+ if (type == 'up') {
727
+ editor.value.addElementBefore(paragraph, pre)
728
+ } else {
729
+ editor.value.addElementAfter(paragraph, pre)
730
+ }
731
+ editor.value.range!.anchor.moveToEnd(paragraph)
732
+ editor.value.range!.focus.moveToEnd(paragraph)
733
+ editor.value.formatElementStack()
734
+ editor.value.domRender()
735
+ editor.value.rangeRender()
736
+ }
737
+ }
738
+ //表格前后插入列
739
+ const insertTableColumn = (type: string | undefined = 'left') => {
740
+ if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
741
+ editor.value.range!.anchor.element = editor.value.range!.focus.element
742
+ editor.value.range!.anchor.offset = editor.value.range!.focus.offset
743
+ }
744
+ const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
745
+ const column = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'td')
746
+ const tbody = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tbody')
747
+ if (column && table && tbody) {
748
+ const rows = tbody.children
749
+ const index = column.parent!.children!.findIndex(item => {
750
+ return item.isEqual(column)
751
+ })
752
+ //插入列
753
+ rows!.forEach(row => {
754
+ const newColumn = column.clone(false)
755
+ const breakEl = new AlexElement('closed', 'br', null, null, null)
756
+ editor.value.addElementTo(breakEl, newColumn)
757
+ if (type == 'left') {
758
+ editor.value.addElementTo(newColumn, row, index)
759
+ } else {
760
+ editor.value.addElementTo(newColumn, row, index + 1)
761
+ }
762
+ })
763
+ //插入col
764
+ const colgroup = table.children!.find(item => {
765
+ return item.parsedom == 'colgroup'
766
+ })!
767
+ const col = new AlexElement('closed', 'col', null, null, null)
768
+ if (type == 'left') {
769
+ editor.value.addElementTo(col, colgroup, index)
770
+ } else {
771
+ editor.value.addElementTo(col, colgroup, index + 1)
772
+ }
773
+ //渲染
774
+ editor.value.formatElementStack()
775
+ if (type == 'left') {
776
+ const previousColumn = editor.value.getPreviousElement(column)!
777
+ editor.value.range!.anchor.moveToStart(previousColumn)
778
+ editor.value.range!.focus.moveToStart(previousColumn)
779
+ } else {
780
+ const nextColumn = editor.value.getNextElement(column)!
781
+ editor.value.range!.anchor.moveToStart(nextColumn)
782
+ editor.value.range!.focus.moveToStart(nextColumn)
783
+ }
784
+ editor.value.domRender()
785
+ editor.value.rangeRender()
786
+ }
787
+ }
788
+ //表格前后插入行
789
+ const insertTableRow = (type: string | undefined = 'up') => {
790
+ if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
791
+ editor.value.range!.anchor.element = editor.value.range!.focus.element
792
+ editor.value.range!.anchor.offset = editor.value.range!.focus.offset
793
+ }
794
+ const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
795
+ const row = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tr')
796
+ if (table && row) {
797
+ const newRow = row.clone()
798
+ newRow.children!.forEach(column => {
799
+ column.children = []
800
+ const breakEl = new AlexElement('closed', 'br', null, null, null)
801
+ editor.value.addElementTo(breakEl, column)
802
+ })
803
+ if (type == 'up') {
804
+ editor.value.addElementBefore(newRow, row)
805
+ } else {
806
+ editor.value.addElementAfter(newRow, row)
807
+ }
808
+ editor.value.formatElementStack()
809
+ editor.value.range!.anchor.moveToStart(newRow)
810
+ editor.value.range!.focus.moveToStart(newRow)
811
+ editor.value.domRender()
812
+ editor.value.rangeRender()
813
+ //更新工具条位置
814
+ setTimeout(() => {
815
+ layerRef.value!.setPosition()
816
+ }, 0)
817
+ }
818
+ }
819
+ //表格前后插入段落
820
+ const insertParagraphWithTable = (type: string | undefined = 'up') => {
821
+ const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
822
+ if (table) {
823
+ const paragraph = new AlexElement('block', AlexElement.BLOCK_NODE, null, null, null)
824
+ const breakEl = new AlexElement('closed', 'br', null, null, null)
825
+ editor.value.addElementTo(breakEl, paragraph)
826
+ if (type == 'up') {
827
+ editor.value.addElementBefore(paragraph, table)
828
+ } else {
829
+ editor.value.addElementAfter(paragraph, table)
830
+ }
831
+ editor.value.range!.anchor.moveToEnd(paragraph)
832
+ editor.value.range!.focus.moveToEnd(paragraph)
833
+ editor.value.formatElementStack()
834
+ editor.value.domRender()
835
+ editor.value.rangeRender()
836
+ }
837
+ }
838
+ //删除元素
839
+ const deleteElement = (parsedom: string) => {
840
+ const element = getCurrentParsedomElement(editor.value, dataRangeCaches.value, parsedom)
841
+ if (element) {
842
+ element.toEmpty()
843
+ editor.value.formatElementStack()
844
+ editor.value.domRender()
845
+ editor.value.rangeRender()
846
+ }
847
+ }
848
+ //删除表格行
849
+ const deleteTableRow = () => {
850
+ if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
851
+ editor.value.range!.anchor.element = editor.value.range!.focus.element
852
+ editor.value.range!.anchor.offset = editor.value.range!.focus.offset
853
+ }
854
+ const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
855
+ const row = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tr')
856
+ if (table && row) {
857
+ const parent = row.parent!
858
+ if (parent.children!.length == 1) {
859
+ deleteElement('table')
860
+ return
861
+ }
862
+ const previousRow = editor.value.getPreviousElement(row)!
863
+ const nextRow = editor.value.getNextElement(row)!
864
+ row.toEmpty()
865
+ editor.value.formatElementStack()
866
+ if (previousRow) {
867
+ editor.value.range!.anchor.moveToEnd(previousRow.children![0])
868
+ editor.value.range!.focus.moveToEnd(previousRow.children![0])
869
+ } else {
870
+ editor.value.range!.anchor.moveToEnd(nextRow.children![0])
871
+ editor.value.range!.focus.moveToEnd(nextRow.children![0])
872
+ }
873
+ editor.value.domRender()
874
+ editor.value.rangeRender()
875
+ //更新工具条位置
876
+ setTimeout(() => {
877
+ layerRef.value!.setPosition()
878
+ }, 0)
879
+ }
880
+ }
881
+ //删除表格列
882
+ const deleteTableColumn = () => {
883
+ if (!editor.value.range!.anchor.isEqual(editor.value.range!.focus)) {
884
+ editor.value.range!.anchor.element = editor.value.range!.focus.element
885
+ editor.value.range!.anchor.offset = editor.value.range!.focus.offset
886
+ }
887
+ const column = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'td')
888
+ const tbody = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'tbody')
889
+ const table = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'table')
890
+ if (column && table && tbody) {
891
+ const rows = tbody.children!
892
+ const parent = column.parent!
893
+ if (parent.children!.length == 1) {
894
+ deleteElement('table')
895
+ return
896
+ }
897
+ const previousColumn = editor.value.getPreviousElement(column)!
898
+ const nextColumn = editor.value.getNextElement(column)!
899
+ const index = column.parent!.children!.findIndex(item => {
900
+ return item.isEqual(column)
901
+ })
902
+ //删除列
903
+ rows.forEach(row => {
904
+ row.children![index].toEmpty()
905
+ })
906
+ //删除col
907
+ const colgroup = table.children!.find(item => {
908
+ return item.parsedom == 'colgroup'
909
+ })!
910
+ colgroup.children![index].toEmpty()
911
+ //渲染
912
+ editor.value.formatElementStack()
913
+ if (previousColumn) {
914
+ editor.value.range!.anchor.moveToEnd(previousColumn)
915
+ editor.value.range!.focus.moveToEnd(previousColumn)
916
+ } else {
917
+ editor.value.range!.anchor.moveToEnd(nextColumn)
918
+ editor.value.range!.focus.moveToEnd(nextColumn)
919
+ }
920
+ editor.value.domRender()
921
+ editor.value.rangeRender()
922
+ }
923
+ }
924
+ //浮层显示时
925
+ const layerShow = () => {
926
+ //代码块初始化展示设置
927
+ if (props.type == 'codeBlock') {
928
+ const pre = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'pre')
929
+ if (pre) {
930
+ languageConfig.value.displayConfig.value = pre.marks!['data-editify-hljs'] || ''
931
+ }
932
+ }
933
+ //链接初始化展示
934
+ else if (props.type == 'link') {
935
+ const link = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'a')
936
+ if (link) {
937
+ linkConfig.value.url = link.marks!['href']
938
+ linkConfig.value.newOpen = link.marks!['target'] == '_blank'
939
+ }
940
+ }
941
+ //视频初始化显示
942
+ else if (props.type == 'video') {
943
+ const video = getCurrentParsedomElement(editor.value, dataRangeCaches.value, 'video')
944
+ if (video) {
945
+ videoConfig.value.autoplay = !!video.marks!['autoplay']
946
+ videoConfig.value.loop = !!video.marks!['loop']
947
+ videoConfig.value.controls = !!video.marks!['controls']
948
+ videoConfig.value.muted = !!video.marks!['muted']
949
+ }
950
+ }
951
+ //文本工具条初始化显示
952
+ else if (props.type == 'text') {
953
+ //额外禁用判定
954
+ const extraDisabled = (name: string) => {
955
+ if (typeof props.config.extraDisabled == 'function') {
956
+ return props.config.extraDisabled.apply(editify.proxy!, [name]) || false
957
+ }
958
+ return false
959
+ }
960
+ //显示已设置标题
961
+ const findHeadingItem = headingConfig.value.displayConfig.options.find((item: string | number | ButtonOptionsItemType) => {
962
+ let val: string | number | ButtonOptionsItemType = item
963
+ if (DapCommon.isObject(item)) {
964
+ val = (<ButtonOptionsItemType>item).value!
965
+ }
966
+ return dataRangeCaches.value.list.every(el => {
967
+ if (el.element.isBlock()) {
968
+ return el.element.parsedom == val
969
+ }
970
+ return el.element.getBlock().parsedom == val
971
+ })
972
+ })
973
+ headingConfig.value.displayConfig.value = findHeadingItem ? (DapCommon.isObject(findHeadingItem) ? findHeadingItem.value : findHeadingItem) : headingConfig.value.defaultValue
974
+ //标题禁用
975
+ headingConfig.value.disabled = extraDisabled('heading')
976
+
977
+ //对齐方式禁用
978
+ alignConfig.value.disabled = extraDisabled('align')
979
+
980
+ //有序列表按钮激活
981
+ orderListConfig.value.active = isRangeInList(editor.value, dataRangeCaches.value, true)
982
+ //有序列表按钮禁用
983
+ orderListConfig.value.disabled = extraDisabled('orderList')
984
+
985
+ //无序列表按钮激活
986
+ unorderListConfig.value.active = isRangeInList(editor.value, dataRangeCaches.value, false)
987
+ //无序列表按钮禁用
988
+ unorderListConfig.value.disabled = extraDisabled('unorderList')
989
+
990
+ //任务列表按钮激活
991
+ taskConfig.value.active = isRangeInTask(editor.value, dataRangeCaches.value)
992
+ //任务列表按钮禁用
993
+ taskConfig.value.disabled = extraDisabled('task')
994
+
995
+ //粗体按钮激活
996
+ boldConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'font-weight', 'bold') || queryTextStyle(editor.value, dataRangeCaches.value, 'font-weight', '700')
997
+ //粗体按钮禁用
998
+ boldConfig.value.disabled = extraDisabled('bold')
999
+
1000
+ //斜体按钮激活
1001
+ italicConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'font-style', 'italic')
1002
+ //斜体按钮禁用
1003
+ italicConfig.value.disabled = extraDisabled('italic')
1004
+
1005
+ //删除线按钮激活
1006
+ strikethroughConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration', 'line-through') || queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration-line', 'line-through')
1007
+ //删除线按钮禁用
1008
+ strikethroughConfig.value.disabled = extraDisabled('strikethrough')
1009
+
1010
+ //下划线按钮激活
1011
+ underlineConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration', 'underline') || queryTextStyle(editor.value, dataRangeCaches.value, 'text-decoration-line', 'underline')
1012
+ //下划线按钮禁用
1013
+ underlineConfig.value.disabled = extraDisabled('underline')
1014
+
1015
+ //行内代码按钮激活
1016
+ codeConfig.value.active = queryTextMark(editor.value, dataRangeCaches.value, 'data-editify-code')
1017
+ //行内代码按钮禁用
1018
+ codeConfig.value.disabled = extraDisabled('code')
1019
+
1020
+ //上标按钮激活
1021
+ superConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'vertical-align', 'super')
1022
+ //上标按钮禁用
1023
+ superConfig.value.disabled = extraDisabled('super')
1024
+
1025
+ //下标按钮激活
1026
+ subConfig.value.active = queryTextStyle(editor.value, dataRangeCaches.value, 'vertical-align', 'sub')
1027
+ //下标按钮禁用
1028
+ subConfig.value.disabled = extraDisabled('sub')
1029
+
1030
+ //显示已选择字号
1031
+ const findFontItem = fontSizeConfig.value.displayConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1032
+ if (DapCommon.isObject(item)) {
1033
+ return queryTextStyle(editor.value, dataRangeCaches.value, 'font-size', (<ButtonOptionsItemType>item).value)
1034
+ }
1035
+ return queryTextStyle(editor.value, dataRangeCaches.value, 'font-size', <string | number>item)
1036
+ })
1037
+ fontSizeConfig.value.displayConfig.value = findFontItem ? (DapCommon.isObject(findFontItem) ? findFontItem.value : findFontItem) : fontSizeConfig.value.defaultValue
1038
+ //字号按钮禁用
1039
+ fontSizeConfig.value.disabled = extraDisabled('fontSize')
1040
+
1041
+ //显示已选择字体
1042
+ const findFamilyItem = fontFamilyConfig.value.displayConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1043
+ if (DapCommon.isObject(item)) {
1044
+ return queryTextStyle(editor.value, dataRangeCaches.value, 'font-family', (<ButtonOptionsItemType>item).value)
1045
+ }
1046
+ return queryTextStyle(editor.value, dataRangeCaches.value, 'font-family', <string | number>item)
1047
+ })
1048
+ fontFamilyConfig.value.displayConfig.value = findFamilyItem ? (DapCommon.isObject(findFamilyItem) ? findFamilyItem.value : findFamilyItem) : fontFamilyConfig.value.defaultValue
1049
+ //字体按钮禁用
1050
+ fontFamilyConfig.value.disabled = extraDisabled('fontFamily')
1051
+
1052
+ //显示已设置行高
1053
+ const findHeightItem = lineHeightConfig.value.displayConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1054
+ let val: string | number | ButtonOptionsItemType = item
1055
+ if (DapCommon.isObject(item)) {
1056
+ val = (<ButtonOptionsItemType>item).value!
1057
+ }
1058
+ return dataRangeCaches.value.list.every(el => {
1059
+ if (el.element.isBlock() || el.element.isInblock()) {
1060
+ return el.element.hasStyles() && el.element.styles!['line-height'] == val
1061
+ }
1062
+ const block = el.element.getBlock()
1063
+ const inblock = el.element.getInblock()
1064
+ if (inblock) {
1065
+ return inblock.hasStyles() && inblock.styles!['line-height'] == val
1066
+ }
1067
+ return block.hasStyles() && block.styles!['line-height'] == val
1068
+ })
1069
+ })
1070
+ lineHeightConfig.value.displayConfig.value = findHeightItem ? (DapCommon.isObject(findHeightItem) ? findHeightItem.value : findHeightItem) : lineHeightConfig.value.defaultValue
1071
+ //行高按钮禁用
1072
+ lineHeightConfig.value.disabled = extraDisabled('lineHeight')
1073
+
1074
+ //显示已选择的前景色
1075
+ const findForeColorItem = foreColorConfig.value.selectConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1076
+ if (DapCommon.isObject(item)) {
1077
+ return queryTextStyle(editor.value, dataRangeCaches.value, 'color', (<ButtonOptionsItemType>item).value)
1078
+ }
1079
+ return queryTextStyle(editor.value, dataRangeCaches.value, 'color', <string | number>item)
1080
+ })
1081
+ foreColorConfig.value.value = findForeColorItem ? (DapCommon.isObject(findForeColorItem) ? findForeColorItem.value : findForeColorItem) : ''
1082
+ //前景色按钮禁用
1083
+ foreColorConfig.value.disabled = extraDisabled('foreColor')
1084
+
1085
+ //显示已选择的背景色
1086
+ const findBackColorItem = backColorConfig.value.selectConfig.options.find((item: string | number | ButtonOptionsItemType) => {
1087
+ if (DapCommon.isObject(item)) {
1088
+ return queryTextStyle(editor.value, dataRangeCaches.value, 'background-color', (<ButtonOptionsItemType>item).value)
1089
+ }
1090
+ return queryTextStyle(editor.value, dataRangeCaches.value, 'background-color', <string | number>item)
1091
+ })
1092
+ backColorConfig.value.value = findBackColorItem ? (DapCommon.isObject(findBackColorItem) ? findBackColorItem.value : findBackColorItem) : ''
1093
+ //背景色按钮禁用
1094
+ backColorConfig.value.disabled = extraDisabled('backColor')
1095
+
1096
+ //清除格式按钮禁用
1097
+ formatClearConfig.value.disabled = extraDisabled('formatClear')
1098
+ }
1099
+ }
1100
+ </script>
1101
+ <style scoped src="./toolbar.less"></style>