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/core/function.ts
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
*/
|
4
4
|
import { common as DapCommon } from 'dap-util'
|
5
5
|
import { AlexEditor, AlexElement, AlexElementsRangeType, AlexElementCreateConfigType } from 'alex-editor'
|
6
|
-
import
|
7
|
-
import {
|
6
|
+
import KaTex from 'katex'
|
7
|
+
import { queryHasValue, ObjectType } from './tool'
|
8
8
|
|
9
9
|
export type ElementMatchConfigType = {
|
10
10
|
parsedom?: string
|
@@ -12,6 +12,257 @@ export type ElementMatchConfigType = {
|
|
12
12
|
styles?: ObjectType
|
13
13
|
}
|
14
14
|
|
15
|
+
/** --------------------------------代码块操作相关函数------------------------------------------------ */
|
16
|
+
|
17
|
+
/**
|
18
|
+
* 更新代码块内的光标位置
|
19
|
+
* @param editor
|
20
|
+
* @param element
|
21
|
+
* @param originalTextElements
|
22
|
+
* @param newElements
|
23
|
+
* @returns
|
24
|
+
*/
|
25
|
+
export const updateRangeInPre = (editor: AlexEditor, element: AlexElement, originalTextElements: AlexElement[], newElements: AlexElement[]) => {
|
26
|
+
if (!editor.range) {
|
27
|
+
return
|
28
|
+
}
|
29
|
+
//如果虚拟光标的起点在代码块内对虚拟光标的起点进行重新定位
|
30
|
+
if (editor.range.anchor.element.getBlock().isEqual(element)) {
|
31
|
+
//获取起点所在文本元素的在所有文本元素中的序列
|
32
|
+
const elIndex = originalTextElements.findIndex(el => editor.range!.anchor.element.isEqual(el))
|
33
|
+
//起点在整个代码内容中的位置
|
34
|
+
const offset = originalTextElements.filter((_el, i) => i < elIndex).reduce((total, item) => total + item.textContent!.length, 0) + editor.range.anchor.offset
|
35
|
+
//获取pre下新的子孙元素中全部的文本元素
|
36
|
+
const newTextElements = AlexElement.flatElements(newElements).filter(el => el.isText() && !el.isEmpty())
|
37
|
+
let i = 0
|
38
|
+
let index = 0
|
39
|
+
//遍历
|
40
|
+
while (i < newTextElements.length) {
|
41
|
+
let newIndex = index + newTextElements[i].textContent!.length
|
42
|
+
if (offset >= index && offset <= newIndex) {
|
43
|
+
editor.range.anchor.element = newTextElements[i]
|
44
|
+
editor.range.anchor.offset = offset - index
|
45
|
+
break
|
46
|
+
}
|
47
|
+
i++
|
48
|
+
index = newIndex
|
49
|
+
}
|
50
|
+
}
|
51
|
+
//如果虚拟光标的终点在代码块内需要对虚拟光标的终点进行重新定位
|
52
|
+
if (editor.range.focus.element.getBlock().isEqual(element)) {
|
53
|
+
//获取终点所在文本元素的在所有文本元素中的序列
|
54
|
+
const elIndex = originalTextElements.findIndex(el => editor.range!.focus.element.isEqual(el))
|
55
|
+
//终点在整个代码内容中的位置
|
56
|
+
const offset = originalTextElements.filter((_el, i) => i < elIndex).reduce((total, item) => total + item.textContent!.length, 0) + editor.range.focus.offset
|
57
|
+
//获取全部的新文本元素
|
58
|
+
const newTextElements = AlexElement.flatElements(newElements).filter(el => el.isText() && !el.isEmpty())
|
59
|
+
let i = 0
|
60
|
+
let index = 0
|
61
|
+
//遍历
|
62
|
+
while (i < newTextElements.length) {
|
63
|
+
let newIndex = index + newTextElements[i].textContent!.length
|
64
|
+
if (offset >= index && offset <= newIndex) {
|
65
|
+
editor.range.focus.element = newTextElements[i]
|
66
|
+
editor.range.focus.offset = offset - index
|
67
|
+
break
|
68
|
+
}
|
69
|
+
i++
|
70
|
+
index = newIndex
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
/** --------------------------------表格操作相关函数--------------------------------------------- */
|
76
|
+
|
77
|
+
/**
|
78
|
+
* 自动隐藏被合并的单元格
|
79
|
+
* @param editor
|
80
|
+
* @param rowElements
|
81
|
+
*/
|
82
|
+
export const autoHideMergedTableCells = (editor: AlexEditor, rowElements: AlexElement[]) => {
|
83
|
+
const cells = AlexElement.flatElements(rowElements).filter(item => item.parsedom == 'td')
|
84
|
+
cells.forEach(cell => {
|
85
|
+
if (cell.hasMarks() && !cell.marks!['data-editify-merged']) {
|
86
|
+
//获取colspan
|
87
|
+
const colspan = isNaN(Number(cell.marks!['colspan'])) ? 1 : Number(cell.marks!['colspan'])
|
88
|
+
//获取rowspan
|
89
|
+
const rowspan = isNaN(Number(cell.marks!['rowspan'])) ? 1 : Number(cell.marks!['rowspan'])
|
90
|
+
//如果是跨列单元格,隐藏该单元格同行后的colspan-1个单元格
|
91
|
+
if (colspan > 1) {
|
92
|
+
let el = cell
|
93
|
+
let i = 1
|
94
|
+
while (i < colspan) {
|
95
|
+
const nextCell = editor.getNextElement(el)!
|
96
|
+
if (nextCell) {
|
97
|
+
if (nextCell.hasMarks()) {
|
98
|
+
nextCell.marks!['data-editify-merged'] = 'true'
|
99
|
+
} else {
|
100
|
+
nextCell.marks = {
|
101
|
+
'data-editify-merged': 'true'
|
102
|
+
}
|
103
|
+
}
|
104
|
+
el = nextCell
|
105
|
+
i++
|
106
|
+
} else {
|
107
|
+
break
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
//如果是跨行单元格,隐藏该单元格同列后的rowspan-1行单元格
|
112
|
+
if (rowspan > 1) {
|
113
|
+
const index = cell.parent!.children!.findIndex(item => item.isEqual(cell))
|
114
|
+
let el = cell
|
115
|
+
let i = 1
|
116
|
+
while (i < rowspan && el && editor.getNextElement(el.parent!)) {
|
117
|
+
const nextRow = editor.getNextElement(el.parent!)!
|
118
|
+
//根据跨行单元格占据的列数,在后的rowspan-1行中隐藏colspan个单元格
|
119
|
+
for (let j = index; j < index + colspan; j++) {
|
120
|
+
const current = nextRow.children![j]
|
121
|
+
if (current) {
|
122
|
+
if (current.hasMarks()) {
|
123
|
+
current.marks!['data-editify-merged'] = 'true'
|
124
|
+
} else {
|
125
|
+
current.marks = {
|
126
|
+
'data-editify-merged': 'true'
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
el = nextRow.children![index]
|
132
|
+
i++
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
})
|
137
|
+
}
|
138
|
+
|
139
|
+
/**
|
140
|
+
* 自动补全表格行和列
|
141
|
+
* @param editor
|
142
|
+
* @param rowElements
|
143
|
+
* @param rowNumber
|
144
|
+
* @param columnNumber
|
145
|
+
*/
|
146
|
+
export const autocompleteTableCells = (editor: AlexEditor, rowElements: AlexElement[], rowNumber: number, columnNumber: number) => {
|
147
|
+
//遍历所有的单元格
|
148
|
+
AlexElement.flatElements(rowElements).forEach(item => {
|
149
|
+
if (item.parsedom == 'td' && item.hasMarks()) {
|
150
|
+
//删除被合并的标识
|
151
|
+
if (item.marks!['data-editify-merged']) {
|
152
|
+
delete item.marks!['data-editify-merged']
|
153
|
+
}
|
154
|
+
//获取colspan
|
155
|
+
const colspan = isNaN(Number(item.marks!['colspan'])) ? 1 : Number(item.marks!['colspan'])
|
156
|
+
//获取rowspan
|
157
|
+
const rowspan = isNaN(Number(item.marks!['rowspan'])) ? 1 : Number(item.marks!['rowspan'])
|
158
|
+
//针对colspan>1的单元格在后面补全隐藏的单元格
|
159
|
+
if (colspan > 1) {
|
160
|
+
let i = 1
|
161
|
+
//补全的数量小于需要补全的数量并且列总数量小于理论数量
|
162
|
+
while (i < colspan && item.parent!.children!.length < columnNumber) {
|
163
|
+
const column = AlexElement.create({
|
164
|
+
type: 'inblock',
|
165
|
+
parsedom: 'td',
|
166
|
+
marks: {
|
167
|
+
'data-editify-merged': 'true'
|
168
|
+
},
|
169
|
+
children: [
|
170
|
+
{
|
171
|
+
type: 'closed',
|
172
|
+
parsedom: 'br'
|
173
|
+
}
|
174
|
+
]
|
175
|
+
})
|
176
|
+
editor.addElementAfter(column, item)
|
177
|
+
i++
|
178
|
+
}
|
179
|
+
}
|
180
|
+
//针对rowspan>1的单元格在后面的行中对应位置补全隐藏的单元格
|
181
|
+
if (rowspan > 1) {
|
182
|
+
let el = item
|
183
|
+
let i = 1
|
184
|
+
while (i < rowspan && editor.getNextElement(el.parent!) && editor.getNextElement(el.parent!)!.children!.length < columnNumber) {
|
185
|
+
//下一行
|
186
|
+
const nextRow = editor.getNextElement(el.parent!)!
|
187
|
+
//单元格在行中的序列
|
188
|
+
const index = el.parent!.children!.findIndex(item => item.isEqual(el))
|
189
|
+
//下一行对应的单元格
|
190
|
+
const nextCell = nextRow.children![index]
|
191
|
+
//根据当前单元格的跨列数补充符合跨列数的隐藏单元格
|
192
|
+
for (let j = 0; j < colspan; j++) {
|
193
|
+
const column = AlexElement.create({
|
194
|
+
type: 'inblock',
|
195
|
+
parsedom: 'td',
|
196
|
+
marks: {
|
197
|
+
'data-editify-merged': 'true'
|
198
|
+
},
|
199
|
+
children: [
|
200
|
+
{
|
201
|
+
type: 'closed',
|
202
|
+
parsedom: 'br'
|
203
|
+
}
|
204
|
+
]
|
205
|
+
})
|
206
|
+
if (nextCell) {
|
207
|
+
editor.addElementBefore(column, nextCell)
|
208
|
+
} else {
|
209
|
+
editor.addElementTo(column, nextRow, nextRow.children!.length)
|
210
|
+
}
|
211
|
+
}
|
212
|
+
el = nextRow.children![index]
|
213
|
+
i++
|
214
|
+
}
|
215
|
+
}
|
216
|
+
}
|
217
|
+
})
|
218
|
+
//遍历每一行,如果还缺少列则在后面补全列
|
219
|
+
rowElements.forEach(rowElement => {
|
220
|
+
//遍历该行的单元格获取总列数
|
221
|
+
const number = rowElement.children!.length
|
222
|
+
if (number < columnNumber) {
|
223
|
+
for (let i = 0; i < columnNumber - number; i++) {
|
224
|
+
const column = AlexElement.create({
|
225
|
+
type: 'inblock',
|
226
|
+
parsedom: 'td',
|
227
|
+
children: [
|
228
|
+
{
|
229
|
+
type: 'closed',
|
230
|
+
parsedom: 'br'
|
231
|
+
}
|
232
|
+
]
|
233
|
+
})
|
234
|
+
editor.addElementTo(column, rowElement, rowElement.children!.length)
|
235
|
+
}
|
236
|
+
}
|
237
|
+
})
|
238
|
+
//获取总行数
|
239
|
+
const length = rowElements.length
|
240
|
+
//判断总行数是否小于实际行数则补全行
|
241
|
+
if (length < rowNumber) {
|
242
|
+
for (let i = 0; i < rowNumber - length; i++) {
|
243
|
+
const children: AlexElementCreateConfigType[] = []
|
244
|
+
for (let j = 0; j < columnNumber; j++) {
|
245
|
+
children.push({
|
246
|
+
type: 'inblock',
|
247
|
+
parsedom: 'td',
|
248
|
+
children: [
|
249
|
+
{
|
250
|
+
type: 'closed',
|
251
|
+
parsedom: 'br'
|
252
|
+
}
|
253
|
+
]
|
254
|
+
})
|
255
|
+
}
|
256
|
+
const row = AlexElement.create({
|
257
|
+
type: 'inblock',
|
258
|
+
parsedom: 'tr',
|
259
|
+
children
|
260
|
+
})
|
261
|
+
rowElements.push(row)
|
262
|
+
}
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
15
266
|
/**
|
16
267
|
* 清空单元格的内容并隐藏
|
17
268
|
* @param editor
|
@@ -184,6 +435,8 @@ export const getTableSize = (rowElements: AlexElement[]) => {
|
|
184
435
|
}
|
185
436
|
}
|
186
437
|
|
438
|
+
/** --------------------------------通用的元素判断函数----------------------------------------------- */
|
439
|
+
|
187
440
|
/**
|
188
441
|
* Open API:判断元素是否符合指定的条件
|
189
442
|
* @param element
|
@@ -292,6 +545,8 @@ export const getMatchElementByRange = (editor: AlexEditor, dataRangeCaches: Alex
|
|
292
545
|
return null
|
293
546
|
}
|
294
547
|
|
548
|
+
/** --------------------------------列表判断函数---------------------------------------------------------- */
|
549
|
+
|
295
550
|
/**
|
296
551
|
* Open API:判断元素是否有序或者无序列表,不做空元素判断
|
297
552
|
* @param element
|
@@ -360,6 +615,8 @@ export const rangeIsInList = (editor: AlexEditor, dataRangeCaches: AlexElementsR
|
|
360
615
|
})
|
361
616
|
}
|
362
617
|
|
618
|
+
/** --------------------------------任务列表判断函数----------------------------------------------- */
|
619
|
+
|
363
620
|
/**
|
364
621
|
* Open API:判断元素是否任务列表,不做空元素判断
|
365
622
|
* @param element
|
@@ -424,6 +681,8 @@ export const rangeIsInTask = (editor: AlexEditor, dataRangeCaches: AlexElementsR
|
|
424
681
|
})
|
425
682
|
}
|
426
683
|
|
684
|
+
/** --------------------------------附件判断函数------------------------------------------------- */
|
685
|
+
|
427
686
|
/**
|
428
687
|
* Open API:判断元素是否附件,不做空元素判断
|
429
688
|
* @param element
|
@@ -456,6 +715,8 @@ export const hasAttachmentInRange = (editor: AlexEditor, dataRangeCaches: AlexEl
|
|
456
715
|
})
|
457
716
|
}
|
458
717
|
|
718
|
+
/** --------------------------------数学公式判断函数--------------------------------------------- */
|
719
|
+
|
459
720
|
/**
|
460
721
|
* Open API:判断元素是否数学公式,不做空元素判断
|
461
722
|
* @param element
|
@@ -502,51 +763,7 @@ export const hasMathformulaInRange = (editor: AlexEditor, dataRangeCaches: AlexE
|
|
502
763
|
})
|
503
764
|
}
|
504
765
|
|
505
|
-
/**
|
506
|
-
* Open API:判断元素是否面板,不做空元素判断
|
507
|
-
* @param el
|
508
|
-
* @returns
|
509
|
-
*/
|
510
|
-
export const elementIsPanel = (element: AlexElement) => {
|
511
|
-
return elementIsMatch(element, {
|
512
|
-
parsedom: 'div',
|
513
|
-
marks: {
|
514
|
-
'data-editify-panel': true
|
515
|
-
}
|
516
|
-
})
|
517
|
-
}
|
518
|
-
|
519
|
-
/**
|
520
|
-
* Open API:判断元素是否在面板内,是的话返回面板元素,否则返回null
|
521
|
-
* @param el
|
522
|
-
* @returns
|
523
|
-
*/
|
524
|
-
export const getPanelByElement = (element: AlexElement): AlexElement | null => {
|
525
|
-
return getMatchElementByElement(element, {
|
526
|
-
parsedom: 'div',
|
527
|
-
marks: {
|
528
|
-
'data-editify-panel': true
|
529
|
-
}
|
530
|
-
})
|
531
|
-
}
|
532
|
-
|
533
|
-
/**
|
534
|
-
* Open API:选区是否含有面板,不一定是同一个面板,只要含有面板即返回true
|
535
|
-
* @param editor
|
536
|
-
* @param dataRangeCaches
|
537
|
-
* @returns
|
538
|
-
*/
|
539
|
-
export const hasPanelInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
540
|
-
if (!editor.range) {
|
541
|
-
return false
|
542
|
-
}
|
543
|
-
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
544
|
-
return !!getPanelByElement(editor.range.anchor.element)
|
545
|
-
}
|
546
|
-
return dataRangeCaches.flatList.some(item => {
|
547
|
-
return !!getPanelByElement(item.element)
|
548
|
-
})
|
549
|
-
}
|
766
|
+
/** --------------------------------信息块判断函数---------------------------------------------- */
|
550
767
|
|
551
768
|
/**
|
552
769
|
* Open API:判断元素是否信息块,不做空元素判断
|
@@ -612,6 +829,8 @@ export const rangeIsInInfoBlock = (editor: AlexEditor, dataRangeCaches: AlexElem
|
|
612
829
|
})
|
613
830
|
}
|
614
831
|
|
832
|
+
/** --------------------------------代码块判断函数------------------------------------------------ */
|
833
|
+
|
615
834
|
/**
|
616
835
|
* Open API:选区是否含有代码块,不一定是同一个代码块,只要含有代码块即返回true
|
617
836
|
* @param editor
|
@@ -630,6 +849,28 @@ export const hasPreInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsR
|
|
630
849
|
})
|
631
850
|
}
|
632
851
|
|
852
|
+
/** --------------------------------表格判断函数------------------------------------------------- */
|
853
|
+
|
854
|
+
/**
|
855
|
+
* Open API:选区是否含有表格,不一定是同一个表格,只要含有表格即返回true
|
856
|
+
* @param editor
|
857
|
+
* @param dataRangeCaches
|
858
|
+
* @returns
|
859
|
+
*/
|
860
|
+
export const hasTableInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
861
|
+
if (!editor.range) {
|
862
|
+
return false
|
863
|
+
}
|
864
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
865
|
+
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'table' })
|
866
|
+
}
|
867
|
+
return dataRangeCaches.flatList.some(item => {
|
868
|
+
return !!getMatchElementByElement(item.element, { parsedom: 'table' })
|
869
|
+
})
|
870
|
+
}
|
871
|
+
|
872
|
+
/** --------------------------------引用判断函数----------------------------------------------- */
|
873
|
+
|
633
874
|
/**
|
634
875
|
* Open API:选区是否含有引用,不一定是同一个引用,只要含有引用即返回true
|
635
876
|
* @param editor
|
@@ -649,41 +890,45 @@ export const hasQuoteInRange = (editor: AlexEditor, dataRangeCaches: AlexElement
|
|
649
890
|
}
|
650
891
|
|
651
892
|
/**
|
652
|
-
* Open API
|
893
|
+
* Open API:选区是否全部在引用内,不一定是同一个引用
|
653
894
|
* @param editor
|
654
895
|
* @param dataRangeCaches
|
655
896
|
* @returns
|
656
897
|
*/
|
657
|
-
export const
|
898
|
+
export const rangeIsInQuote = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
658
899
|
if (!editor.range) {
|
659
900
|
return false
|
660
901
|
}
|
661
902
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
662
|
-
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: '
|
903
|
+
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'blockquote' })
|
663
904
|
}
|
664
|
-
return dataRangeCaches.
|
665
|
-
return !!getMatchElementByElement(item.element, { parsedom: '
|
905
|
+
return dataRangeCaches.list.every(item => {
|
906
|
+
return !!getMatchElementByElement(item.element, { parsedom: 'blockquote' })
|
666
907
|
})
|
667
908
|
}
|
668
909
|
|
910
|
+
/** --------------------------------链接判断函数-------------------------------------------------- */
|
911
|
+
|
669
912
|
/**
|
670
|
-
* Open API
|
913
|
+
* Open API:选区是否含有链接,不一定是同一个链接,只要含有链接即返回true
|
671
914
|
* @param editor
|
672
915
|
* @param dataRangeCaches
|
673
916
|
* @returns
|
674
917
|
*/
|
675
|
-
export const
|
918
|
+
export const hasLinkInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
676
919
|
if (!editor.range) {
|
677
920
|
return false
|
678
921
|
}
|
679
922
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
680
|
-
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: '
|
923
|
+
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'a' })
|
681
924
|
}
|
682
925
|
return dataRangeCaches.flatList.some(item => {
|
683
|
-
return !!getMatchElementByElement(item.element, { parsedom: '
|
926
|
+
return !!getMatchElementByElement(item.element, { parsedom: 'a' })
|
684
927
|
})
|
685
928
|
}
|
686
929
|
|
930
|
+
/** --------------------------------图片视频判断函数--------------------------------------------- */
|
931
|
+
|
687
932
|
/**
|
688
933
|
* Open API:选区是否含有图片,不一定是同一个图片,只要含有图片即返回true
|
689
934
|
* @param editor
|
@@ -720,22 +965,72 @@ export const hasVideoInRange = (editor: AlexEditor, dataRangeCaches: AlexElement
|
|
720
965
|
})
|
721
966
|
}
|
722
967
|
|
968
|
+
/** --------------------文本元素标记和样式相关函数--------------------------------------- */
|
969
|
+
|
723
970
|
/**
|
724
|
-
*
|
971
|
+
* 获取光标选取内的扁平化元素数组(可能会分割文本元素导致stack变更,同时也会更新选取元素和光标位置)
|
725
972
|
* @param editor
|
726
973
|
* @param dataRangeCaches
|
727
974
|
* @returns
|
728
975
|
*/
|
729
|
-
export const
|
976
|
+
export const getFlatElementsByRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
730
977
|
if (!editor.range) {
|
731
|
-
return
|
978
|
+
return []
|
732
979
|
}
|
733
|
-
|
734
|
-
|
980
|
+
//获取选区数据的长度
|
981
|
+
let length = dataRangeCaches.flatList.length
|
982
|
+
//返回的元素数组
|
983
|
+
let elements = []
|
984
|
+
//遍历选区数据
|
985
|
+
for (let i = 0; i < length; i++) {
|
986
|
+
const item = dataRangeCaches.flatList[i]
|
987
|
+
//如果存在offset那么一定是文本元素
|
988
|
+
if (item.offset) {
|
989
|
+
let selectEl = null
|
990
|
+
//文本元素前面一部分在光标范围内
|
991
|
+
if (item.offset[0] == 0 && item.offset[1] < item.element.textContent!.length) {
|
992
|
+
const el = item.element.clone()
|
993
|
+
item.element.textContent = item.element.textContent!.substring(0, item.offset[1])
|
994
|
+
el.textContent = el.textContent!.substring(item.offset[1])
|
995
|
+
editor.addElementAfter(el, item.element)
|
996
|
+
selectEl = item.element
|
997
|
+
}
|
998
|
+
//文本元素后面一部分在光标范围内
|
999
|
+
else if (item.offset[1] == item.element.textContent!.length && item.offset[0] > 0) {
|
1000
|
+
const el = item.element.clone()
|
1001
|
+
item.element.textContent = item.element.textContent!.substring(0, item.offset[0])
|
1002
|
+
el.textContent = el.textContent!.substring(item.offset[0])
|
1003
|
+
editor.addElementAfter(el, item.element)
|
1004
|
+
selectEl = el
|
1005
|
+
}
|
1006
|
+
//文本元素的中间一部分在光标范围内
|
1007
|
+
else if (item.offset[0] > 0 && item.offset[1] < item.element.textContent!.length) {
|
1008
|
+
const el = item.element.clone()
|
1009
|
+
const el2 = item.element.clone()
|
1010
|
+
item.element.textContent = item.element.textContent!.substring(0, item.offset[0])
|
1011
|
+
el.textContent = el.textContent!.substring(item.offset[0], item.offset[1])
|
1012
|
+
el2.textContent = el2.textContent!.substring(item.offset[1])
|
1013
|
+
editor.addElementAfter(el, item.element)
|
1014
|
+
editor.addElementAfter(el2, el)
|
1015
|
+
selectEl = el
|
1016
|
+
}
|
1017
|
+
//如果selectEl存在证明文本元素被分割了
|
1018
|
+
if (selectEl) {
|
1019
|
+
//如果i为0的话肯定是起点
|
1020
|
+
if (i == 0) {
|
1021
|
+
editor.range.anchor.moveToStart(selectEl)
|
1022
|
+
}
|
1023
|
+
//如果i是最后一个序列的话肯定是终点
|
1024
|
+
if (i == length - 1) {
|
1025
|
+
editor.range.focus.moveToEnd(selectEl)
|
1026
|
+
}
|
1027
|
+
elements.push(selectEl)
|
1028
|
+
}
|
1029
|
+
} else {
|
1030
|
+
elements.push(item.element)
|
1031
|
+
}
|
735
1032
|
}
|
736
|
-
return
|
737
|
-
return !!getMatchElementByElement(item.element, { parsedom: 'blockquote' })
|
738
|
-
})
|
1033
|
+
return elements
|
739
1034
|
}
|
740
1035
|
|
741
1036
|
/**
|
@@ -780,132 +1075,287 @@ export const queryTextStyle = (editor: AlexEditor, dataRangeCaches: AlexElements
|
|
780
1075
|
}
|
781
1076
|
|
782
1077
|
/**
|
783
|
-
* Open API
|
1078
|
+
* Open API:设置文本元素的样式
|
784
1079
|
* @param editor
|
785
1080
|
* @param dataRangeCaches
|
786
|
-
* @param
|
787
|
-
* @param value
|
1081
|
+
* @param styles 值为{ 'font-weight':'bold' }这类格式
|
788
1082
|
* @returns
|
789
1083
|
*/
|
790
|
-
export const
|
1084
|
+
export const setTextStyle = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, styles: ObjectType) => {
|
791
1085
|
if (!editor.range) {
|
792
|
-
return
|
1086
|
+
return
|
793
1087
|
}
|
794
1088
|
//起点和终点在一起
|
795
1089
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
796
|
-
|
797
|
-
if (editor.range.anchor.element.
|
798
|
-
|
1090
|
+
//如果是空白文本元素直接设置样式
|
1091
|
+
if (editor.range.anchor.element.isSpaceText()) {
|
1092
|
+
if (editor.range.anchor.element.hasStyles()) {
|
1093
|
+
Object.assign(editor.range.anchor.element.styles!, DapCommon.clone(styles))
|
1094
|
+
} else {
|
1095
|
+
editor.range.anchor.element.styles = DapCommon.clone(styles)
|
1096
|
+
}
|
799
1097
|
}
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
return queryHasValue(item.element.marks!, name, value)
|
1098
|
+
//如果是文本元素
|
1099
|
+
else if (editor.range.anchor.element.isText()) {
|
1100
|
+
//新建一个空白文本元素
|
1101
|
+
const el = AlexElement.getSpaceElement()
|
1102
|
+
//继承文本元素的样式和标记
|
1103
|
+
el.styles = DapCommon.clone(editor.range.anchor.element.styles)
|
1104
|
+
el.marks = DapCommon.clone(editor.range.anchor.element.marks)
|
1105
|
+
//设置样式
|
1106
|
+
if (el.hasStyles()) {
|
1107
|
+
Object.assign(el.styles!, DapCommon.clone(styles))
|
1108
|
+
} else {
|
1109
|
+
el.styles = DapCommon.clone(styles)
|
1110
|
+
}
|
1111
|
+
//插入空白文本元素
|
1112
|
+
editor.insertElement(el)
|
816
1113
|
}
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
1114
|
+
//如果是自闭合元素
|
1115
|
+
else {
|
1116
|
+
const el = AlexElement.getSpaceElement()
|
1117
|
+
el.styles = DapCommon.clone(styles)
|
1118
|
+
editor.insertElement(el)
|
1119
|
+
}
|
1120
|
+
}
|
1121
|
+
//不在同一个点
|
1122
|
+
else {
|
1123
|
+
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1124
|
+
elements.forEach(ele => {
|
1125
|
+
if (ele.isText()) {
|
1126
|
+
if (ele.hasStyles()) {
|
1127
|
+
Object.assign(ele.styles!, DapCommon.clone(styles))
|
1128
|
+
} else {
|
1129
|
+
ele.styles = DapCommon.clone(styles)
|
1130
|
+
}
|
1131
|
+
}
|
1132
|
+
})
|
1133
|
+
}
|
821
1134
|
}
|
822
1135
|
|
823
1136
|
/**
|
824
|
-
* Open API
|
1137
|
+
* Open API:移除文本元素的样式
|
1138
|
+
* @param editor
|
825
1139
|
* @param dataRangeCaches
|
1140
|
+
* @param styleNames 样式名称数组,如果不存在则移除全部样式
|
826
1141
|
* @returns
|
827
1142
|
*/
|
828
|
-
export const
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
1143
|
+
export const removeTextStyle = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, styleNames?: string[]) => {
|
1144
|
+
if (!editor.range) {
|
1145
|
+
return
|
1146
|
+
}
|
1147
|
+
//移除样式的方法
|
1148
|
+
const removeFn = (el: AlexElement) => {
|
1149
|
+
//如果参数是数组,表示删除指定的样式
|
1150
|
+
if (Array.isArray(styleNames)) {
|
1151
|
+
if (el.hasStyles()) {
|
1152
|
+
let styles: ObjectType = {}
|
1153
|
+
Object.keys(el.styles!).forEach(key => {
|
1154
|
+
if (!styleNames.includes(key)) {
|
1155
|
+
styles[key] = el.styles![key]
|
1156
|
+
}
|
1157
|
+
})
|
1158
|
+
el.styles = styles
|
1159
|
+
}
|
1160
|
+
}
|
1161
|
+
//如果没有参数,则表示删除所有的样式
|
1162
|
+
else {
|
1163
|
+
el.styles = null
|
1164
|
+
}
|
1165
|
+
}
|
1166
|
+
//如果起点和终点在一起
|
1167
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1168
|
+
//如果是空白文本元素直接移除样式
|
1169
|
+
if (editor.range.anchor.element.isSpaceText()) {
|
1170
|
+
removeFn(editor.range.anchor.element)
|
1171
|
+
}
|
1172
|
+
//如果是文本元素则新建一个空白文本元素
|
1173
|
+
else if (editor.range.anchor.element.isText()) {
|
1174
|
+
const el = AlexElement.getSpaceElement()
|
1175
|
+
//继承文本元素的样式和标记
|
1176
|
+
el.styles = DapCommon.clone(editor.range.anchor.element.styles)
|
1177
|
+
el.marks = DapCommon.clone(editor.range.anchor.element.marks)
|
1178
|
+
//移除样式
|
1179
|
+
removeFn(el)
|
1180
|
+
//插入
|
1181
|
+
editor.insertElement(el)
|
1182
|
+
}
|
1183
|
+
}
|
1184
|
+
//起点和终点不在一起
|
1185
|
+
else {
|
1186
|
+
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1187
|
+
elements.forEach(ele => {
|
1188
|
+
if (ele.isText()) {
|
1189
|
+
removeFn(ele)
|
837
1190
|
}
|
1191
|
+
})
|
1192
|
+
}
|
1193
|
+
}
|
1194
|
+
|
1195
|
+
/**
|
1196
|
+
* Open API:查询光标所在的文本元素是否具有某个标记
|
1197
|
+
* @param editor
|
1198
|
+
* @param dataRangeCaches
|
1199
|
+
* @param name
|
1200
|
+
* @param value
|
1201
|
+
* @returns
|
1202
|
+
*/
|
1203
|
+
export const queryTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, name: string, value?: string | number) => {
|
1204
|
+
if (!editor.range) {
|
1205
|
+
return false
|
1206
|
+
}
|
1207
|
+
//起点和终点在一起
|
1208
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1209
|
+
//如果是文本元素并且具有标记
|
1210
|
+
if (editor.range.anchor.element.isText() && editor.range.anchor.element.hasMarks()) {
|
1211
|
+
return queryHasValue(editor.range.anchor.element.marks!, name, value)
|
838
1212
|
}
|
1213
|
+
//不是文本元素或者没有标记直接返回
|
1214
|
+
return false
|
1215
|
+
}
|
1216
|
+
//起点和终点不在一起获取选区中的文本元素
|
1217
|
+
let result = dataRangeCaches.flatList.filter(item => {
|
1218
|
+
return item.element.isText()
|
839
1219
|
})
|
840
|
-
|
1220
|
+
//如果不包含文本元素直接返回false
|
1221
|
+
if (result.length == 0) {
|
1222
|
+
return false
|
1223
|
+
}
|
1224
|
+
//判断每个文本元素是否都具有该标记
|
1225
|
+
let flag = result.every(item => {
|
1226
|
+
//文本元素含有标记进一步判断
|
1227
|
+
if (item.element.hasMarks()) {
|
1228
|
+
return queryHasValue(item.element.marks!, name, value)
|
1229
|
+
}
|
1230
|
+
//文本元素没有标记直接返回false
|
1231
|
+
return false
|
1232
|
+
})
|
1233
|
+
return flag
|
841
1234
|
}
|
842
1235
|
|
843
1236
|
/**
|
844
|
-
*
|
1237
|
+
* Open API:设置文本元素的标记
|
845
1238
|
* @param editor
|
846
1239
|
* @param dataRangeCaches
|
1240
|
+
* @param marks 值为{ 'class':'a' }这类格式
|
847
1241
|
* @returns
|
848
1242
|
*/
|
849
|
-
export const
|
1243
|
+
export const setTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, marks: ObjectType) => {
|
850
1244
|
if (!editor.range) {
|
851
|
-
return
|
1245
|
+
return
|
852
1246
|
}
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
if (item.offset[0] == 0 && item.offset[1] < item.element.textContent!.length) {
|
865
|
-
const el = item.element.clone()
|
866
|
-
item.element.textContent = item.element.textContent!.substring(0, item.offset[1])
|
867
|
-
el.textContent = el.textContent!.substring(item.offset[1])
|
868
|
-
editor.addElementAfter(el, item.element)
|
869
|
-
selectEl = item.element
|
870
|
-
}
|
871
|
-
//文本元素后面一部分在光标范围内
|
872
|
-
else if (item.offset[1] == item.element.textContent!.length && item.offset[0] > 0) {
|
873
|
-
const el = item.element.clone()
|
874
|
-
item.element.textContent = item.element.textContent!.substring(0, item.offset[0])
|
875
|
-
el.textContent = el.textContent!.substring(item.offset[0])
|
876
|
-
editor.addElementAfter(el, item.element)
|
877
|
-
selectEl = el
|
1247
|
+
if (!DapCommon.isObject(marks)) {
|
1248
|
+
throw new Error('The argument must be an object')
|
1249
|
+
}
|
1250
|
+
//起点和终点在一起
|
1251
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1252
|
+
//如果是空白文本元素直接设置标记
|
1253
|
+
if (editor.range.anchor.element.isSpaceText()) {
|
1254
|
+
if (editor.range.anchor.element.hasMarks()) {
|
1255
|
+
Object.assign(editor.range.anchor.element.marks!, DapCommon.clone(marks))
|
1256
|
+
} else {
|
1257
|
+
editor.range.anchor.element.marks = DapCommon.clone(marks)
|
878
1258
|
}
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
1259
|
+
}
|
1260
|
+
//如果是文本元素
|
1261
|
+
else if (editor.range.anchor.element.isText()) {
|
1262
|
+
//新建一个空白文本元素
|
1263
|
+
const el = AlexElement.getSpaceElement()
|
1264
|
+
//继承文本元素的样式和标记
|
1265
|
+
el.styles = DapCommon.clone(editor.range.anchor.element.styles)
|
1266
|
+
el.marks = DapCommon.clone(editor.range.anchor.element.marks)
|
1267
|
+
//设置标记
|
1268
|
+
if (el.hasMarks()) {
|
1269
|
+
Object.assign(el.marks!, DapCommon.clone(marks))
|
1270
|
+
} else {
|
1271
|
+
el.marks = DapCommon.clone(marks)
|
889
1272
|
}
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
1273
|
+
//插入空白文本元素
|
1274
|
+
editor.insertElement(el)
|
1275
|
+
}
|
1276
|
+
//如果是自闭合元素
|
1277
|
+
else {
|
1278
|
+
const el = AlexElement.getSpaceElement()
|
1279
|
+
el.marks = DapCommon.clone(marks)
|
1280
|
+
editor.insertElement(el)
|
1281
|
+
}
|
1282
|
+
}
|
1283
|
+
//不在同一个点
|
1284
|
+
else {
|
1285
|
+
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1286
|
+
elements.forEach(ele => {
|
1287
|
+
if (ele.isText()) {
|
1288
|
+
if (ele.hasMarks()) {
|
1289
|
+
Object.assign(ele.marks!, DapCommon.clone(marks))
|
1290
|
+
} else {
|
1291
|
+
ele.marks = DapCommon.clone(marks)
|
899
1292
|
}
|
900
|
-
elements.push(selectEl)
|
901
1293
|
}
|
902
|
-
}
|
903
|
-
|
1294
|
+
})
|
1295
|
+
}
|
1296
|
+
}
|
1297
|
+
|
1298
|
+
/**
|
1299
|
+
* Open API:移除文本元素的标记
|
1300
|
+
* @param editor
|
1301
|
+
* @param dataRangeCaches
|
1302
|
+
* @param markNames 标记名称数组,如果不存在则移除全部标记
|
1303
|
+
* @returns
|
1304
|
+
*/
|
1305
|
+
export const removeTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, markNames?: string[]) => {
|
1306
|
+
if (!editor.range) {
|
1307
|
+
return
|
1308
|
+
}
|
1309
|
+
//移除样式的方法
|
1310
|
+
const removeFn = (el: AlexElement) => {
|
1311
|
+
//如果参数是数组,表示删除指定的样式
|
1312
|
+
if (Array.isArray(markNames)) {
|
1313
|
+
if (el.hasMarks()) {
|
1314
|
+
let marks: ObjectType = {}
|
1315
|
+
Object.keys(el.marks!).forEach(key => {
|
1316
|
+
if (!markNames.includes(key)) {
|
1317
|
+
marks[key] = el.marks![key]
|
1318
|
+
}
|
1319
|
+
})
|
1320
|
+
el.marks = marks
|
1321
|
+
}
|
1322
|
+
}
|
1323
|
+
//如果没有参数,则表示删除所有的样式
|
1324
|
+
else {
|
1325
|
+
el.marks = null
|
904
1326
|
}
|
905
1327
|
}
|
906
|
-
|
1328
|
+
//如果起点和终点在一起
|
1329
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1330
|
+
//如果是空白文本元素直接移除标记
|
1331
|
+
if (editor.range.anchor.element.isSpaceText()) {
|
1332
|
+
removeFn(editor.range.anchor.element)
|
1333
|
+
}
|
1334
|
+
//如果是文本元素则新建一个空白文本元素
|
1335
|
+
else if (editor.range.anchor.element.isText()) {
|
1336
|
+
const el = AlexElement.getSpaceElement()
|
1337
|
+
//继承文本元素的样式和标记
|
1338
|
+
el.styles = DapCommon.clone(editor.range.anchor.element.styles)
|
1339
|
+
el.marks = DapCommon.clone(editor.range.anchor.element.marks)
|
1340
|
+
//移除标记
|
1341
|
+
removeFn(el)
|
1342
|
+
//插入
|
1343
|
+
editor.insertElement(el)
|
1344
|
+
}
|
1345
|
+
}
|
1346
|
+
//起点和终点不在一起
|
1347
|
+
else {
|
1348
|
+
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1349
|
+
elements.forEach(ele => {
|
1350
|
+
if (ele.isText()) {
|
1351
|
+
removeFn(ele)
|
1352
|
+
}
|
1353
|
+
})
|
1354
|
+
}
|
907
1355
|
}
|
908
1356
|
|
1357
|
+
/** --------------------------------元素转换函数-------------------------------------------------- */
|
1358
|
+
|
909
1359
|
/**
|
910
1360
|
* 将某个元素转为段落标签
|
911
1361
|
* @param element
|
@@ -957,22 +1407,70 @@ export const elementToTask = (element: AlexElement) => {
|
|
957
1407
|
element.marks!['data-editify-task'] = 'uncheck'
|
958
1408
|
}
|
959
1409
|
|
1410
|
+
/** --------------------------------封装的功能函数----------------------------------------------- */
|
1411
|
+
|
1412
|
+
/**
|
1413
|
+
* Open API:获取选区内的文字内容
|
1414
|
+
* @param dataRangeCaches
|
1415
|
+
* @returns
|
1416
|
+
*/
|
1417
|
+
export const getRangeText = (dataRangeCaches: AlexElementsRangeType) => {
|
1418
|
+
//存在选区的情况下预置链接文本值
|
1419
|
+
let text = ''
|
1420
|
+
dataRangeCaches.flatList.forEach(item => {
|
1421
|
+
if (item.element.isText()) {
|
1422
|
+
if (item.offset) {
|
1423
|
+
text += item.element.textContent!.substring(item.offset[0], item.offset[1])
|
1424
|
+
} else {
|
1425
|
+
text += item.element.textContent || ''
|
1426
|
+
}
|
1427
|
+
}
|
1428
|
+
})
|
1429
|
+
return text
|
1430
|
+
}
|
1431
|
+
|
960
1432
|
/**
|
961
|
-
*
|
1433
|
+
* Open API:给元素两侧加上空白文本元素
|
1434
|
+
* @param editor
|
1435
|
+
* @param element
|
1436
|
+
*/
|
1437
|
+
export const addSpaceTextToBothSides = (editor: AlexEditor, element: AlexElement) => {
|
1438
|
+
const previousElement = editor.getPreviousElement(element)
|
1439
|
+
const newTextElement = editor.getNextElement(element)
|
1440
|
+
//如果不存在前一个元素或者前一个元素不是空白元素则设置空白元素
|
1441
|
+
if (!previousElement || !previousElement.isSpaceText()) {
|
1442
|
+
const spaceText = AlexElement.getSpaceElement()
|
1443
|
+
editor.addElementBefore(spaceText, element)
|
1444
|
+
}
|
1445
|
+
//如果不存在后一个元素或者后一个元素不是空白元素则设置空白元素
|
1446
|
+
if (!newTextElement || !newTextElement.isSpaceText()) {
|
1447
|
+
const spaceText = AlexElement.getSpaceElement()
|
1448
|
+
editor.addElementAfter(spaceText, element)
|
1449
|
+
}
|
1450
|
+
//如果光标在视频上则更新光标位置
|
1451
|
+
if (editor.range && element.isContains(editor.range.anchor.element)) {
|
1452
|
+
editor.range.anchor.moveToEnd(editor.getNextElement(element)!)
|
1453
|
+
}
|
1454
|
+
if (editor.range && element.isContains(editor.range.focus.element)) {
|
1455
|
+
editor.range.focus.moveToEnd(editor.getNextElement(element)!)
|
1456
|
+
}
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
/** --------------------------------菜单功能函数----------------------------------------------------- */
|
1460
|
+
|
1461
|
+
/**
|
1462
|
+
* Open API:设置标题,支持h1-h6和p
|
962
1463
|
* @param editor
|
963
1464
|
* @param dataRangeCaches
|
964
1465
|
* @param editTrans
|
965
1466
|
* @param parsedom
|
966
1467
|
* @returns
|
967
1468
|
*/
|
968
|
-
export const setHeading = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType,
|
1469
|
+
export const setHeading = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, parsedom: string) => {
|
969
1470
|
if (!editor.range) {
|
970
1471
|
return
|
971
1472
|
}
|
972
|
-
|
973
|
-
return (<ButtonOptionsItemType>item).value
|
974
|
-
})
|
975
|
-
if (!values.includes(parsedom)) {
|
1473
|
+
if (!['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'].includes(parsedom)) {
|
976
1474
|
throw new Error('The parameter supports only h1-h6 and p')
|
977
1475
|
}
|
978
1476
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
@@ -1130,266 +1628,62 @@ export const setQuote = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeT
|
|
1130
1628
|
* Open API:设置对齐方式
|
1131
1629
|
* @param editor
|
1132
1630
|
* @param dataRangeCaches
|
1133
|
-
* @param value 取值justify/left/right/center
|
1134
|
-
* @returns
|
1135
|
-
*/
|
1136
|
-
export const setAlign = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, value: 'justify' | 'left' | 'right' | 'center') => {
|
1137
|
-
if (!editor.range) {
|
1138
|
-
return
|
1139
|
-
}
|
1140
|
-
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1141
|
-
const block = editor.range.anchor.element.getBlock()
|
1142
|
-
const inblock = editor.range.anchor.element.getInblock()
|
1143
|
-
if (inblock) {
|
1144
|
-
if (inblock.hasStyles()) {
|
1145
|
-
inblock.styles!['text-align'] = value
|
1146
|
-
} else {
|
1147
|
-
inblock.styles = {
|
1148
|
-
'text-align': value
|
1149
|
-
}
|
1150
|
-
}
|
1151
|
-
} else {
|
1152
|
-
if (block.hasStyles()) {
|
1153
|
-
block.styles!['text-align'] = value
|
1154
|
-
} else {
|
1155
|
-
block.styles = {
|
1156
|
-
'text-align': value
|
1157
|
-
}
|
1158
|
-
}
|
1159
|
-
}
|
1160
|
-
} else {
|
1161
|
-
dataRangeCaches.list.forEach(el => {
|
1162
|
-
if (el.element.isBlock() || el.element.isInblock()) {
|
1163
|
-
if (el.element.hasStyles()) {
|
1164
|
-
el.element.styles!['text-align'] = value
|
1165
|
-
} else {
|
1166
|
-
el.element.styles = {
|
1167
|
-
'text-align': value
|
1168
|
-
}
|
1169
|
-
}
|
1170
|
-
} else {
|
1171
|
-
const block = el.element.getBlock()
|
1172
|
-
const inblock = el.element.getInblock()
|
1173
|
-
if (inblock) {
|
1174
|
-
if (inblock.hasStyles()) {
|
1175
|
-
inblock.styles!['text-align'] = value
|
1176
|
-
} else {
|
1177
|
-
inblock.styles = {
|
1178
|
-
'text-align': value
|
1179
|
-
}
|
1180
|
-
}
|
1181
|
-
} else {
|
1182
|
-
if (block.hasStyles()) {
|
1183
|
-
block.styles!['text-align'] = value
|
1184
|
-
} else {
|
1185
|
-
block.styles = {
|
1186
|
-
'text-align': value
|
1187
|
-
}
|
1188
|
-
}
|
1189
|
-
}
|
1190
|
-
}
|
1191
|
-
})
|
1192
|
-
}
|
1193
|
-
}
|
1194
|
-
|
1195
|
-
/**
|
1196
|
-
* Open API:插入或者取消 有序或者无序列表
|
1197
|
-
* @param editor
|
1198
|
-
* @param dataRangeCaches
|
1199
|
-
* @param ordered 为true表示有序列表
|
1200
|
-
* @returns
|
1201
|
-
*/
|
1202
|
-
export const setList = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, ordered: boolean) => {
|
1203
|
-
if (!editor.range) {
|
1204
|
-
return
|
1205
|
-
}
|
1206
|
-
//是否都在列表内
|
1207
|
-
const flag = rangeIsInList(editor, dataRangeCaches, ordered)
|
1208
|
-
//起点和终点在一起
|
1209
|
-
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1210
|
-
const block = editor.range.anchor.element.getBlock()
|
1211
|
-
if (flag) {
|
1212
|
-
elementToParagraph(block)
|
1213
|
-
} else {
|
1214
|
-
elementToList(block, ordered)
|
1215
|
-
}
|
1216
|
-
}
|
1217
|
-
//起点和终点不在一起
|
1218
|
-
else {
|
1219
|
-
let blocks: AlexElement[] = []
|
1220
|
-
dataRangeCaches.list.forEach(item => {
|
1221
|
-
const block = item.element.getBlock()
|
1222
|
-
const exist = blocks.some(el => block.isEqual(el))
|
1223
|
-
if (!exist) {
|
1224
|
-
blocks.push(block)
|
1225
|
-
}
|
1226
|
-
})
|
1227
|
-
blocks.forEach(block => {
|
1228
|
-
if (flag) {
|
1229
|
-
elementToParagraph(block)
|
1230
|
-
} else {
|
1231
|
-
elementToList(block, ordered)
|
1232
|
-
}
|
1233
|
-
})
|
1234
|
-
}
|
1235
|
-
}
|
1236
|
-
|
1237
|
-
/**
|
1238
|
-
* Open API:插入或者取消任务列表
|
1239
|
-
* @param editor
|
1240
|
-
* @param dataRangeCaches
|
1241
|
-
* @returns
|
1242
|
-
*/
|
1243
|
-
export const setTask = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
1244
|
-
if (!editor.range) {
|
1245
|
-
return
|
1246
|
-
}
|
1247
|
-
//是否都在任务列表里
|
1248
|
-
const flag = rangeIsInTask(editor, dataRangeCaches)
|
1249
|
-
//起点和终点在一起
|
1250
|
-
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1251
|
-
const block = editor.range.anchor.element.getBlock()
|
1252
|
-
if (flag) {
|
1253
|
-
elementToParagraph(block)
|
1254
|
-
} else {
|
1255
|
-
elementToTask(block)
|
1256
|
-
}
|
1257
|
-
}
|
1258
|
-
//起点和终点不在一起
|
1259
|
-
else {
|
1260
|
-
let blocks: AlexElement[] = []
|
1261
|
-
dataRangeCaches.list.forEach(item => {
|
1262
|
-
const block = item.element.getBlock()
|
1263
|
-
const exist = blocks.some(el => block.isEqual(el))
|
1264
|
-
if (!exist) {
|
1265
|
-
blocks.push(block)
|
1266
|
-
}
|
1267
|
-
})
|
1268
|
-
blocks.forEach(block => {
|
1269
|
-
if (flag) {
|
1270
|
-
elementToParagraph(block)
|
1271
|
-
} else {
|
1272
|
-
elementToTask(block)
|
1273
|
-
}
|
1274
|
-
})
|
1275
|
-
}
|
1276
|
-
}
|
1277
|
-
|
1278
|
-
/**
|
1279
|
-
* Open API:设置文本元素的样式
|
1280
|
-
* @param editor
|
1281
|
-
* @param dataRangeCaches
|
1282
|
-
* @param styles 值为{ 'font-weight':'bold' }这类格式
|
1283
|
-
* @returns
|
1284
|
-
*/
|
1285
|
-
export const setTextStyle = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, styles: ObjectType) => {
|
1286
|
-
if (!editor.range) {
|
1287
|
-
return
|
1288
|
-
}
|
1289
|
-
//起点和终点在一起
|
1290
|
-
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1291
|
-
//如果是空白文本元素直接设置样式
|
1292
|
-
if (editor.range.anchor.element.isSpaceText()) {
|
1293
|
-
if (editor.range.anchor.element.hasStyles()) {
|
1294
|
-
Object.assign(editor.range.anchor.element.styles!, cloneData(styles))
|
1295
|
-
} else {
|
1296
|
-
editor.range.anchor.element.styles = cloneData(styles)
|
1297
|
-
}
|
1298
|
-
}
|
1299
|
-
//如果是文本元素
|
1300
|
-
else if (editor.range.anchor.element.isText()) {
|
1301
|
-
//新建一个空白文本元素
|
1302
|
-
const el = AlexElement.getSpaceElement()
|
1303
|
-
//继承文本元素的样式和标记
|
1304
|
-
el.styles = cloneData(editor.range.anchor.element.styles)
|
1305
|
-
el.marks = cloneData(editor.range.anchor.element.marks)
|
1306
|
-
//设置样式
|
1307
|
-
if (el.hasStyles()) {
|
1308
|
-
Object.assign(el.styles!, cloneData(styles))
|
1309
|
-
} else {
|
1310
|
-
el.styles = cloneData(styles)
|
1311
|
-
}
|
1312
|
-
//插入空白文本元素
|
1313
|
-
editor.insertElement(el)
|
1314
|
-
}
|
1315
|
-
//如果是自闭合元素
|
1316
|
-
else {
|
1317
|
-
const el = AlexElement.getSpaceElement()
|
1318
|
-
el.styles = cloneData(styles)
|
1319
|
-
editor.insertElement(el)
|
1320
|
-
}
|
1321
|
-
}
|
1322
|
-
//不在同一个点
|
1323
|
-
else {
|
1324
|
-
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1325
|
-
elements.forEach(ele => {
|
1326
|
-
if (ele.isText()) {
|
1327
|
-
if (ele.hasStyles()) {
|
1328
|
-
Object.assign(ele.styles!, cloneData(styles))
|
1329
|
-
} else {
|
1330
|
-
ele.styles = cloneData(styles)
|
1331
|
-
}
|
1332
|
-
}
|
1333
|
-
})
|
1334
|
-
}
|
1335
|
-
}
|
1336
|
-
|
1337
|
-
/**
|
1338
|
-
* Open API:设置文本元素的标记
|
1339
|
-
* @param editor
|
1340
|
-
* @param dataRangeCaches
|
1341
|
-
* @param marks 值为{ 'class':'a' }这类格式
|
1631
|
+
* @param value 取值justify/left/right/center
|
1342
1632
|
* @returns
|
1343
1633
|
*/
|
1344
|
-
export const
|
1634
|
+
export const setAlign = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, value: 'justify' | 'left' | 'right' | 'center') => {
|
1345
1635
|
if (!editor.range) {
|
1346
1636
|
return
|
1347
1637
|
}
|
1348
|
-
if (!DapCommon.isObject(marks)) {
|
1349
|
-
throw new Error('The argument must be an object')
|
1350
|
-
}
|
1351
|
-
//起点和终点在一起
|
1352
1638
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1639
|
+
const block = editor.range.anchor.element.getBlock()
|
1640
|
+
const inblock = editor.range.anchor.element.getInblock()
|
1641
|
+
if (inblock) {
|
1642
|
+
if (inblock.hasStyles()) {
|
1643
|
+
inblock.styles!['text-align'] = value
|
1357
1644
|
} else {
|
1358
|
-
|
1645
|
+
inblock.styles = {
|
1646
|
+
'text-align': value
|
1647
|
+
}
|
1359
1648
|
}
|
1360
|
-
}
|
1361
|
-
|
1362
|
-
|
1363
|
-
//新建一个空白文本元素
|
1364
|
-
const el = AlexElement.getSpaceElement()
|
1365
|
-
//继承文本元素的样式和标记
|
1366
|
-
el.styles = cloneData(editor.range.anchor.element.styles)
|
1367
|
-
el.marks = cloneData(editor.range.anchor.element.marks)
|
1368
|
-
//设置标记
|
1369
|
-
if (el.hasMarks()) {
|
1370
|
-
Object.assign(el.marks!, cloneData(marks))
|
1649
|
+
} else {
|
1650
|
+
if (block.hasStyles()) {
|
1651
|
+
block.styles!['text-align'] = value
|
1371
1652
|
} else {
|
1372
|
-
|
1653
|
+
block.styles = {
|
1654
|
+
'text-align': value
|
1655
|
+
}
|
1373
1656
|
}
|
1374
|
-
//插入空白文本元素
|
1375
|
-
editor.insertElement(el)
|
1376
|
-
}
|
1377
|
-
//如果是自闭合元素
|
1378
|
-
else {
|
1379
|
-
const el = AlexElement.getSpaceElement()
|
1380
|
-
el.marks = cloneData(marks)
|
1381
|
-
editor.insertElement(el)
|
1382
1657
|
}
|
1383
|
-
}
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1658
|
+
} else {
|
1659
|
+
dataRangeCaches.list.forEach(el => {
|
1660
|
+
if (el.element.isBlock() || el.element.isInblock()) {
|
1661
|
+
if (el.element.hasStyles()) {
|
1662
|
+
el.element.styles!['text-align'] = value
|
1663
|
+
} else {
|
1664
|
+
el.element.styles = {
|
1665
|
+
'text-align': value
|
1666
|
+
}
|
1667
|
+
}
|
1668
|
+
} else {
|
1669
|
+
const block = el.element.getBlock()
|
1670
|
+
const inblock = el.element.getInblock()
|
1671
|
+
if (inblock) {
|
1672
|
+
if (inblock.hasStyles()) {
|
1673
|
+
inblock.styles!['text-align'] = value
|
1674
|
+
} else {
|
1675
|
+
inblock.styles = {
|
1676
|
+
'text-align': value
|
1677
|
+
}
|
1678
|
+
}
|
1391
1679
|
} else {
|
1392
|
-
|
1680
|
+
if (block.hasStyles()) {
|
1681
|
+
block.styles!['text-align'] = value
|
1682
|
+
} else {
|
1683
|
+
block.styles = {
|
1684
|
+
'text-align': value
|
1685
|
+
}
|
1686
|
+
}
|
1393
1687
|
}
|
1394
1688
|
}
|
1395
1689
|
})
|
@@ -1397,125 +1691,90 @@ export const setTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRan
|
|
1397
1691
|
}
|
1398
1692
|
|
1399
1693
|
/**
|
1400
|
-
* Open API
|
1694
|
+
* Open API:插入或者取消 有序或者无序列表
|
1401
1695
|
* @param editor
|
1402
1696
|
* @param dataRangeCaches
|
1403
|
-
* @param
|
1697
|
+
* @param ordered 为true表示有序列表
|
1404
1698
|
* @returns
|
1405
1699
|
*/
|
1406
|
-
export const
|
1700
|
+
export const setList = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, ordered: boolean) => {
|
1407
1701
|
if (!editor.range) {
|
1408
1702
|
return
|
1409
1703
|
}
|
1410
|
-
|
1411
|
-
const
|
1412
|
-
|
1413
|
-
if (Array.isArray(styleNames)) {
|
1414
|
-
if (el.hasStyles()) {
|
1415
|
-
let styles: ObjectType = {}
|
1416
|
-
Object.keys(el.styles!).forEach(key => {
|
1417
|
-
if (!styleNames.includes(key)) {
|
1418
|
-
styles[key] = el.styles![key]
|
1419
|
-
}
|
1420
|
-
})
|
1421
|
-
el.styles = styles
|
1422
|
-
}
|
1423
|
-
}
|
1424
|
-
//如果没有参数,则表示删除所有的样式
|
1425
|
-
else {
|
1426
|
-
el.styles = null
|
1427
|
-
}
|
1428
|
-
}
|
1429
|
-
//如果起点和终点在一起
|
1704
|
+
//是否都在列表内
|
1705
|
+
const flag = rangeIsInList(editor, dataRangeCaches, ordered)
|
1706
|
+
//起点和终点在一起
|
1430
1707
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1431
|
-
|
1432
|
-
if (
|
1433
|
-
|
1434
|
-
}
|
1435
|
-
|
1436
|
-
else if (editor.range.anchor.element.isText()) {
|
1437
|
-
const el = AlexElement.getSpaceElement()
|
1438
|
-
//继承文本元素的样式和标记
|
1439
|
-
el.styles = cloneData(editor.range.anchor.element.styles)
|
1440
|
-
el.marks = cloneData(editor.range.anchor.element.marks)
|
1441
|
-
//移除样式
|
1442
|
-
removeFn(el)
|
1443
|
-
//插入
|
1444
|
-
editor.insertElement(el)
|
1708
|
+
const block = editor.range.anchor.element.getBlock()
|
1709
|
+
if (flag) {
|
1710
|
+
elementToParagraph(block)
|
1711
|
+
} else {
|
1712
|
+
elementToList(block, ordered)
|
1445
1713
|
}
|
1446
1714
|
}
|
1447
1715
|
//起点和终点不在一起
|
1448
1716
|
else {
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1717
|
+
let blocks: AlexElement[] = []
|
1718
|
+
dataRangeCaches.list.forEach(item => {
|
1719
|
+
const block = item.element.getBlock()
|
1720
|
+
const exist = blocks.some(el => block.isEqual(el))
|
1721
|
+
if (!exist) {
|
1722
|
+
blocks.push(block)
|
1723
|
+
}
|
1724
|
+
})
|
1725
|
+
blocks.forEach(block => {
|
1726
|
+
if (flag) {
|
1727
|
+
elementToParagraph(block)
|
1728
|
+
} else {
|
1729
|
+
elementToList(block, ordered)
|
1453
1730
|
}
|
1454
1731
|
})
|
1455
1732
|
}
|
1456
1733
|
}
|
1457
1734
|
|
1458
1735
|
/**
|
1459
|
-
* Open API
|
1736
|
+
* Open API:插入或者取消任务列表
|
1460
1737
|
* @param editor
|
1461
1738
|
* @param dataRangeCaches
|
1462
|
-
* @param markNames 标记名称数组,如果不存在则移除全部标记
|
1463
1739
|
* @returns
|
1464
1740
|
*/
|
1465
|
-
export const
|
1741
|
+
export const setTask = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
1466
1742
|
if (!editor.range) {
|
1467
1743
|
return
|
1468
1744
|
}
|
1469
|
-
|
1470
|
-
const
|
1471
|
-
|
1472
|
-
if (Array.isArray(markNames)) {
|
1473
|
-
if (el.hasMarks()) {
|
1474
|
-
let marks: ObjectType = {}
|
1475
|
-
Object.keys(el.marks!).forEach(key => {
|
1476
|
-
if (!markNames.includes(key)) {
|
1477
|
-
marks[key] = el.marks![key]
|
1478
|
-
}
|
1479
|
-
})
|
1480
|
-
el.marks = marks
|
1481
|
-
}
|
1482
|
-
}
|
1483
|
-
//如果没有参数,则表示删除所有的样式
|
1484
|
-
else {
|
1485
|
-
el.marks = null
|
1486
|
-
}
|
1487
|
-
}
|
1488
|
-
//如果起点和终点在一起
|
1745
|
+
//是否都在任务列表里
|
1746
|
+
const flag = rangeIsInTask(editor, dataRangeCaches)
|
1747
|
+
//起点和终点在一起
|
1489
1748
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1490
|
-
|
1491
|
-
if (
|
1492
|
-
|
1493
|
-
}
|
1494
|
-
|
1495
|
-
else if (editor.range.anchor.element.isText()) {
|
1496
|
-
const el = AlexElement.getSpaceElement()
|
1497
|
-
//继承文本元素的样式和标记
|
1498
|
-
el.styles = cloneData(editor.range.anchor.element.styles)
|
1499
|
-
el.marks = cloneData(editor.range.anchor.element.marks)
|
1500
|
-
//移除标记
|
1501
|
-
removeFn(el)
|
1502
|
-
//插入
|
1503
|
-
editor.insertElement(el)
|
1749
|
+
const block = editor.range.anchor.element.getBlock()
|
1750
|
+
if (flag) {
|
1751
|
+
elementToParagraph(block)
|
1752
|
+
} else {
|
1753
|
+
elementToTask(block)
|
1504
1754
|
}
|
1505
1755
|
}
|
1506
1756
|
//起点和终点不在一起
|
1507
1757
|
else {
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1758
|
+
let blocks: AlexElement[] = []
|
1759
|
+
dataRangeCaches.list.forEach(item => {
|
1760
|
+
const block = item.element.getBlock()
|
1761
|
+
const exist = blocks.some(el => block.isEqual(el))
|
1762
|
+
if (!exist) {
|
1763
|
+
blocks.push(block)
|
1764
|
+
}
|
1765
|
+
})
|
1766
|
+
blocks.forEach(block => {
|
1767
|
+
if (flag) {
|
1768
|
+
elementToParagraph(block)
|
1769
|
+
} else {
|
1770
|
+
elementToTask(block)
|
1512
1771
|
}
|
1513
1772
|
})
|
1514
1773
|
}
|
1515
1774
|
}
|
1516
1775
|
|
1517
1776
|
/**
|
1518
|
-
* Open API
|
1777
|
+
* Open API:设置内部块元素或者根级块元素的行高
|
1519
1778
|
* @param editor
|
1520
1779
|
* @param dataRangeCaches
|
1521
1780
|
* @param value
|
@@ -1844,3 +2103,126 @@ export const insertSeparator = (editor: AlexEditor) => {
|
|
1844
2103
|
editor.range.anchor.moveToEnd(separator)
|
1845
2104
|
editor.range.focus.moveToEnd(separator)
|
1846
2105
|
}
|
2106
|
+
|
2107
|
+
/**
|
2108
|
+
* Open API:插入附件
|
2109
|
+
* @param editor
|
2110
|
+
* @param url 附件地址
|
2111
|
+
* @param name 附件名称
|
2112
|
+
*/
|
2113
|
+
export const insertAttachment = (editor: AlexEditor, url: string, name: string) => {
|
2114
|
+
const marks: ObjectType = {
|
2115
|
+
'data-editify-attachment': url,
|
2116
|
+
'data-editify-attachment-name': name
|
2117
|
+
}
|
2118
|
+
//创建元素
|
2119
|
+
const attachmentElement = AlexElement.create({
|
2120
|
+
type: 'closed',
|
2121
|
+
parsedom: 'span',
|
2122
|
+
marks
|
2123
|
+
})
|
2124
|
+
//插入编辑器
|
2125
|
+
editor.insertElement(attachmentElement)
|
2126
|
+
//移动光标到新插入的元素
|
2127
|
+
editor.range!.anchor.moveToEnd(attachmentElement)
|
2128
|
+
editor.range!.focus.moveToEnd(attachmentElement)
|
2129
|
+
}
|
2130
|
+
|
2131
|
+
/**
|
2132
|
+
* Open API:插入数学公式
|
2133
|
+
* @param editor
|
2134
|
+
* @param dataRangeCaches
|
2135
|
+
* @param mathContent 数学公式字符串
|
2136
|
+
* @param errorCallback 错误处理
|
2137
|
+
*/
|
2138
|
+
export const insertMathformula = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, mathContent: string, errorCallback?: (err: Error) => void) => {
|
2139
|
+
if (!mathContent) {
|
2140
|
+
return
|
2141
|
+
}
|
2142
|
+
//获取选区所在的数学公式元素
|
2143
|
+
const mathformulaElement = getMatchElementByRange(editor, dataRangeCaches, {
|
2144
|
+
parsedom: 'span',
|
2145
|
+
marks: {
|
2146
|
+
'data-editify-mathformula': true
|
2147
|
+
}
|
2148
|
+
})
|
2149
|
+
//如果在数学公式下
|
2150
|
+
if (mathformulaElement) {
|
2151
|
+
//清除该数学公式
|
2152
|
+
mathformulaElement.toEmpty()
|
2153
|
+
//移动光标到后一个元素上
|
2154
|
+
const nextElement = editor.getNextElement(mathformulaElement)!
|
2155
|
+
editor.range!.anchor.moveToStart(nextElement)
|
2156
|
+
editor.range!.focus.moveToStart(nextElement)
|
2157
|
+
}
|
2158
|
+
//定义转换后的mathml内容
|
2159
|
+
let mathml: string = ''
|
2160
|
+
try {
|
2161
|
+
//获取转换后的mathml
|
2162
|
+
mathml = KaTex.renderToString(mathContent, {
|
2163
|
+
output: 'mathml',
|
2164
|
+
throwOnError: true
|
2165
|
+
})
|
2166
|
+
} catch (error) {
|
2167
|
+
mathml = ''
|
2168
|
+
if (typeof errorCallback == 'function') {
|
2169
|
+
errorCallback(error as Error)
|
2170
|
+
}
|
2171
|
+
}
|
2172
|
+
//如果mathml存在则表示数学公式渲染成功则插入到编辑器
|
2173
|
+
if (mathml) {
|
2174
|
+
//设置最终的html内容
|
2175
|
+
const html = `<span data-editify-mathformula="${mathContent}" contenteditable="false">${mathml}</span>`
|
2176
|
+
//html内容转为元素数组
|
2177
|
+
const elements = editor.parseHtml(html)
|
2178
|
+
//插入编辑器
|
2179
|
+
editor.insertElement(elements[0])
|
2180
|
+
//移动光标到新插入的元素
|
2181
|
+
editor.range!.anchor.moveToEnd(elements[0])
|
2182
|
+
editor.range!.focus.moveToEnd(elements[0])
|
2183
|
+
//渲染
|
2184
|
+
editor.domRender()
|
2185
|
+
editor.rangeRender()
|
2186
|
+
}
|
2187
|
+
}
|
2188
|
+
|
2189
|
+
/**
|
2190
|
+
* Open API:插入信息块
|
2191
|
+
* @param editor
|
2192
|
+
* @param dataRangeCaches
|
2193
|
+
*/
|
2194
|
+
export const insertInfoBlock = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
2195
|
+
//是否都在信息块里
|
2196
|
+
const flag = rangeIsInInfoBlock(editor, dataRangeCaches)
|
2197
|
+
//起点和终点在一起
|
2198
|
+
if (editor.range!.anchor.isEqual(editor.range!.focus)) {
|
2199
|
+
const block = editor.range!.anchor.element.getBlock()
|
2200
|
+
elementToParagraph(block)
|
2201
|
+
if (!flag) {
|
2202
|
+
block.parsedom = 'div'
|
2203
|
+
block.marks = {
|
2204
|
+
'data-editify-info': 'true'
|
2205
|
+
}
|
2206
|
+
}
|
2207
|
+
}
|
2208
|
+
//起点和终点不在一起
|
2209
|
+
else {
|
2210
|
+
let blocks: AlexElement[] = []
|
2211
|
+
dataRangeCaches.list.forEach(item => {
|
2212
|
+
const block = item.element.getBlock()
|
2213
|
+
const exist = blocks.some(el => block.isEqual(el))
|
2214
|
+
if (!exist) {
|
2215
|
+
blocks.push(block)
|
2216
|
+
}
|
2217
|
+
})
|
2218
|
+
blocks.forEach(block => {
|
2219
|
+
elementToParagraph(block)
|
2220
|
+
if (!flag) {
|
2221
|
+
block.parsedom = 'div'
|
2222
|
+
block.marks = {
|
2223
|
+
'data-editify-info': 'true'
|
2224
|
+
}
|
2225
|
+
}
|
2226
|
+
})
|
2227
|
+
}
|
2228
|
+
}
|