vue-editify 0.1.18 → 0.1.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. package/README.md +3 -3
  2. package/examples/App.vue +62 -61
  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 +68 -68
  18. package/lib/editify.es.js +17 -17
  19. package/lib/editify.umd.js +1 -1
  20. package/lib/index.d.ts +1 -1
  21. package/lib/style.css +1 -1
  22. package/package.json +45 -45
  23. package/src/components/button/button.less +145 -145
  24. package/src/components/button/button.vue +197 -197
  25. package/src/components/button/props.ts +95 -95
  26. package/src/components/checkbox/checkbox.less +84 -84
  27. package/src/components/checkbox/checkbox.vue +68 -68
  28. package/src/components/checkbox/props.ts +49 -49
  29. package/src/components/colors/colors.less +75 -75
  30. package/src/components/colors/colors.vue +36 -36
  31. package/src/components/colors/props.ts +29 -29
  32. package/src/components/icon/icon.less +14 -14
  33. package/src/components/icon/icon.vue +12 -12
  34. package/src/components/icon/props.ts +11 -11
  35. package/src/components/insertImage/insertImage.less +135 -135
  36. package/src/components/insertImage/insertImage.vue +146 -146
  37. package/src/components/insertImage/props.ts +43 -43
  38. package/src/components/insertLink/insertLink.less +64 -64
  39. package/src/components/insertLink/insertLink.vue +58 -58
  40. package/src/components/insertLink/props.ts +16 -16
  41. package/src/components/insertTable/insertTable.less +54 -54
  42. package/src/components/insertTable/insertTable.vue +85 -85
  43. package/src/components/insertTable/props.ts +27 -27
  44. package/src/components/insertVideo/insertVideo.less +135 -135
  45. package/src/components/insertVideo/insertVideo.vue +146 -146
  46. package/src/components/insertVideo/props.ts +43 -43
  47. package/src/components/layer/layer.less +49 -49
  48. package/src/components/layer/layer.vue +598 -598
  49. package/src/components/layer/props.ts +71 -71
  50. package/src/components/menu/menu.less +63 -63
  51. package/src/components/menu/menu.vue +1569 -1569
  52. package/src/components/menu/props.ts +17 -17
  53. package/src/components/toolbar/props.ts +35 -35
  54. package/src/components/toolbar/toolbar.less +89 -89
  55. package/src/components/toolbar/toolbar.vue +1101 -1101
  56. package/src/components/tooltip/props.ts +21 -21
  57. package/src/components/tooltip/tooltip.less +23 -23
  58. package/src/components/tooltip/tooltip.vue +37 -37
  59. package/src/components/triangle/props.ts +26 -26
  60. package/src/components/triangle/triangle.less +79 -79
  61. package/src/components/triangle/triangle.vue +65 -65
  62. package/src/core/function.ts +1144 -1144
  63. package/src/core/rule.ts +259 -259
  64. package/src/core/tool.ts +1137 -1137
  65. package/src/css/base.less +30 -30
  66. package/src/css/hljs.less +54 -54
  67. package/src/editify/editify.less +404 -403
  68. package/src/editify/editify.vue +803 -803
  69. package/src/editify/props.ts +156 -156
  70. package/src/hljs/index.ts +197 -197
  71. package/src/icon/iconfont.css +219 -219
  72. package/src/index.ts +32 -32
  73. package/src/locale/en_US.ts +88 -88
  74. package/src/locale/index.ts +12 -12
  75. package/src/locale/zh_CN.ts +88 -88
  76. package/tsconfig.json +27 -27
  77. package/tsconfig.node.json +11 -11
  78. package/vite-env.d.ts +1 -1
  79. 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>