vue-editify 0.2.17 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/examples/App.vue +4 -12
- package/lib/components/colors/colors.vue.d.ts +9 -0
- package/lib/components/colors/props.d.ts +4 -0
- package/lib/components/tooltip/tooltip.vue.d.ts +1 -1
- package/lib/core/function.d.ts +112 -64
- package/lib/core/rule.d.ts +23 -17
- package/lib/core/shortcut.d.ts +36 -0
- package/lib/core/tool.d.ts +12 -16
- package/lib/editify/editify.vue.d.ts +162 -15
- package/lib/editify/props.d.ts +1 -5
- package/lib/editify/toolbar/props.d.ts +1 -1
- package/lib/editify/toolbar/toolbar.vue.d.ts +3 -3
- package/lib/editify.es.js +13660 -12954
- package/lib/editify.umd.js +2 -2
- package/lib/feature/align.d.ts +0 -14
- package/lib/feature/heading.d.ts +0 -14
- package/lib/feature/lineHeight.d.ts +0 -14
- package/lib/feature/orderList.d.ts +1 -3
- package/lib/feature/task.d.ts +0 -14
- package/lib/feature/unorderList.d.ts +1 -3
- package/lib/index.d.ts +164 -17
- package/package.json +2 -2
- package/src/components/button/button.vue +3 -3
- package/src/components/checkbox/checkbox.vue +1 -1
- package/src/components/colors/colors.vue +4 -4
- package/src/components/colors/props.ts +6 -1
- package/src/components/insertAttachment/insertAttachment.vue +1 -1
- package/src/components/insertImage/insertImage.vue +1 -1
- package/src/components/insertLink/insertLink.vue +1 -1
- package/src/components/insertVideo/insertVideo.vue +1 -1
- package/src/components/layer/layer.vue +9 -3
- package/src/components/tooltip/tooltip.vue +1 -1
- package/src/components/updateLink/updateLink.vue +1 -1
- package/src/core/function.ts +873 -491
- package/src/core/rule.ts +86 -368
- package/src/core/shortcut.ts +386 -0
- package/src/core/tool.ts +111 -159
- package/src/css/var.less +0 -10
- package/src/editify/editify.less +85 -39
- package/src/editify/editify.vue +204 -88
- package/src/editify/menu/menu.vue +2 -3
- package/src/editify/props.ts +1 -6
- package/src/editify/toolbar/props.ts +2 -2
- package/src/editify/toolbar/toolbar.vue +12 -12
- package/src/feature/align.ts +2 -62
- package/src/feature/attachment.ts +14 -27
- package/src/feature/backColor.ts +2 -1
- package/src/feature/bold.ts +1 -1
- package/src/feature/code.ts +1 -1
- package/src/feature/codeBlock.ts +3 -3
- package/src/feature/fontFamily.ts +1 -1
- package/src/feature/fontSize.ts +1 -1
- package/src/feature/foreColor.ts +2 -1
- package/src/feature/formatClear.ts +1 -1
- package/src/feature/fullScreen.ts +1 -1
- package/src/feature/heading.ts +5 -76
- package/src/feature/image.ts +1 -1
- package/src/feature/indent.ts +1 -1
- package/src/feature/infoBlock.ts +6 -37
- package/src/feature/italic.ts +1 -1
- package/src/feature/lineHeight.ts +2 -78
- package/src/feature/link.ts +1 -1
- package/src/feature/mathformula.ts +4 -51
- package/src/feature/orderList.ts +168 -37
- package/src/feature/quote.ts +3 -3
- package/src/feature/redo.ts +1 -1
- package/src/feature/separator.ts +1 -1
- package/src/feature/sourceView.ts +1 -1
- package/src/feature/strikethrough.ts +1 -1
- package/src/feature/sub.ts +1 -1
- package/src/feature/super.ts +1 -1
- package/src/feature/table.ts +3 -3
- package/src/feature/task.ts +4 -58
- package/src/feature/underline.ts +1 -1
- package/src/feature/undo.ts +1 -1
- package/src/feature/unorderList.ts +108 -37
- package/src/feature/video.ts +1 -1
- package/src/icon/iconfont.css +39 -3
- package/src/icon/iconfont.ttf +0 -0
- package/src/icon/iconfont.woff +0 -0
- package/src/index.ts +13 -11
- package/src/locale/en_US.ts +109 -110
- package/src/locale/zh_CN.ts +11 -12
- package/lib/feature/panel.d.ts +0 -18
- package/src/feature/panel.ts +0 -107
package/src/editify/editify.less
CHANGED
@@ -136,23 +136,92 @@
|
|
136
136
|
:deep(h6) {
|
137
137
|
font-size: 16px;
|
138
138
|
}
|
139
|
+
|
140
|
+
//不是有序列表元素则重置后面的有序列表序列
|
141
|
+
:deep(:not(div[data-editify-list='ol'])) + div[data-editify-list='ol'] {
|
142
|
+
counter-reset: item 0;
|
143
|
+
}
|
144
|
+
|
139
145
|
//有序列表样式
|
140
146
|
:deep(div[data-editify-list='ol']) {
|
141
147
|
margin-bottom: 15px;
|
142
148
|
|
149
|
+
//第一个元素重置序列
|
150
|
+
&:first-of-type {
|
151
|
+
counter-reset: item 0;
|
152
|
+
}
|
153
|
+
|
143
154
|
&::before {
|
144
|
-
|
155
|
+
counter-increment: item;
|
156
|
+
content: counter(item) '.';
|
145
157
|
margin-right: 10px;
|
146
158
|
}
|
159
|
+
|
160
|
+
&[data-editify-list-style='decimal'] {
|
161
|
+
&::before {
|
162
|
+
content: counter(item, decimal) '.';
|
163
|
+
}
|
164
|
+
}
|
165
|
+
&[data-editify-list-style='decimal-leading-zero'] {
|
166
|
+
&::before {
|
167
|
+
content: counter(item, decimal-leading-zero) '.';
|
168
|
+
}
|
169
|
+
}
|
170
|
+
&[data-editify-list-style='lower-roman'] {
|
171
|
+
&::before {
|
172
|
+
content: counter(item, lower-roman) '.';
|
173
|
+
}
|
174
|
+
}
|
175
|
+
&[data-editify-list-style='upper-roman'] {
|
176
|
+
&::before {
|
177
|
+
content: counter(item, upper-roman) '.';
|
178
|
+
}
|
179
|
+
}
|
180
|
+
&[data-editify-list-style='lower-alpha'] {
|
181
|
+
&::before {
|
182
|
+
content: counter(item, lower-alpha) '.';
|
183
|
+
}
|
184
|
+
}
|
185
|
+
&[data-editify-list-style='upper-alpha'] {
|
186
|
+
&::before {
|
187
|
+
content: counter(item, upper-alpha) '.';
|
188
|
+
}
|
189
|
+
}
|
190
|
+
&[data-editify-list-style='lower-greek'] {
|
191
|
+
&::before {
|
192
|
+
content: counter(item, lower-greek) '.';
|
193
|
+
}
|
194
|
+
}
|
195
|
+
&[data-editify-list-style='cjk-ideographic'] {
|
196
|
+
&::before {
|
197
|
+
content: counter(item, cjk-ideographic) '.';
|
198
|
+
}
|
199
|
+
}
|
147
200
|
}
|
148
201
|
//无序列表样式
|
149
202
|
:deep(div[data-editify-list='ul']) {
|
150
203
|
margin-bottom: 15px;
|
151
204
|
|
152
205
|
&::before {
|
153
|
-
content:
|
206
|
+
content: counter(item, disc);
|
154
207
|
margin-right: 10px;
|
155
208
|
}
|
209
|
+
|
210
|
+
&[data-editify-list-style='disc'] {
|
211
|
+
&::before {
|
212
|
+
content: counter(item, disc);
|
213
|
+
}
|
214
|
+
}
|
215
|
+
&[data-editify-list-style='circle'] {
|
216
|
+
&::before {
|
217
|
+
content: counter(item, circle);
|
218
|
+
}
|
219
|
+
}
|
220
|
+
&[data-editify-list-style='square'] {
|
221
|
+
&::before {
|
222
|
+
content: counter(item, square);
|
223
|
+
}
|
224
|
+
}
|
156
225
|
}
|
157
226
|
//代码样式
|
158
227
|
:deep([data-editify-code]) {
|
@@ -309,15 +378,13 @@
|
|
309
378
|
padding-left: 26px;
|
310
379
|
font-size: var(--editify-font-size);
|
311
380
|
color: var(--editify-font-color-dark);
|
312
|
-
transition: all 300ms;
|
313
381
|
|
314
382
|
&::before {
|
315
383
|
display: block;
|
316
|
-
width:
|
317
|
-
height:
|
384
|
+
width: 14px;
|
385
|
+
height: 14px;
|
318
386
|
border-radius: 2px;
|
319
387
|
border: 1px solid var(--editify-font-color-light);
|
320
|
-
transition: all 300ms;
|
321
388
|
box-sizing: border-box;
|
322
389
|
user-select: none;
|
323
390
|
content: '';
|
@@ -332,29 +399,32 @@
|
|
332
399
|
&::after {
|
333
400
|
display: inline-block;
|
334
401
|
width: 10px;
|
335
|
-
height:
|
402
|
+
height: 5px;
|
336
403
|
position: absolute;
|
337
404
|
content: '';
|
338
|
-
left:
|
405
|
+
left: 2px;
|
339
406
|
top: 50%;
|
340
|
-
margin-top: -
|
341
|
-
border:
|
407
|
+
margin-top: -1px;
|
408
|
+
border: 2px solid transparent;
|
342
409
|
border-top: none;
|
343
410
|
border-right: none;
|
344
411
|
transform: translateY(-50%) rotate(-45deg);
|
345
412
|
transform-origin: center;
|
346
|
-
box-sizing: border-box;
|
347
413
|
z-index: 2;
|
348
414
|
cursor: pointer;
|
349
|
-
opacity: 0;
|
350
|
-
transition: all 300ms;
|
351
415
|
}
|
352
416
|
|
353
417
|
&[data-editify-task='checked'] {
|
354
418
|
text-decoration: line-through;
|
355
419
|
color: var(--editify-font-color-light);
|
420
|
+
|
421
|
+
&::before {
|
422
|
+
background-color: var(--editify-font-color-disabled);
|
423
|
+
border-color: var(--editify-font-color-disabled);
|
424
|
+
}
|
425
|
+
|
356
426
|
&::after {
|
357
|
-
|
427
|
+
border-color: #fff;
|
358
428
|
}
|
359
429
|
}
|
360
430
|
}
|
@@ -407,30 +477,6 @@
|
|
407
477
|
background: var(--editify-background-darker);
|
408
478
|
}
|
409
479
|
}
|
410
|
-
//面板样式
|
411
|
-
:deep(div[data-editify-panel]) {
|
412
|
-
display: block;
|
413
|
-
position: relative;
|
414
|
-
width: 100%;
|
415
|
-
background-color: var(--editify-background-dark);
|
416
|
-
color: var(--editify-font-color);
|
417
|
-
border-radius: 4px;
|
418
|
-
margin-bottom: 15px;
|
419
|
-
padding: 10px 10px 1px 10px;
|
420
|
-
border: 1px solid var(--editify-border-color);
|
421
|
-
|
422
|
-
& > div {
|
423
|
-
margin: 0 0 10px 0;
|
424
|
-
font-size: var(--editify-font-size);
|
425
|
-
|
426
|
-
&:first-child {
|
427
|
-
margin: 0 0 15px 0;
|
428
|
-
font-size: 18px;
|
429
|
-
border-bottom: 1px solid var(--editify-border-color);
|
430
|
-
padding-bottom: 8px;
|
431
|
-
}
|
432
|
-
}
|
433
|
-
}
|
434
480
|
//信息块样式
|
435
481
|
:deep(div[data-editify-info]) {
|
436
482
|
display: block;
|
@@ -452,7 +498,7 @@
|
|
452
498
|
display: flex;
|
453
499
|
justify-content: center;
|
454
500
|
align-items: center;
|
455
|
-
content: '\
|
501
|
+
content: '\e600';
|
456
502
|
font-family: 'editify-icon' !important;
|
457
503
|
font-size: 1.25em;
|
458
504
|
padding: 0 20px;
|
package/src/editify/editify.vue
CHANGED
@@ -21,10 +21,10 @@
|
|
21
21
|
<script setup lang="ts">
|
22
22
|
import { computed, getCurrentInstance, nextTick, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue'
|
23
23
|
import { AlexEditor, AlexElement, AlexElementRangeType, AlexElementsRangeType } from 'alex-editor'
|
24
|
-
import { element as DapElement, event as DapEvent, data as DapData, number as DapNumber, color as DapColor } from 'dap-util'
|
25
|
-
import { mergeObject, getToolbarConfig, getMenuConfig, MenuConfigType, ObjectType, ToolbarConfigType, clickIsOut,
|
26
|
-
import {
|
27
|
-
import { elementToParagraph, getMatchElementByRange,
|
24
|
+
import { element as DapElement, event as DapEvent, data as DapData, number as DapNumber, color as DapColor, common as DapCommon } from 'dap-util'
|
25
|
+
import { mergeObject, getToolbarConfig, getMenuConfig, MenuConfigType, ObjectType, ToolbarConfigType, clickIsOut, ShortcutType, MenuExtendType } from '@/core/tool'
|
26
|
+
import { listHandle, imageHandle, videoHandle, separatorHandle, linkHandle, codeHandle, tableHandle, preHandle, attachmentHandle, mathformulaHandle, infoBlockHandle, specialInblockHandle } from '@/core/rule'
|
27
|
+
import { elementToParagraph, getMatchElementByRange, elementIsTask, elementIsAttachment, elementIsList, elementIsMathformula, getMathformulaByElement, elementIsInfoBlock, getMatchElementByElement, hasTableInRange, hasPreInRange } from '@/core/function'
|
28
28
|
import { trans } from '@/locale'
|
29
29
|
import { LanguagesItemType } from '@/hljs'
|
30
30
|
import { extraKeepTagsForMathformula } from '@/feature/mathformula'
|
@@ -125,7 +125,7 @@ const showBorder = computed<boolean>(() => {
|
|
125
125
|
})
|
126
126
|
//最终生效的工具栏配置
|
127
127
|
const toolbarConfig = computed<ToolbarConfigType>(() => {
|
128
|
-
return mergeObject(getToolbarConfig($editTrans
|
128
|
+
return mergeObject(getToolbarConfig($editTrans), props.toolbar || {}) as ToolbarConfigType
|
129
129
|
})
|
130
130
|
//最终生效的菜单栏配置
|
131
131
|
const menuConfig = computed<MenuConfigType>(() => {
|
@@ -163,9 +163,7 @@ const handleToolbar = () => {
|
|
163
163
|
}
|
164
164
|
hideToolbar()
|
165
165
|
nextTick(() => {
|
166
|
-
const table = getMatchElementByRange(editor.value!, dataRangeCaches.value, { parsedom: 'table' })
|
167
166
|
const codeBlock = getMatchElementByRange(editor.value!, dataRangeCaches.value, { parsedom: 'pre' })
|
168
|
-
const link = getMatchElementByRange(editor.value!, dataRangeCaches.value, { parsedom: 'a' })
|
169
167
|
const image = getMatchElementByRange(editor.value!, dataRangeCaches.value, { parsedom: 'img' })
|
170
168
|
const video = getMatchElementByRange(editor.value!, dataRangeCaches.value, { parsedom: 'video' })
|
171
169
|
|
@@ -189,26 +187,6 @@ const handleToolbar = () => {
|
|
189
187
|
toolbarOptions.value.show = true
|
190
188
|
}
|
191
189
|
}
|
192
|
-
//显示链接工具条
|
193
|
-
else if (link) {
|
194
|
-
toolbarOptions.value.type = 'link'
|
195
|
-
toolbarOptions.value.node = `[data-editify-uid="${instance.uid}"] [data-editify-element="${link.key}"]`
|
196
|
-
if (toolbarOptions.value.show) {
|
197
|
-
toolbarRef.value!.layerRef!.setPosition()
|
198
|
-
} else {
|
199
|
-
toolbarOptions.value.show = true
|
200
|
-
}
|
201
|
-
}
|
202
|
-
//显示表格工具条
|
203
|
-
else if (table) {
|
204
|
-
toolbarOptions.value.type = 'table'
|
205
|
-
toolbarOptions.value.node = `[data-editify-uid="${instance.uid}"] [data-editify-element="${table.key}"]`
|
206
|
-
if (toolbarOptions.value.show) {
|
207
|
-
toolbarRef.value!.layerRef!.setPosition()
|
208
|
-
} else {
|
209
|
-
toolbarOptions.value.show = true
|
210
|
-
}
|
211
|
-
}
|
212
190
|
//显示代码块工具条
|
213
191
|
else if (codeBlock) {
|
214
192
|
toolbarOptions.value.type = 'codeBlock'
|
@@ -219,10 +197,11 @@ const handleToolbar = () => {
|
|
219
197
|
toolbarOptions.value.show = true
|
220
198
|
}
|
221
199
|
}
|
222
|
-
|
200
|
+
//以下是选区时显示文本工具条,非选区时显示其他工具条的情况
|
223
201
|
else {
|
224
202
|
const result = dataRangeCaches.value.flatList.filter((item: AlexElementRangeType) => item.element.isText())
|
225
|
-
|
203
|
+
//显示文本工具条
|
204
|
+
if (result.length) {
|
226
205
|
toolbarOptions.value.type = 'text'
|
227
206
|
if (toolbarOptions.value.show) {
|
228
207
|
toolbarRef.value!.layerRef!.setPosition()
|
@@ -230,6 +209,63 @@ const handleToolbar = () => {
|
|
230
209
|
toolbarOptions.value.show = true
|
231
210
|
}
|
232
211
|
}
|
212
|
+
//显示其他工具条
|
213
|
+
else {
|
214
|
+
const table = getMatchElementByRange(editor.value!, dataRangeCaches.value, { parsedom: 'table' })
|
215
|
+
const link = getMatchElementByRange(editor.value!, dataRangeCaches.value, { parsedom: 'a' })
|
216
|
+
const orderList = getMatchElementByRange(editor.value!, dataRangeCaches.value, {
|
217
|
+
parsedom: 'div',
|
218
|
+
marks: {
|
219
|
+
'data-editify-list': 'ol'
|
220
|
+
}
|
221
|
+
})
|
222
|
+
const unorderList = getMatchElementByRange(editor.value!, dataRangeCaches.value, {
|
223
|
+
parsedom: 'div',
|
224
|
+
marks: {
|
225
|
+
'data-editify-list': 'ul'
|
226
|
+
}
|
227
|
+
})
|
228
|
+
//显示链接工具条
|
229
|
+
if (link) {
|
230
|
+
toolbarOptions.value.type = 'link'
|
231
|
+
toolbarOptions.value.node = `[data-editify-uid="${instance.uid}"] [data-editify-element="${link.key}"]`
|
232
|
+
if (toolbarOptions.value.show) {
|
233
|
+
toolbarRef.value!.layerRef!.setPosition()
|
234
|
+
} else {
|
235
|
+
toolbarOptions.value.show = true
|
236
|
+
}
|
237
|
+
}
|
238
|
+
//显示表格工具条
|
239
|
+
else if (table) {
|
240
|
+
toolbarOptions.value.type = 'table'
|
241
|
+
toolbarOptions.value.node = `[data-editify-uid="${instance.uid}"] [data-editify-element="${table.key}"]`
|
242
|
+
if (toolbarOptions.value.show) {
|
243
|
+
toolbarRef.value!.layerRef!.setPosition()
|
244
|
+
} else {
|
245
|
+
toolbarOptions.value.show = true
|
246
|
+
}
|
247
|
+
}
|
248
|
+
//显示有序列表工具条
|
249
|
+
else if (orderList) {
|
250
|
+
toolbarOptions.value.type = 'orderList'
|
251
|
+
toolbarOptions.value.node = `[data-editify-uid="${instance.uid}"] [data-editify-element="${orderList.key}"]`
|
252
|
+
if (toolbarOptions.value.show) {
|
253
|
+
toolbarRef.value!.layerRef!.setPosition()
|
254
|
+
} else {
|
255
|
+
toolbarOptions.value.show = true
|
256
|
+
}
|
257
|
+
}
|
258
|
+
//显示无序列表工具条
|
259
|
+
else if (unorderList) {
|
260
|
+
toolbarOptions.value.type = 'unorderList'
|
261
|
+
toolbarOptions.value.node = `[data-editify-uid="${instance.uid}"] [data-editify-element="${unorderList.key}"]`
|
262
|
+
if (toolbarOptions.value.show) {
|
263
|
+
toolbarRef.value!.layerRef!.setPosition()
|
264
|
+
} else {
|
265
|
+
toolbarOptions.value.show = true
|
266
|
+
}
|
267
|
+
}
|
268
|
+
}
|
233
269
|
}
|
234
270
|
})
|
235
271
|
}
|
@@ -241,28 +277,28 @@ const createEditor = () => {
|
|
241
277
|
disabled: isDisabled.value,
|
242
278
|
renderRules: [
|
243
279
|
el => {
|
244
|
-
|
280
|
+
listHandle(editor.value!, el)
|
245
281
|
},
|
246
282
|
el => {
|
247
|
-
|
283
|
+
imageHandle(editor.value!, el)
|
248
284
|
},
|
249
285
|
el => {
|
250
|
-
|
286
|
+
videoHandle(editor.value!, el)
|
251
287
|
},
|
252
288
|
el => {
|
253
|
-
|
289
|
+
separatorHandle(editor.value!, el)
|
254
290
|
},
|
255
291
|
el => {
|
256
|
-
|
292
|
+
linkHandle(editor.value!, el)
|
257
293
|
},
|
258
294
|
el => {
|
259
|
-
|
295
|
+
codeHandle(editor.value!, el)
|
260
296
|
},
|
261
297
|
el => {
|
262
|
-
|
298
|
+
tableHandle(editor.value!, el)
|
263
299
|
},
|
264
300
|
el => {
|
265
|
-
|
301
|
+
preHandle(editor.value!, el, !!(toolbarConfig.value?.use && toolbarConfig.value?.codeBlock?.languages?.show), toolbarConfig.value?.codeBlock?.languages?.options as (string | LanguagesItemType)[])
|
266
302
|
},
|
267
303
|
el => {
|
268
304
|
attachmentHandle(editor.value!, el, $editTrans)
|
@@ -273,6 +309,9 @@ const createEditor = () => {
|
|
273
309
|
el => {
|
274
310
|
infoBlockHandle(editor.value!, el, props.color)
|
275
311
|
},
|
312
|
+
el => {
|
313
|
+
specialInblockHandle(editor.value!, el)
|
314
|
+
},
|
276
315
|
...props.renderRules
|
277
316
|
],
|
278
317
|
extraKeepTags: [...extraKeepTagsForMathformula, ...props.extraKeepTags],
|
@@ -473,7 +512,7 @@ const documentClick = (e: Event) => {
|
|
473
512
|
if (key) {
|
474
513
|
const element = editor.value!.getElementByKey(key)!
|
475
514
|
//如果是任务列表元素
|
476
|
-
if (elementIsTask(element)) {
|
515
|
+
if (element && elementIsTask(element)) {
|
477
516
|
const rect = DapElement.getElementBounding(elm)
|
478
517
|
//在复选框范围内
|
479
518
|
if (event.pageX >= Math.abs(rect.left) && event.pageX <= Math.abs(rect.left + 16) && event.pageY >= Math.abs(rect.top + elm.offsetHeight / 2 - 8) && event.pageY <= Math.abs(rect.top + elm.offsetHeight / 2 + 8)) {
|
@@ -499,7 +538,8 @@ const documentClick = (e: Event) => {
|
|
499
538
|
}
|
500
539
|
//重新定义编辑器粘贴html
|
501
540
|
const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
|
502
|
-
AlexElement.flatElements(elements)
|
541
|
+
const flatElements = AlexElement.flatElements(elements)
|
542
|
+
flatElements.forEach(el => {
|
503
543
|
if (!el.isText()) {
|
504
544
|
let marks: ObjectType = {}
|
505
545
|
let styles: ObjectType = {}
|
@@ -552,10 +592,7 @@ const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
|
|
552
592
|
//有序和无序列表属性保留
|
553
593
|
if (elementIsList(el, true) || elementIsList(el, false)) {
|
554
594
|
marks['data-editify-list'] = el.marks!['data-editify-list']
|
555
|
-
|
556
|
-
if (el.marks!['data-editify-value']) {
|
557
|
-
marks['data-editify-value'] = el.marks!['data-editify-value']
|
558
|
-
}
|
595
|
+
marks['data-editify-list-style'] = el.marks!['data-editify-list-style']
|
559
596
|
}
|
560
597
|
//行内代码属性保留
|
561
598
|
if (el.parsedom == AlexElement.TEXT_NODE && el.marks!['data-editify-code']) {
|
@@ -590,11 +627,7 @@ const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
|
|
590
627
|
}
|
591
628
|
//数学公式内的属性全部保留
|
592
629
|
if (!!getMathformulaByElement(el)) {
|
593
|
-
marks = mergeObject(marks,
|
594
|
-
}
|
595
|
-
//面板属性保留
|
596
|
-
if (elementIsPanel(el)) {
|
597
|
-
marks['data-editify-panel'] = el.marks!['data-editify-panel']
|
630
|
+
marks = mergeObject(marks, DapCommon.clone(el.marks!))!
|
598
631
|
}
|
599
632
|
//信息块属性保留
|
600
633
|
if (elementIsInfoBlock(el)) {
|
@@ -621,7 +654,7 @@ const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
|
|
621
654
|
}
|
622
655
|
//数学公式内的样式全部保留
|
623
656
|
if (!!getMathformulaByElement(el)) {
|
624
|
-
styles = mergeObject(styles,
|
657
|
+
styles = mergeObject(styles, DapCommon.clone(el.styles!))!
|
625
658
|
}
|
626
659
|
}
|
627
660
|
//对外的自定义属性和样式保留
|
@@ -635,7 +668,24 @@ const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
|
|
635
668
|
el.marks = marks
|
636
669
|
el.styles = styles
|
637
670
|
}
|
671
|
+
//对于不在table下的这些表格元素直接置空
|
672
|
+
if (el.parsedom && ['tbody', 'tr', 'th', 'td', 'thead', 'tfooter', 'colgroup', 'col'].includes(el.parsedom)) {
|
673
|
+
const flag = !!getMatchElementByElement(el, {
|
674
|
+
parsedom: 'table'
|
675
|
+
})
|
676
|
+
if (!flag) {
|
677
|
+
el.toEmpty()
|
678
|
+
if (el.parent) {
|
679
|
+
const index = el.parent.children!.findIndex(item => item.isEqual(el))
|
680
|
+
el.parent.children!.splice(index, 1)
|
681
|
+
}
|
682
|
+
}
|
683
|
+
}
|
638
684
|
})
|
685
|
+
elements = elements.filter(el => !el.isEmpty())
|
686
|
+
if (!elements.length) {
|
687
|
+
return
|
688
|
+
}
|
639
689
|
//如果使用了自定义粘贴html的功能
|
640
690
|
if (typeof props.customHtmlPaste == 'function') {
|
641
691
|
await props.customHtmlPaste(elements)
|
@@ -687,12 +737,94 @@ const handleCustomParseNode = (ele: AlexElement) => {
|
|
687
737
|
return ele
|
688
738
|
}
|
689
739
|
//编辑区域键盘按下
|
690
|
-
const handleEditorKeydown = (val: string, e:
|
740
|
+
const handleEditorKeydown = (val: string, e: KeyboardEvent) => {
|
691
741
|
if (isDisabled.value) {
|
692
742
|
return
|
693
743
|
}
|
694
|
-
|
695
|
-
|
744
|
+
//遍历菜单栏配置,设置快捷键
|
745
|
+
for (let key in menuConfig.value) {
|
746
|
+
//如果是拓展菜单
|
747
|
+
if (key == 'extends') {
|
748
|
+
//获取拓展菜单列表
|
749
|
+
const extendMenus = (menuConfig.value as any)[key] as MenuExtendType
|
750
|
+
//遍历拓展菜单列表
|
751
|
+
Object.keys(extendMenus).forEach(extendKey => {
|
752
|
+
//获取拓展菜单配置
|
753
|
+
const item = extendMenus[extendKey]
|
754
|
+
//获取该菜单按钮的快捷键配置
|
755
|
+
const shortcut = item.shortcut as ShortcutType | undefined
|
756
|
+
//如果快捷键配置存在并且定义了define方法
|
757
|
+
if (shortcut && typeof shortcut.define == 'function') {
|
758
|
+
//获取define方法执行结果
|
759
|
+
const res = shortcut.define(e) as boolean | { [code: string]: boolean }
|
760
|
+
//如果执行结果是true,则表示该快捷键按下
|
761
|
+
if (res === true) {
|
762
|
+
//阻止默认行为
|
763
|
+
e.preventDefault()
|
764
|
+
//没有被禁用则执行对应的操作
|
765
|
+
if (!item.disabled) {
|
766
|
+
shortcut.operation?.(editor.value!, dataRangeCaches.value, isSourceView, isFullScreen)
|
767
|
+
}
|
768
|
+
}
|
769
|
+
//如果是对象,则表示有多个快捷键操作
|
770
|
+
else if (res && DapCommon.isObject(res)) {
|
771
|
+
//遍历
|
772
|
+
Object.keys(res).forEach(code => {
|
773
|
+
//如果是true,则执行对应的操作
|
774
|
+
if (!!res[code]) {
|
775
|
+
//阻止默认行为
|
776
|
+
e.preventDefault()
|
777
|
+
//没有被禁用则执行对应的操作
|
778
|
+
if (!item.disabled) {
|
779
|
+
shortcut.operation?.(editor.value!, dataRangeCaches.value, isSourceView, isFullScreen, code)
|
780
|
+
}
|
781
|
+
}
|
782
|
+
})
|
783
|
+
}
|
784
|
+
}
|
785
|
+
})
|
786
|
+
}
|
787
|
+
//如果是内置菜单
|
788
|
+
else if (!['use', 'tooltip', 'mode', 'style', 'sequence'].includes(key)) {
|
789
|
+
const item = (menuConfig.value as any)[key]
|
790
|
+
//这里多做一步判断:判断是否菜单并且是否有快捷键配置
|
791
|
+
if (DapCommon.isObject(item) && item.show === true && DapCommon.isObject(item.shortcut)) {
|
792
|
+
//获取该菜单按钮的快捷键配置
|
793
|
+
const shortcut = item.shortcut as ShortcutType
|
794
|
+
//如果定义了define方法
|
795
|
+
if (typeof shortcut.define == 'function') {
|
796
|
+
//获取define方法执行结果
|
797
|
+
const res = shortcut.define(e) as boolean | { [code: string]: boolean }
|
798
|
+
//如果执行结果是true,则表示该快捷键按下
|
799
|
+
if (res === true) {
|
800
|
+
//阻止默认行为
|
801
|
+
e.preventDefault()
|
802
|
+
//没有被禁用则执行对应的操作
|
803
|
+
if (!item.disabled) {
|
804
|
+
shortcut.operation?.(editor.value!, dataRangeCaches.value, isSourceView, isFullScreen)
|
805
|
+
}
|
806
|
+
}
|
807
|
+
//如果是对象,则表示有多个快捷键操作
|
808
|
+
else if (res && DapCommon.isObject(res)) {
|
809
|
+
//遍历
|
810
|
+
Object.keys(res).forEach(code => {
|
811
|
+
//如果是true,则执行对应的操作
|
812
|
+
if (!!res[code]) {
|
813
|
+
//阻止默认行为
|
814
|
+
e.preventDefault()
|
815
|
+
//没有被禁用则执行对应的操作
|
816
|
+
if (!item.disabled) {
|
817
|
+
shortcut.operation?.(editor.value!, dataRangeCaches.value, isSourceView, isFullScreen, code)
|
818
|
+
}
|
819
|
+
}
|
820
|
+
})
|
821
|
+
}
|
822
|
+
}
|
823
|
+
}
|
824
|
+
}
|
825
|
+
}
|
826
|
+
//代码块和表格中单独按下tab键,插入4个空格
|
827
|
+
if (e.key.toLocaleLowerCase() == 'tab' && !e.metaKey && !e.shiftKey && !e.ctrlKey && !e.altKey && (hasTableInRange(editor.value!, dataRangeCaches.value) || hasPreInRange(editor.value!, dataRangeCaches.value))) {
|
696
828
|
e.preventDefault()
|
697
829
|
editor.value!.insertText(' ')
|
698
830
|
editor.value!.domRender()
|
@@ -862,27 +994,25 @@ const handleAfterRender = () => {
|
|
862
994
|
//设定视频高度
|
863
995
|
setVideoHeight()
|
864
996
|
//附件元素下载事件设置
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
method: 'GET'
|
875
|
-
})
|
876
|
-
//获取blob数据
|
877
|
-
const blob = await res.blob()
|
878
|
-
//创建a标签进行下载
|
879
|
-
const a = document.createElement('a')
|
880
|
-
a.setAttribute('target', '_blank')
|
881
|
-
a.setAttribute('href', URL.createObjectURL(blob))
|
882
|
-
a.setAttribute('download', el.marks!['data-editify-attachment-name'])
|
883
|
-
a.click()
|
997
|
+
contentRef.value!.querySelectorAll('span[data-editify-attachment]').forEach(dom => {
|
998
|
+
DapEvent.off(dom as HTMLElement, 'click')
|
999
|
+
//单击下载
|
1000
|
+
DapEvent.on(dom as HTMLElement, 'click', async () => {
|
1001
|
+
//获取文件地址
|
1002
|
+
const url = dom.getAttribute('data-editify-attachment')!
|
1003
|
+
//使用fetch读取文件地址
|
1004
|
+
const res = await fetch(url, {
|
1005
|
+
method: 'GET'
|
884
1006
|
})
|
885
|
-
|
1007
|
+
//获取blob数据
|
1008
|
+
const blob = await res.blob()
|
1009
|
+
//创建a标签进行下载
|
1010
|
+
const a = document.createElement('a')
|
1011
|
+
a.setAttribute('target', '_blank')
|
1012
|
+
a.setAttribute('href', URL.createObjectURL(blob))
|
1013
|
+
a.setAttribute('download', dom.getAttribute('data-editify-attachment-name')!)
|
1014
|
+
a.click()
|
1015
|
+
})
|
886
1016
|
})
|
887
1017
|
emits('updateview')
|
888
1018
|
}
|
@@ -919,28 +1049,14 @@ const undo = () => {
|
|
919
1049
|
if (isDisabled.value) {
|
920
1050
|
return
|
921
1051
|
}
|
922
|
-
|
923
|
-
if (historyRecord) {
|
924
|
-
editor.value!.history.current = historyRecord.current
|
925
|
-
editor.value!.stack = historyRecord.stack
|
926
|
-
editor.value!.range = historyRecord.range
|
927
|
-
editor.value!.domRender(true)
|
928
|
-
editor.value!.rangeRender()
|
929
|
-
}
|
1052
|
+
editor.value!.undo()
|
930
1053
|
}
|
931
1054
|
//api:重做
|
932
1055
|
const redo = () => {
|
933
1056
|
if (isDisabled.value) {
|
934
1057
|
return
|
935
1058
|
}
|
936
|
-
|
937
|
-
if (historyRecord) {
|
938
|
-
editor.value!.history.current = historyRecord.current
|
939
|
-
editor.value!.stack = historyRecord.stack
|
940
|
-
editor.value!.range = historyRecord.range
|
941
|
-
editor.value!.domRender(true)
|
942
|
-
editor.value!.rangeRender()
|
943
|
-
}
|
1059
|
+
editor.value!.redo()
|
944
1060
|
}
|
945
1061
|
|
946
1062
|
//监听编辑的值变更
|
@@ -46,7 +46,6 @@ import { SourceViewMenuButton } from '@/feature/sourceView'
|
|
46
46
|
import { FullScreenMenuButton } from '@/feature/fullScreen'
|
47
47
|
import { AttachmentMenuButton } from '@/feature/attachment'
|
48
48
|
import { MathformulaMenuButton } from '@/feature/mathformula'
|
49
|
-
import { PanelMenuButton } from '@/feature/panel'
|
50
49
|
import { InfoBlockMenuButton } from '@/feature/infoBlock'
|
51
50
|
|
52
51
|
defineOptions({
|
@@ -84,7 +83,7 @@ const menuNames = computed<string[]>(() => {
|
|
84
83
|
})
|
85
84
|
})
|
86
85
|
//内置菜单组件的数组
|
87
|
-
const defaultMenus = shallowRef([UndoMenuButton, RedoMenuButton, HeadingMenuButton, IndentMenuButton, QuoteMenuButton, SeparatorMenuButton, AlignMenuButton, OrderListMenuButton, UnorderListMenuButton, TaskMenuButton, BoldMenuButton, UnderlineMenuButton, ItalicMenuButton, StrikethroughMenuButton, CodeMenuButton, SuperMenuButton, SubMenuButton, FormatClearMenuButton, FontSizeMenuButton, FontFamilyMenuButton, LineHeightMenuButton, ForeColorMenuButton, BackColorMenuButton, LinkMenuButton, ImageMenuButton, VideoMenuButton, TableMenuButton, CodeBlockMenuButton, SourceViewMenuButton, FullScreenMenuButton, AttachmentMenuButton, MathformulaMenuButton,
|
86
|
+
const defaultMenus = shallowRef([UndoMenuButton, RedoMenuButton, HeadingMenuButton, IndentMenuButton, QuoteMenuButton, SeparatorMenuButton, AlignMenuButton, OrderListMenuButton, UnorderListMenuButton, TaskMenuButton, BoldMenuButton, UnderlineMenuButton, ItalicMenuButton, StrikethroughMenuButton, CodeMenuButton, SuperMenuButton, SubMenuButton, FormatClearMenuButton, FontSizeMenuButton, FontFamilyMenuButton, LineHeightMenuButton, ForeColorMenuButton, BackColorMenuButton, LinkMenuButton, ImageMenuButton, VideoMenuButton, TableMenuButton, CodeBlockMenuButton, SourceViewMenuButton, FullScreenMenuButton, AttachmentMenuButton, MathformulaMenuButton, InfoBlockMenuButton])
|
88
87
|
//根据菜单名称获取对应的内置菜单组件
|
89
88
|
const currentDefaultMenu = computed(() => {
|
90
89
|
return (name: string) => defaultMenus.value.find(item => item.name == `_${name}`)
|
@@ -128,7 +127,7 @@ const ExtendMenuButton = defineComponent(
|
|
128
127
|
zIndex: props.zIndex + 1,
|
129
128
|
ref: btnRef,
|
130
129
|
type: configuration.type || 'default',
|
131
|
-
title: configuration.title || ''
|
130
|
+
title: `${configuration.title || ''}${configuration.shortcut?.title ? `【${configuration.shortcut?.title}】` : ''}`,
|
132
131
|
leftBorder: configuration.leftBorder || false,
|
133
132
|
rightBorder: configuration.rightBorder || false,
|
134
133
|
hideScroll: configuration.hideScroll || false,
|
package/src/editify/props.ts
CHANGED
@@ -12,7 +12,7 @@ export type EditifyResizeParamsType = {
|
|
12
12
|
export type EditifyToolbarOptionsType = {
|
13
13
|
show: boolean
|
14
14
|
node: string | null
|
15
|
-
type: 'text' | 'link' | 'image' | 'video' | 'table' | 'codeBlock'
|
15
|
+
type: 'text' | 'link' | 'image' | 'video' | 'table' | 'codeBlock' | 'orderList' | 'unorderList'
|
16
16
|
}
|
17
17
|
|
18
18
|
export const EditifyProps = {
|
@@ -156,11 +156,6 @@ export const EditifyProps = {
|
|
156
156
|
type: Boolean,
|
157
157
|
default: false
|
158
158
|
},
|
159
|
-
//是否使用tab快捷键
|
160
|
-
tab: {
|
161
|
-
type: Boolean,
|
162
|
-
default: true
|
163
|
-
},
|
164
159
|
//是否使用深色模式
|
165
160
|
dark: {
|
166
161
|
type: Boolean,
|
@@ -19,10 +19,10 @@ export const ToolbarProps = {
|
|
19
19
|
},
|
20
20
|
//类型
|
21
21
|
type: {
|
22
|
-
type: String as PropType<'text' | 'table' | 'link' | 'codeBlock' | 'image' | 'video'>,
|
22
|
+
type: String as PropType<'text' | 'table' | 'link' | 'codeBlock' | 'image' | 'video' | 'orderList' | 'unorderList'>,
|
23
23
|
default: 'text',
|
24
24
|
validator(value: any) {
|
25
|
-
return ['text', 'table', 'link', 'codeBlock', 'image', 'video'].includes(value)
|
25
|
+
return ['text', 'table', 'link', 'codeBlock', 'image', 'video', 'orderList', 'unorderList'].includes(value)
|
26
26
|
}
|
27
27
|
},
|
28
28
|
//工具条配置
|