vue-editify 0.2.16 → 0.2.18
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 +289 -5
- package/lib/components/colors/colors.vue.d.ts +9 -0
- package/lib/components/colors/props.d.ts +4 -0
- package/lib/core/function.d.ts +120 -45
- package/lib/core/rule.d.ts +23 -17
- package/lib/core/tool.d.ts +1 -13
- package/lib/editify/editify.vue.d.ts +10 -1
- package/lib/editify/props.d.ts +1 -1
- package/lib/editify/toolbar/props.d.ts +1 -1
- package/lib/editify/toolbar/toolbar.vue.d.ts +3 -3
- package/lib/editify.es.js +13640 -13799
- 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 +12 -3
- 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 +961 -475
- package/src/core/rule.ts +85 -367
- package/src/core/tool.ts +8 -114
- package/src/editify/editify.less +88 -14
- package/src/editify/editify.vue +117 -65
- package/src/editify/props.ts +1 -1
- package/src/editify/toolbar/props.ts +2 -2
- package/src/editify/toolbar/toolbar.vue +12 -12
- package/src/feature/align.ts +1 -61
- package/src/feature/attachment.ts +13 -26
- package/src/feature/backColor.ts +1 -0
- package/src/feature/foreColor.ts +1 -0
- package/src/feature/heading.ts +2 -73
- package/src/feature/infoBlock.ts +4 -35
- package/src/feature/lineHeight.ts +1 -77
- package/src/feature/mathformula.ts +3 -50
- package/src/feature/orderList.ts +166 -35
- package/src/feature/panel.ts +4 -49
- package/src/feature/sub.ts +1 -1
- package/src/feature/super.ts +1 -1
- package/src/feature/task.ts +1 -55
- package/src/feature/unorderList.ts +106 -35
- package/src/feature/video.ts +1 -1
- package/src/icon/iconfont.css +40 -0
- package/src/icon/iconfont.ttf +0 -0
- package/src/icon/iconfont.woff +0 -0
- package/src/index.ts +14 -8
- package/src/locale/en_US.ts +112 -110
- package/src/locale/zh_CN.ts +11 -9
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,6 +763,8 @@ export const hasMathformulaInRange = (editor: AlexEditor, dataRangeCaches: AlexE
|
|
502
763
|
})
|
503
764
|
}
|
504
765
|
|
766
|
+
/** --------------------------------面板判断函数--------------------------------------------------- */
|
767
|
+
|
505
768
|
/**
|
506
769
|
* Open API:判断元素是否面板,不做空元素判断
|
507
770
|
* @param el
|
@@ -548,6 +811,8 @@ export const hasPanelInRange = (editor: AlexEditor, dataRangeCaches: AlexElement
|
|
548
811
|
})
|
549
812
|
}
|
550
813
|
|
814
|
+
/** --------------------------------信息块判断函数---------------------------------------------- */
|
815
|
+
|
551
816
|
/**
|
552
817
|
* Open API:判断元素是否信息块,不做空元素判断
|
553
818
|
* @param el
|
@@ -612,6 +877,8 @@ export const rangeIsInInfoBlock = (editor: AlexEditor, dataRangeCaches: AlexElem
|
|
612
877
|
})
|
613
878
|
}
|
614
879
|
|
880
|
+
/** --------------------------------代码块判断函数------------------------------------------------ */
|
881
|
+
|
615
882
|
/**
|
616
883
|
* Open API:选区是否含有代码块,不一定是同一个代码块,只要含有代码块即返回true
|
617
884
|
* @param editor
|
@@ -630,41 +897,7 @@ export const hasPreInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsR
|
|
630
897
|
})
|
631
898
|
}
|
632
899
|
|
633
|
-
/**
|
634
|
-
* Open API:选区是否含有引用,不一定是同一个引用,只要含有引用即返回true
|
635
|
-
* @param editor
|
636
|
-
* @param dataRangeCaches
|
637
|
-
* @returns
|
638
|
-
*/
|
639
|
-
export const hasQuoteInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
640
|
-
if (!editor.range) {
|
641
|
-
return false
|
642
|
-
}
|
643
|
-
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
644
|
-
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'blockquote' })
|
645
|
-
}
|
646
|
-
return dataRangeCaches.flatList.some(item => {
|
647
|
-
return !!getMatchElementByElement(item.element, { parsedom: 'blockquote' })
|
648
|
-
})
|
649
|
-
}
|
650
|
-
|
651
|
-
/**
|
652
|
-
* Open API:选区是否含有链接,不一定是同一个链接,只要含有链接即返回true
|
653
|
-
* @param editor
|
654
|
-
* @param dataRangeCaches
|
655
|
-
* @returns
|
656
|
-
*/
|
657
|
-
export const hasLinkInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
658
|
-
if (!editor.range) {
|
659
|
-
return false
|
660
|
-
}
|
661
|
-
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
662
|
-
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'a' })
|
663
|
-
}
|
664
|
-
return dataRangeCaches.flatList.some(item => {
|
665
|
-
return !!getMatchElementByElement(item.element, { parsedom: 'a' })
|
666
|
-
})
|
667
|
-
}
|
900
|
+
/** --------------------------------表格判断函数------------------------------------------------- */
|
668
901
|
|
669
902
|
/**
|
670
903
|
* Open API:选区是否含有表格,不一定是同一个表格,只要含有表格即返回true
|
@@ -684,161 +917,103 @@ export const hasTableInRange = (editor: AlexEditor, dataRangeCaches: AlexElement
|
|
684
917
|
})
|
685
918
|
}
|
686
919
|
|
920
|
+
/** --------------------------------引用判断函数----------------------------------------------- */
|
921
|
+
|
687
922
|
/**
|
688
|
-
* Open API
|
923
|
+
* Open API:选区是否含有引用,不一定是同一个引用,只要含有引用即返回true
|
689
924
|
* @param editor
|
690
925
|
* @param dataRangeCaches
|
691
926
|
* @returns
|
692
927
|
*/
|
693
|
-
export const
|
928
|
+
export const hasQuoteInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
694
929
|
if (!editor.range) {
|
695
930
|
return false
|
696
931
|
}
|
697
932
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
698
|
-
return
|
933
|
+
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'blockquote' })
|
699
934
|
}
|
700
935
|
return dataRangeCaches.flatList.some(item => {
|
701
|
-
return
|
936
|
+
return !!getMatchElementByElement(item.element, { parsedom: 'blockquote' })
|
702
937
|
})
|
703
938
|
}
|
704
939
|
|
705
940
|
/**
|
706
|
-
* Open API
|
941
|
+
* Open API:选区是否全部在引用内,不一定是同一个引用
|
707
942
|
* @param editor
|
708
943
|
* @param dataRangeCaches
|
709
944
|
* @returns
|
710
945
|
*/
|
711
|
-
export const
|
946
|
+
export const rangeIsInQuote = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
712
947
|
if (!editor.range) {
|
713
948
|
return false
|
714
949
|
}
|
715
950
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
716
|
-
return
|
951
|
+
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'blockquote' })
|
717
952
|
}
|
718
|
-
return dataRangeCaches.
|
719
|
-
return
|
953
|
+
return dataRangeCaches.list.every(item => {
|
954
|
+
return !!getMatchElementByElement(item.element, { parsedom: 'blockquote' })
|
720
955
|
})
|
721
956
|
}
|
722
957
|
|
958
|
+
/** --------------------------------链接判断函数-------------------------------------------------- */
|
959
|
+
|
723
960
|
/**
|
724
|
-
* Open API
|
961
|
+
* Open API:选区是否含有链接,不一定是同一个链接,只要含有链接即返回true
|
725
962
|
* @param editor
|
726
963
|
* @param dataRangeCaches
|
727
964
|
* @returns
|
728
965
|
*/
|
729
|
-
export const
|
966
|
+
export const hasLinkInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
730
967
|
if (!editor.range) {
|
731
968
|
return false
|
732
969
|
}
|
733
970
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
734
|
-
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: '
|
971
|
+
return !!getMatchElementByElement(editor.range.anchor.element, { parsedom: 'a' })
|
735
972
|
}
|
736
|
-
return dataRangeCaches.
|
737
|
-
return !!getMatchElementByElement(item.element, { parsedom: '
|
973
|
+
return dataRangeCaches.flatList.some(item => {
|
974
|
+
return !!getMatchElementByElement(item.element, { parsedom: 'a' })
|
738
975
|
})
|
739
976
|
}
|
740
977
|
|
978
|
+
/** --------------------------------图片视频判断函数--------------------------------------------- */
|
979
|
+
|
741
980
|
/**
|
742
|
-
* Open API
|
981
|
+
* Open API:选区是否含有图片,不一定是同一个图片,只要含有图片即返回true
|
743
982
|
* @param editor
|
744
983
|
* @param dataRangeCaches
|
745
|
-
* @param name
|
746
|
-
* @param value
|
747
984
|
* @returns
|
748
985
|
*/
|
749
|
-
export const
|
986
|
+
export const hasImageInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
750
987
|
if (!editor.range) {
|
751
988
|
return false
|
752
989
|
}
|
753
|
-
//起点和终点在一起
|
754
990
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
755
|
-
|
756
|
-
if (editor.range.anchor.element.isText() && editor.range.anchor.element.hasStyles()) {
|
757
|
-
return queryHasValue(editor.range.anchor.element.styles!, name, value)
|
758
|
-
}
|
759
|
-
//不是文本元素或者没有样式直接返回
|
760
|
-
return false
|
761
|
-
}
|
762
|
-
//起点和终点不在一起获取选区中的文本元素
|
763
|
-
let result = dataRangeCaches.flatList.filter(item => {
|
764
|
-
return item.element.isText()
|
765
|
-
})
|
766
|
-
//如果不包含文本元素直接返回false
|
767
|
-
if (result.length == 0) {
|
768
|
-
return false
|
991
|
+
return elementIsMatch(editor.range.anchor.element, { parsedom: 'img' })
|
769
992
|
}
|
770
|
-
|
771
|
-
|
772
|
-
//文本元素含有样式进一步判断
|
773
|
-
if (item.element.hasStyles()) {
|
774
|
-
return queryHasValue(item.element.styles!, name, value)
|
775
|
-
}
|
776
|
-
//文本元素没有样式直接返回false
|
777
|
-
return false
|
993
|
+
return dataRangeCaches.flatList.some(item => {
|
994
|
+
return elementIsMatch(item.element, { parsedom: 'img' })
|
778
995
|
})
|
779
|
-
return flag
|
780
996
|
}
|
781
997
|
|
782
998
|
/**
|
783
|
-
* Open API
|
999
|
+
* Open API:选区是否含有视频,不一定是同一个视频,只要含有视频即返回true
|
784
1000
|
* @param editor
|
785
1001
|
* @param dataRangeCaches
|
786
|
-
* @param name
|
787
|
-
* @param value
|
788
1002
|
* @returns
|
789
1003
|
*/
|
790
|
-
export const
|
1004
|
+
export const hasVideoInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
791
1005
|
if (!editor.range) {
|
792
1006
|
return false
|
793
1007
|
}
|
794
|
-
//起点和终点在一起
|
795
1008
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
796
|
-
|
797
|
-
if (editor.range.anchor.element.isText() && editor.range.anchor.element.hasMarks()) {
|
798
|
-
return queryHasValue(editor.range.anchor.element.marks!, name, value)
|
799
|
-
}
|
800
|
-
//不是文本元素或者没有标记直接返回
|
801
|
-
return false
|
802
|
-
}
|
803
|
-
//起点和终点不在一起获取选区中的文本元素
|
804
|
-
let result = dataRangeCaches.flatList.filter(item => {
|
805
|
-
return item.element.isText()
|
806
|
-
})
|
807
|
-
//如果不包含文本元素直接返回false
|
808
|
-
if (result.length == 0) {
|
809
|
-
return false
|
1009
|
+
return elementIsMatch(editor.range.anchor.element, { parsedom: 'video' })
|
810
1010
|
}
|
811
|
-
|
812
|
-
|
813
|
-
//文本元素含有标记进一步判断
|
814
|
-
if (item.element.hasMarks()) {
|
815
|
-
return queryHasValue(item.element.marks!, name, value)
|
816
|
-
}
|
817
|
-
//文本元素没有标记直接返回false
|
818
|
-
return false
|
1011
|
+
return dataRangeCaches.flatList.some(item => {
|
1012
|
+
return elementIsMatch(item.element, { parsedom: 'video' })
|
819
1013
|
})
|
820
|
-
return flag
|
821
1014
|
}
|
822
1015
|
|
823
|
-
/**
|
824
|
-
* Open API:获取选区内的文字内容
|
825
|
-
* @param dataRangeCaches
|
826
|
-
* @returns
|
827
|
-
*/
|
828
|
-
export const getRangeText = (dataRangeCaches: AlexElementsRangeType) => {
|
829
|
-
//存在选区的情况下预置链接文本值
|
830
|
-
let text = ''
|
831
|
-
dataRangeCaches.flatList.forEach(item => {
|
832
|
-
if (item.element.isText()) {
|
833
|
-
if (item.offset) {
|
834
|
-
text += item.element.textContent!.substring(item.offset[0], item.offset[1])
|
835
|
-
} else {
|
836
|
-
text += item.element.textContent || ''
|
837
|
-
}
|
838
|
-
}
|
839
|
-
})
|
840
|
-
return text
|
841
|
-
}
|
1016
|
+
/** --------------------文本元素标记和样式相关函数--------------------------------------- */
|
842
1017
|
|
843
1018
|
/**
|
844
1019
|
* 获取光标选取内的扁平化元素数组(可能会分割文本元素导致stack变更,同时也会更新选取元素和光标位置)
|
@@ -907,32 +1082,355 @@ export const getFlatElementsByRange = (editor: AlexEditor, dataRangeCaches: Alex
|
|
907
1082
|
}
|
908
1083
|
|
909
1084
|
/**
|
910
|
-
*
|
911
|
-
* @param
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
element.styles = null
|
916
|
-
element.parsedom = AlexElement.BLOCK_NODE
|
917
|
-
}
|
918
|
-
|
919
|
-
/**
|
920
|
-
* 其他元素转为有序或者无序列表
|
921
|
-
* @param element
|
922
|
-
* @param ordered
|
1085
|
+
* Open API:查询光标所在的文本元素是否具有某个样式
|
1086
|
+
* @param editor
|
1087
|
+
* @param dataRangeCaches
|
1088
|
+
* @param name
|
1089
|
+
* @param value
|
923
1090
|
* @returns
|
924
1091
|
*/
|
925
|
-
export const
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
1092
|
+
export const queryTextStyle = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, name: string, value?: string | number) => {
|
1093
|
+
if (!editor.range) {
|
1094
|
+
return false
|
1095
|
+
}
|
1096
|
+
//起点和终点在一起
|
1097
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1098
|
+
//如果是文本元素并且具有样式
|
1099
|
+
if (editor.range.anchor.element.isText() && editor.range.anchor.element.hasStyles()) {
|
1100
|
+
return queryHasValue(editor.range.anchor.element.styles!, name, value)
|
1101
|
+
}
|
1102
|
+
//不是文本元素或者没有样式直接返回
|
1103
|
+
return false
|
1104
|
+
}
|
1105
|
+
//起点和终点不在一起获取选区中的文本元素
|
1106
|
+
let result = dataRangeCaches.flatList.filter(item => {
|
1107
|
+
return item.element.isText()
|
1108
|
+
})
|
1109
|
+
//如果不包含文本元素直接返回false
|
1110
|
+
if (result.length == 0) {
|
1111
|
+
return false
|
1112
|
+
}
|
1113
|
+
//判断每个文本元素是否都具有该样式
|
1114
|
+
let flag = result.every(item => {
|
1115
|
+
//文本元素含有样式进一步判断
|
1116
|
+
if (item.element.hasStyles()) {
|
1117
|
+
return queryHasValue(item.element.styles!, name, value)
|
1118
|
+
}
|
1119
|
+
//文本元素没有样式直接返回false
|
1120
|
+
return false
|
1121
|
+
})
|
1122
|
+
return flag
|
1123
|
+
}
|
1124
|
+
|
1125
|
+
/**
|
1126
|
+
* Open API:设置文本元素的样式
|
1127
|
+
* @param editor
|
1128
|
+
* @param dataRangeCaches
|
1129
|
+
* @param styles 值为{ 'font-weight':'bold' }这类格式
|
1130
|
+
* @returns
|
1131
|
+
*/
|
1132
|
+
export const setTextStyle = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, styles: ObjectType) => {
|
1133
|
+
if (!editor.range) {
|
1134
|
+
return
|
1135
|
+
}
|
1136
|
+
//起点和终点在一起
|
1137
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1138
|
+
//如果是空白文本元素直接设置样式
|
1139
|
+
if (editor.range.anchor.element.isSpaceText()) {
|
1140
|
+
if (editor.range.anchor.element.hasStyles()) {
|
1141
|
+
Object.assign(editor.range.anchor.element.styles!, DapCommon.clone(styles))
|
1142
|
+
} else {
|
1143
|
+
editor.range.anchor.element.styles = DapCommon.clone(styles)
|
1144
|
+
}
|
1145
|
+
}
|
1146
|
+
//如果是文本元素
|
1147
|
+
else if (editor.range.anchor.element.isText()) {
|
1148
|
+
//新建一个空白文本元素
|
1149
|
+
const el = AlexElement.getSpaceElement()
|
1150
|
+
//继承文本元素的样式和标记
|
1151
|
+
el.styles = DapCommon.clone(editor.range.anchor.element.styles)
|
1152
|
+
el.marks = DapCommon.clone(editor.range.anchor.element.marks)
|
1153
|
+
//设置样式
|
1154
|
+
if (el.hasStyles()) {
|
1155
|
+
Object.assign(el.styles!, DapCommon.clone(styles))
|
1156
|
+
} else {
|
1157
|
+
el.styles = DapCommon.clone(styles)
|
1158
|
+
}
|
1159
|
+
//插入空白文本元素
|
1160
|
+
editor.insertElement(el)
|
1161
|
+
}
|
1162
|
+
//如果是自闭合元素
|
1163
|
+
else {
|
1164
|
+
const el = AlexElement.getSpaceElement()
|
1165
|
+
el.styles = DapCommon.clone(styles)
|
1166
|
+
editor.insertElement(el)
|
1167
|
+
}
|
1168
|
+
}
|
1169
|
+
//不在同一个点
|
1170
|
+
else {
|
1171
|
+
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1172
|
+
elements.forEach(ele => {
|
1173
|
+
if (ele.isText()) {
|
1174
|
+
if (ele.hasStyles()) {
|
1175
|
+
Object.assign(ele.styles!, DapCommon.clone(styles))
|
1176
|
+
} else {
|
1177
|
+
ele.styles = DapCommon.clone(styles)
|
1178
|
+
}
|
1179
|
+
}
|
1180
|
+
})
|
1181
|
+
}
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
/**
|
1185
|
+
* Open API:移除文本元素的样式
|
1186
|
+
* @param editor
|
1187
|
+
* @param dataRangeCaches
|
1188
|
+
* @param styleNames 样式名称数组,如果不存在则移除全部样式
|
1189
|
+
* @returns
|
1190
|
+
*/
|
1191
|
+
export const removeTextStyle = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, styleNames?: string[]) => {
|
1192
|
+
if (!editor.range) {
|
1193
|
+
return
|
1194
|
+
}
|
1195
|
+
//移除样式的方法
|
1196
|
+
const removeFn = (el: AlexElement) => {
|
1197
|
+
//如果参数是数组,表示删除指定的样式
|
1198
|
+
if (Array.isArray(styleNames)) {
|
1199
|
+
if (el.hasStyles()) {
|
1200
|
+
let styles: ObjectType = {}
|
1201
|
+
Object.keys(el.styles!).forEach(key => {
|
1202
|
+
if (!styleNames.includes(key)) {
|
1203
|
+
styles[key] = el.styles![key]
|
1204
|
+
}
|
1205
|
+
})
|
1206
|
+
el.styles = styles
|
1207
|
+
}
|
1208
|
+
}
|
1209
|
+
//如果没有参数,则表示删除所有的样式
|
1210
|
+
else {
|
1211
|
+
el.styles = null
|
1212
|
+
}
|
1213
|
+
}
|
1214
|
+
//如果起点和终点在一起
|
1215
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1216
|
+
//如果是空白文本元素直接移除样式
|
1217
|
+
if (editor.range.anchor.element.isSpaceText()) {
|
1218
|
+
removeFn(editor.range.anchor.element)
|
1219
|
+
}
|
1220
|
+
//如果是文本元素则新建一个空白文本元素
|
1221
|
+
else if (editor.range.anchor.element.isText()) {
|
1222
|
+
const el = AlexElement.getSpaceElement()
|
1223
|
+
//继承文本元素的样式和标记
|
1224
|
+
el.styles = DapCommon.clone(editor.range.anchor.element.styles)
|
1225
|
+
el.marks = DapCommon.clone(editor.range.anchor.element.marks)
|
1226
|
+
//移除样式
|
1227
|
+
removeFn(el)
|
1228
|
+
//插入
|
1229
|
+
editor.insertElement(el)
|
1230
|
+
}
|
1231
|
+
}
|
1232
|
+
//起点和终点不在一起
|
1233
|
+
else {
|
1234
|
+
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1235
|
+
elements.forEach(ele => {
|
1236
|
+
if (ele.isText()) {
|
1237
|
+
removeFn(ele)
|
1238
|
+
}
|
1239
|
+
})
|
1240
|
+
}
|
1241
|
+
}
|
1242
|
+
|
1243
|
+
/**
|
1244
|
+
* Open API:查询光标所在的文本元素是否具有某个标记
|
1245
|
+
* @param editor
|
1246
|
+
* @param dataRangeCaches
|
1247
|
+
* @param name
|
1248
|
+
* @param value
|
1249
|
+
* @returns
|
1250
|
+
*/
|
1251
|
+
export const queryTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, name: string, value?: string | number) => {
|
1252
|
+
if (!editor.range) {
|
1253
|
+
return false
|
1254
|
+
}
|
1255
|
+
//起点和终点在一起
|
1256
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1257
|
+
//如果是文本元素并且具有标记
|
1258
|
+
if (editor.range.anchor.element.isText() && editor.range.anchor.element.hasMarks()) {
|
1259
|
+
return queryHasValue(editor.range.anchor.element.marks!, name, value)
|
1260
|
+
}
|
1261
|
+
//不是文本元素或者没有标记直接返回
|
1262
|
+
return false
|
1263
|
+
}
|
1264
|
+
//起点和终点不在一起获取选区中的文本元素
|
1265
|
+
let result = dataRangeCaches.flatList.filter(item => {
|
1266
|
+
return item.element.isText()
|
1267
|
+
})
|
1268
|
+
//如果不包含文本元素直接返回false
|
1269
|
+
if (result.length == 0) {
|
1270
|
+
return false
|
1271
|
+
}
|
1272
|
+
//判断每个文本元素是否都具有该标记
|
1273
|
+
let flag = result.every(item => {
|
1274
|
+
//文本元素含有标记进一步判断
|
1275
|
+
if (item.element.hasMarks()) {
|
1276
|
+
return queryHasValue(item.element.marks!, name, value)
|
1277
|
+
}
|
1278
|
+
//文本元素没有标记直接返回false
|
1279
|
+
return false
|
1280
|
+
})
|
1281
|
+
return flag
|
1282
|
+
}
|
1283
|
+
|
1284
|
+
/**
|
1285
|
+
* Open API:设置文本元素的标记
|
1286
|
+
* @param editor
|
1287
|
+
* @param dataRangeCaches
|
1288
|
+
* @param marks 值为{ 'class':'a' }这类格式
|
1289
|
+
* @returns
|
1290
|
+
*/
|
1291
|
+
export const setTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, marks: ObjectType) => {
|
1292
|
+
if (!editor.range) {
|
1293
|
+
return
|
1294
|
+
}
|
1295
|
+
if (!DapCommon.isObject(marks)) {
|
1296
|
+
throw new Error('The argument must be an object')
|
1297
|
+
}
|
1298
|
+
//起点和终点在一起
|
1299
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1300
|
+
//如果是空白文本元素直接设置标记
|
1301
|
+
if (editor.range.anchor.element.isSpaceText()) {
|
1302
|
+
if (editor.range.anchor.element.hasMarks()) {
|
1303
|
+
Object.assign(editor.range.anchor.element.marks!, DapCommon.clone(marks))
|
1304
|
+
} else {
|
1305
|
+
editor.range.anchor.element.marks = DapCommon.clone(marks)
|
1306
|
+
}
|
1307
|
+
}
|
1308
|
+
//如果是文本元素
|
1309
|
+
else if (editor.range.anchor.element.isText()) {
|
1310
|
+
//新建一个空白文本元素
|
1311
|
+
const el = AlexElement.getSpaceElement()
|
1312
|
+
//继承文本元素的样式和标记
|
1313
|
+
el.styles = DapCommon.clone(editor.range.anchor.element.styles)
|
1314
|
+
el.marks = DapCommon.clone(editor.range.anchor.element.marks)
|
1315
|
+
//设置标记
|
1316
|
+
if (el.hasMarks()) {
|
1317
|
+
Object.assign(el.marks!, DapCommon.clone(marks))
|
1318
|
+
} else {
|
1319
|
+
el.marks = DapCommon.clone(marks)
|
1320
|
+
}
|
1321
|
+
//插入空白文本元素
|
1322
|
+
editor.insertElement(el)
|
1323
|
+
}
|
1324
|
+
//如果是自闭合元素
|
1325
|
+
else {
|
1326
|
+
const el = AlexElement.getSpaceElement()
|
1327
|
+
el.marks = DapCommon.clone(marks)
|
1328
|
+
editor.insertElement(el)
|
1329
|
+
}
|
1330
|
+
}
|
1331
|
+
//不在同一个点
|
1332
|
+
else {
|
1333
|
+
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1334
|
+
elements.forEach(ele => {
|
1335
|
+
if (ele.isText()) {
|
1336
|
+
if (ele.hasMarks()) {
|
1337
|
+
Object.assign(ele.marks!, DapCommon.clone(marks))
|
1338
|
+
} else {
|
1339
|
+
ele.marks = DapCommon.clone(marks)
|
1340
|
+
}
|
1341
|
+
}
|
1342
|
+
})
|
1343
|
+
}
|
1344
|
+
}
|
1345
|
+
|
1346
|
+
/**
|
1347
|
+
* Open API:移除文本元素的标记
|
1348
|
+
* @param editor
|
1349
|
+
* @param dataRangeCaches
|
1350
|
+
* @param markNames 标记名称数组,如果不存在则移除全部标记
|
1351
|
+
* @returns
|
1352
|
+
*/
|
1353
|
+
export const removeTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, markNames?: string[]) => {
|
1354
|
+
if (!editor.range) {
|
1355
|
+
return
|
1356
|
+
}
|
1357
|
+
//移除样式的方法
|
1358
|
+
const removeFn = (el: AlexElement) => {
|
1359
|
+
//如果参数是数组,表示删除指定的样式
|
1360
|
+
if (Array.isArray(markNames)) {
|
1361
|
+
if (el.hasMarks()) {
|
1362
|
+
let marks: ObjectType = {}
|
1363
|
+
Object.keys(el.marks!).forEach(key => {
|
1364
|
+
if (!markNames.includes(key)) {
|
1365
|
+
marks[key] = el.marks![key]
|
1366
|
+
}
|
1367
|
+
})
|
1368
|
+
el.marks = marks
|
1369
|
+
}
|
1370
|
+
}
|
1371
|
+
//如果没有参数,则表示删除所有的样式
|
1372
|
+
else {
|
1373
|
+
el.marks = null
|
1374
|
+
}
|
1375
|
+
}
|
1376
|
+
//如果起点和终点在一起
|
1377
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1378
|
+
//如果是空白文本元素直接移除标记
|
1379
|
+
if (editor.range.anchor.element.isSpaceText()) {
|
1380
|
+
removeFn(editor.range.anchor.element)
|
1381
|
+
}
|
1382
|
+
//如果是文本元素则新建一个空白文本元素
|
1383
|
+
else if (editor.range.anchor.element.isText()) {
|
1384
|
+
const el = AlexElement.getSpaceElement()
|
1385
|
+
//继承文本元素的样式和标记
|
1386
|
+
el.styles = DapCommon.clone(editor.range.anchor.element.styles)
|
1387
|
+
el.marks = DapCommon.clone(editor.range.anchor.element.marks)
|
1388
|
+
//移除标记
|
1389
|
+
removeFn(el)
|
1390
|
+
//插入
|
1391
|
+
editor.insertElement(el)
|
1392
|
+
}
|
1393
|
+
}
|
1394
|
+
//起点和终点不在一起
|
1395
|
+
else {
|
1396
|
+
const elements = getFlatElementsByRange(editor, dataRangeCaches)
|
1397
|
+
elements.forEach(ele => {
|
1398
|
+
if (ele.isText()) {
|
1399
|
+
removeFn(ele)
|
1400
|
+
}
|
1401
|
+
})
|
1402
|
+
}
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
/** --------------------------------元素转换函数-------------------------------------------------- */
|
1406
|
+
|
1407
|
+
/**
|
1408
|
+
* 将某个元素转为段落标签
|
1409
|
+
* @param element
|
1410
|
+
*/
|
1411
|
+
export const elementToParagraph = (element: AlexElement) => {
|
1412
|
+
element.marks = null
|
1413
|
+
element.styles = null
|
1414
|
+
element.parsedom = AlexElement.BLOCK_NODE
|
1415
|
+
}
|
1416
|
+
|
1417
|
+
/**
|
1418
|
+
* 其他元素转为有序或者无序列表
|
1419
|
+
* @param element
|
1420
|
+
* @param ordered
|
1421
|
+
* @returns
|
1422
|
+
*/
|
1423
|
+
export const elementToList = (element: AlexElement, ordered: boolean | undefined = false) => {
|
1424
|
+
//如果是列表则返回
|
1425
|
+
if (elementIsList(element, ordered)) {
|
1426
|
+
return
|
1427
|
+
}
|
1428
|
+
//先转为段落
|
1429
|
+
elementToParagraph(element)
|
1430
|
+
//然后转为列表
|
1431
|
+
element.parsedom = 'div'
|
1432
|
+
if (!element.hasMarks()) {
|
1433
|
+
element.marks = {}
|
936
1434
|
}
|
937
1435
|
element.marks!['data-editify-list'] = ordered ? 'ol' : 'ul'
|
938
1436
|
}
|
@@ -957,22 +1455,70 @@ export const elementToTask = (element: AlexElement) => {
|
|
957
1455
|
element.marks!['data-editify-task'] = 'uncheck'
|
958
1456
|
}
|
959
1457
|
|
1458
|
+
/** --------------------------------封装的功能函数----------------------------------------------- */
|
1459
|
+
|
1460
|
+
/**
|
1461
|
+
* Open API:获取选区内的文字内容
|
1462
|
+
* @param dataRangeCaches
|
1463
|
+
* @returns
|
1464
|
+
*/
|
1465
|
+
export const getRangeText = (dataRangeCaches: AlexElementsRangeType) => {
|
1466
|
+
//存在选区的情况下预置链接文本值
|
1467
|
+
let text = ''
|
1468
|
+
dataRangeCaches.flatList.forEach(item => {
|
1469
|
+
if (item.element.isText()) {
|
1470
|
+
if (item.offset) {
|
1471
|
+
text += item.element.textContent!.substring(item.offset[0], item.offset[1])
|
1472
|
+
} else {
|
1473
|
+
text += item.element.textContent || ''
|
1474
|
+
}
|
1475
|
+
}
|
1476
|
+
})
|
1477
|
+
return text
|
1478
|
+
}
|
1479
|
+
|
1480
|
+
/**
|
1481
|
+
* Open API:给元素两侧加上空白文本元素
|
1482
|
+
* @param editor
|
1483
|
+
* @param element
|
1484
|
+
*/
|
1485
|
+
export const addSpaceTextToBothSides = (editor: AlexEditor, element: AlexElement) => {
|
1486
|
+
const previousElement = editor.getPreviousElement(element)
|
1487
|
+
const newTextElement = editor.getNextElement(element)
|
1488
|
+
//如果不存在前一个元素或者前一个元素不是空白元素则设置空白元素
|
1489
|
+
if (!previousElement || !previousElement.isSpaceText()) {
|
1490
|
+
const spaceText = AlexElement.getSpaceElement()
|
1491
|
+
editor.addElementBefore(spaceText, element)
|
1492
|
+
}
|
1493
|
+
//如果不存在后一个元素或者后一个元素不是空白元素则设置空白元素
|
1494
|
+
if (!newTextElement || !newTextElement.isSpaceText()) {
|
1495
|
+
const spaceText = AlexElement.getSpaceElement()
|
1496
|
+
editor.addElementAfter(spaceText, element)
|
1497
|
+
}
|
1498
|
+
//如果光标在视频上则更新光标位置
|
1499
|
+
if (editor.range && element.isContains(editor.range.anchor.element)) {
|
1500
|
+
editor.range.anchor.moveToEnd(editor.getNextElement(element)!)
|
1501
|
+
}
|
1502
|
+
if (editor.range && element.isContains(editor.range.focus.element)) {
|
1503
|
+
editor.range.focus.moveToEnd(editor.getNextElement(element)!)
|
1504
|
+
}
|
1505
|
+
}
|
1506
|
+
|
1507
|
+
/** --------------------------------菜单功能函数----------------------------------------------------- */
|
1508
|
+
|
960
1509
|
/**
|
961
|
-
*
|
1510
|
+
* OpenAPI:设置标题,支持h1-h6和p
|
962
1511
|
* @param editor
|
963
1512
|
* @param dataRangeCaches
|
964
1513
|
* @param editTrans
|
965
1514
|
* @param parsedom
|
966
1515
|
* @returns
|
967
1516
|
*/
|
968
|
-
export const setHeading = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType,
|
1517
|
+
export const setHeading = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, parsedom: string) => {
|
969
1518
|
if (!editor.range) {
|
970
1519
|
return
|
971
1520
|
}
|
972
|
-
|
973
|
-
return (<ButtonOptionsItemType>item).value
|
974
|
-
})
|
975
|
-
if (!values.includes(parsedom)) {
|
1521
|
+
if (!['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'].includes(parsedom)) {
|
976
1522
|
throw new Error('The parameter supports only h1-h6 and p')
|
977
1523
|
}
|
978
1524
|
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
@@ -1152,244 +1698,40 @@ export const setAlign = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeT
|
|
1152
1698
|
if (block.hasStyles()) {
|
1153
1699
|
block.styles!['text-align'] = value
|
1154
1700
|
} 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' }这类格式
|
1342
|
-
* @returns
|
1343
|
-
*/
|
1344
|
-
export const setTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, marks: ObjectType) => {
|
1345
|
-
if (!editor.range) {
|
1346
|
-
return
|
1347
|
-
}
|
1348
|
-
if (!DapCommon.isObject(marks)) {
|
1349
|
-
throw new Error('The argument must be an object')
|
1350
|
-
}
|
1351
|
-
//起点和终点在一起
|
1352
|
-
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
1353
|
-
//如果是空白文本元素直接设置标记
|
1354
|
-
if (editor.range.anchor.element.isSpaceText()) {
|
1355
|
-
if (editor.range.anchor.element.hasMarks()) {
|
1356
|
-
Object.assign(editor.range.anchor.element.marks!, cloneData(marks))
|
1357
|
-
} else {
|
1358
|
-
editor.range.anchor.element.marks = cloneData(marks)
|
1359
|
-
}
|
1360
|
-
}
|
1361
|
-
//如果是文本元素
|
1362
|
-
else if (editor.range.anchor.element.isText()) {
|
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))
|
1371
|
-
} else {
|
1372
|
-
el.marks = cloneData(marks)
|
1373
|
-
}
|
1374
|
-
//插入空白文本元素
|
1375
|
-
editor.insertElement(el)
|
1376
|
-
}
|
1377
|
-
//如果是自闭合元素
|
1378
|
-
else {
|
1379
|
-
const el = AlexElement.getSpaceElement()
|
1380
|
-
el.marks = cloneData(marks)
|
1381
|
-
editor.insertElement(el)
|
1701
|
+
block.styles = {
|
1702
|
+
'text-align': value
|
1703
|
+
}
|
1704
|
+
}
|
1382
1705
|
}
|
1383
|
-
}
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1706
|
+
} else {
|
1707
|
+
dataRangeCaches.list.forEach(el => {
|
1708
|
+
if (el.element.isBlock() || el.element.isInblock()) {
|
1709
|
+
if (el.element.hasStyles()) {
|
1710
|
+
el.element.styles!['text-align'] = value
|
1711
|
+
} else {
|
1712
|
+
el.element.styles = {
|
1713
|
+
'text-align': value
|
1714
|
+
}
|
1715
|
+
}
|
1716
|
+
} else {
|
1717
|
+
const block = el.element.getBlock()
|
1718
|
+
const inblock = el.element.getInblock()
|
1719
|
+
if (inblock) {
|
1720
|
+
if (inblock.hasStyles()) {
|
1721
|
+
inblock.styles!['text-align'] = value
|
1722
|
+
} else {
|
1723
|
+
inblock.styles = {
|
1724
|
+
'text-align': value
|
1725
|
+
}
|
1726
|
+
}
|
1391
1727
|
} else {
|
1392
|
-
|
1728
|
+
if (block.hasStyles()) {
|
1729
|
+
block.styles!['text-align'] = value
|
1730
|
+
} else {
|
1731
|
+
block.styles = {
|
1732
|
+
'text-align': value
|
1733
|
+
}
|
1734
|
+
}
|
1393
1735
|
}
|
1394
1736
|
}
|
1395
1737
|
})
|
@@ -1397,125 +1739,90 @@ export const setTextMark = (editor: AlexEditor, dataRangeCaches: AlexElementsRan
|
|
1397
1739
|
}
|
1398
1740
|
|
1399
1741
|
/**
|
1400
|
-
* Open API
|
1742
|
+
* Open API:插入或者取消 有序或者无序列表
|
1401
1743
|
* @param editor
|
1402
1744
|
* @param dataRangeCaches
|
1403
|
-
* @param
|
1745
|
+
* @param ordered 为true表示有序列表
|
1404
1746
|
* @returns
|
1405
1747
|
*/
|
1406
|
-
export const
|
1748
|
+
export const setList = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, ordered: boolean) => {
|
1407
1749
|
if (!editor.range) {
|
1408
1750
|
return
|
1409
1751
|
}
|
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
|
-
//如果起点和终点在一起
|
1752
|
+
//是否都在列表内
|
1753
|
+
const flag = rangeIsInList(editor, dataRangeCaches, ordered)
|
1754
|
+
//起点和终点在一起
|
1430
1755
|
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)
|
1756
|
+
const block = editor.range.anchor.element.getBlock()
|
1757
|
+
if (flag) {
|
1758
|
+
elementToParagraph(block)
|
1759
|
+
} else {
|
1760
|
+
elementToList(block, ordered)
|
1445
1761
|
}
|
1446
1762
|
}
|
1447
1763
|
//起点和终点不在一起
|
1448
1764
|
else {
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1765
|
+
let blocks: AlexElement[] = []
|
1766
|
+
dataRangeCaches.list.forEach(item => {
|
1767
|
+
const block = item.element.getBlock()
|
1768
|
+
const exist = blocks.some(el => block.isEqual(el))
|
1769
|
+
if (!exist) {
|
1770
|
+
blocks.push(block)
|
1771
|
+
}
|
1772
|
+
})
|
1773
|
+
blocks.forEach(block => {
|
1774
|
+
if (flag) {
|
1775
|
+
elementToParagraph(block)
|
1776
|
+
} else {
|
1777
|
+
elementToList(block, ordered)
|
1453
1778
|
}
|
1454
1779
|
})
|
1455
1780
|
}
|
1456
1781
|
}
|
1457
1782
|
|
1458
1783
|
/**
|
1459
|
-
* Open API
|
1784
|
+
* Open API:插入或者取消任务列表
|
1460
1785
|
* @param editor
|
1461
1786
|
* @param dataRangeCaches
|
1462
|
-
* @param markNames 标记名称数组,如果不存在则移除全部标记
|
1463
1787
|
* @returns
|
1464
1788
|
*/
|
1465
|
-
export const
|
1789
|
+
export const setTask = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
1466
1790
|
if (!editor.range) {
|
1467
1791
|
return
|
1468
1792
|
}
|
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
|
-
//如果起点和终点在一起
|
1793
|
+
//是否都在任务列表里
|
1794
|
+
const flag = rangeIsInTask(editor, dataRangeCaches)
|
1795
|
+
//起点和终点在一起
|
1489
1796
|
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)
|
1797
|
+
const block = editor.range.anchor.element.getBlock()
|
1798
|
+
if (flag) {
|
1799
|
+
elementToParagraph(block)
|
1800
|
+
} else {
|
1801
|
+
elementToTask(block)
|
1504
1802
|
}
|
1505
1803
|
}
|
1506
1804
|
//起点和终点不在一起
|
1507
1805
|
else {
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1806
|
+
let blocks: AlexElement[] = []
|
1807
|
+
dataRangeCaches.list.forEach(item => {
|
1808
|
+
const block = item.element.getBlock()
|
1809
|
+
const exist = blocks.some(el => block.isEqual(el))
|
1810
|
+
if (!exist) {
|
1811
|
+
blocks.push(block)
|
1812
|
+
}
|
1813
|
+
})
|
1814
|
+
blocks.forEach(block => {
|
1815
|
+
if (flag) {
|
1816
|
+
elementToParagraph(block)
|
1817
|
+
} else {
|
1818
|
+
elementToTask(block)
|
1512
1819
|
}
|
1513
1820
|
})
|
1514
1821
|
}
|
1515
1822
|
}
|
1516
1823
|
|
1517
1824
|
/**
|
1518
|
-
* Open API
|
1825
|
+
* Open API:设置内部块元素或者根级块元素的行高
|
1519
1826
|
* @param editor
|
1520
1827
|
* @param dataRangeCaches
|
1521
1828
|
* @param value
|
@@ -1844,3 +2151,182 @@ export const insertSeparator = (editor: AlexEditor) => {
|
|
1844
2151
|
editor.range.anchor.moveToEnd(separator)
|
1845
2152
|
editor.range.focus.moveToEnd(separator)
|
1846
2153
|
}
|
2154
|
+
|
2155
|
+
/**
|
2156
|
+
* Open API:插入附件
|
2157
|
+
* @param editor
|
2158
|
+
* @param url 附件地址
|
2159
|
+
* @param name 附件名称
|
2160
|
+
*/
|
2161
|
+
export const insertAttachment = (editor: AlexEditor, url: string, name: string) => {
|
2162
|
+
const marks: ObjectType = {
|
2163
|
+
'data-editify-attachment': url,
|
2164
|
+
'data-editify-attachment-name': name
|
2165
|
+
}
|
2166
|
+
//创建元素
|
2167
|
+
const attachmentElement = AlexElement.create({
|
2168
|
+
type: 'closed',
|
2169
|
+
parsedom: 'span',
|
2170
|
+
marks
|
2171
|
+
})
|
2172
|
+
//插入编辑器
|
2173
|
+
editor.insertElement(attachmentElement)
|
2174
|
+
//移动光标到新插入的元素
|
2175
|
+
editor.range!.anchor.moveToEnd(attachmentElement)
|
2176
|
+
editor.range!.focus.moveToEnd(attachmentElement)
|
2177
|
+
}
|
2178
|
+
|
2179
|
+
/**
|
2180
|
+
* Open API:插入数学公式
|
2181
|
+
* @param editor
|
2182
|
+
* @param dataRangeCaches
|
2183
|
+
* @param mathContent 数学公式字符串
|
2184
|
+
* @param errorCallback 错误处理
|
2185
|
+
*/
|
2186
|
+
export const insertMathformula = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType, mathContent: string, errorCallback?: (err: Error) => void) => {
|
2187
|
+
if (!mathContent) {
|
2188
|
+
return
|
2189
|
+
}
|
2190
|
+
//获取选区所在的数学公式元素
|
2191
|
+
const mathformulaElement = getMatchElementByRange(editor, dataRangeCaches, {
|
2192
|
+
parsedom: 'span',
|
2193
|
+
marks: {
|
2194
|
+
'data-editify-mathformula': true
|
2195
|
+
}
|
2196
|
+
})
|
2197
|
+
//如果在数学公式下
|
2198
|
+
if (mathformulaElement) {
|
2199
|
+
//清除该数学公式
|
2200
|
+
mathformulaElement.toEmpty()
|
2201
|
+
//移动光标到后一个元素上
|
2202
|
+
const nextElement = editor.getNextElement(mathformulaElement)!
|
2203
|
+
editor.range!.anchor.moveToStart(nextElement)
|
2204
|
+
editor.range!.focus.moveToStart(nextElement)
|
2205
|
+
}
|
2206
|
+
//定义转换后的mathml内容
|
2207
|
+
let mathml: string = ''
|
2208
|
+
try {
|
2209
|
+
//获取转换后的mathml
|
2210
|
+
mathml = KaTex.renderToString(mathContent, {
|
2211
|
+
output: 'mathml',
|
2212
|
+
throwOnError: true
|
2213
|
+
})
|
2214
|
+
} catch (error) {
|
2215
|
+
mathml = ''
|
2216
|
+
if (typeof errorCallback == 'function') {
|
2217
|
+
errorCallback(error as Error)
|
2218
|
+
}
|
2219
|
+
}
|
2220
|
+
//如果mathml存在则表示数学公式渲染成功则插入到编辑器
|
2221
|
+
if (mathml) {
|
2222
|
+
//设置最终的html内容
|
2223
|
+
const html = `<span data-editify-mathformula="${mathContent}" contenteditable="false">${mathml}</span>`
|
2224
|
+
//html内容转为元素数组
|
2225
|
+
const elements = editor.parseHtml(html)
|
2226
|
+
//插入编辑器
|
2227
|
+
editor.insertElement(elements[0])
|
2228
|
+
//移动光标到新插入的元素
|
2229
|
+
editor.range!.anchor.moveToEnd(elements[0])
|
2230
|
+
editor.range!.focus.moveToEnd(elements[0])
|
2231
|
+
//渲染
|
2232
|
+
editor.domRender()
|
2233
|
+
editor.rangeRender()
|
2234
|
+
}
|
2235
|
+
}
|
2236
|
+
|
2237
|
+
/**
|
2238
|
+
* Open API:插入信息块
|
2239
|
+
* @param editor
|
2240
|
+
* @param dataRangeCaches
|
2241
|
+
*/
|
2242
|
+
export const insertInfoBlock = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
2243
|
+
//是否都在信息块里
|
2244
|
+
const flag = rangeIsInInfoBlock(editor, dataRangeCaches)
|
2245
|
+
//起点和终点在一起
|
2246
|
+
if (editor.range!.anchor.isEqual(editor.range!.focus)) {
|
2247
|
+
const block = editor.range!.anchor.element.getBlock()
|
2248
|
+
elementToParagraph(block)
|
2249
|
+
if (!flag) {
|
2250
|
+
block.parsedom = 'div'
|
2251
|
+
block.marks = {
|
2252
|
+
'data-editify-info': 'true'
|
2253
|
+
}
|
2254
|
+
}
|
2255
|
+
}
|
2256
|
+
//起点和终点不在一起
|
2257
|
+
else {
|
2258
|
+
let blocks: AlexElement[] = []
|
2259
|
+
dataRangeCaches.list.forEach(item => {
|
2260
|
+
const block = item.element.getBlock()
|
2261
|
+
const exist = blocks.some(el => block.isEqual(el))
|
2262
|
+
if (!exist) {
|
2263
|
+
blocks.push(block)
|
2264
|
+
}
|
2265
|
+
})
|
2266
|
+
blocks.forEach(block => {
|
2267
|
+
elementToParagraph(block)
|
2268
|
+
if (!flag) {
|
2269
|
+
block.parsedom = 'div'
|
2270
|
+
block.marks = {
|
2271
|
+
'data-editify-info': 'true'
|
2272
|
+
}
|
2273
|
+
}
|
2274
|
+
})
|
2275
|
+
}
|
2276
|
+
}
|
2277
|
+
|
2278
|
+
/**
|
2279
|
+
* Open API:插入面板
|
2280
|
+
* @param editor
|
2281
|
+
* @param panelTitle 面板标题
|
2282
|
+
* @param panelContent 面板内容
|
2283
|
+
*/
|
2284
|
+
export const insertPanel = (editor: AlexEditor, panelTitle: string, panelContent: string) => {
|
2285
|
+
const panelElement = AlexElement.create({
|
2286
|
+
type: 'block',
|
2287
|
+
parsedom: 'div',
|
2288
|
+
marks: {
|
2289
|
+
'data-editify-panel': 'true'
|
2290
|
+
},
|
2291
|
+
children: [
|
2292
|
+
{
|
2293
|
+
type: 'inblock',
|
2294
|
+
parsedom: 'div',
|
2295
|
+
behavior: 'block',
|
2296
|
+
children: [
|
2297
|
+
{
|
2298
|
+
type: 'text',
|
2299
|
+
textcontent: panelTitle
|
2300
|
+
}
|
2301
|
+
]
|
2302
|
+
},
|
2303
|
+
{
|
2304
|
+
type: 'inblock',
|
2305
|
+
parsedom: 'div',
|
2306
|
+
behavior: 'block',
|
2307
|
+
children: [
|
2308
|
+
{
|
2309
|
+
type: 'text',
|
2310
|
+
textcontent: panelContent
|
2311
|
+
}
|
2312
|
+
]
|
2313
|
+
}
|
2314
|
+
]
|
2315
|
+
})
|
2316
|
+
editor.insertElement(panelElement)
|
2317
|
+
//面板后面插入段落
|
2318
|
+
const paragraph = AlexElement.create({
|
2319
|
+
type: 'block',
|
2320
|
+
parsedom: AlexElement.BLOCK_NODE,
|
2321
|
+
children: [
|
2322
|
+
{
|
2323
|
+
type: 'closed',
|
2324
|
+
parsedom: 'br'
|
2325
|
+
}
|
2326
|
+
]
|
2327
|
+
})
|
2328
|
+
editor.addElementAfter(paragraph, panelElement)
|
2329
|
+
//移动光标到新插入的元素
|
2330
|
+
editor.range!.anchor.moveToEnd(panelElement.children![0])
|
2331
|
+
editor.range!.focus.moveToEnd(panelElement.children![0])
|
2332
|
+
}
|