vue-editify 0.1.43 → 0.1.45

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/src/core/rule.ts CHANGED
@@ -1,8 +1,175 @@
1
1
  import { AlexEditor, AlexElement } from 'alex-editor'
2
2
  import { LanguagesItemType, getHljsHtml } from '../hljs'
3
- import { isList, isTask } from './function'
3
+ import { isList, isTask, getTableSize, getCellSpanNumber } from './function'
4
4
  import { common as DapCommon } from 'dap-util'
5
5
 
6
+ /**
7
+ * 自动补全表格行和列
8
+ * @param editor
9
+ * @param rowElements
10
+ * @param rowNumber
11
+ * @param columnNumber
12
+ */
13
+ const autocompleteTableCells = (editor: AlexEditor, rowElements: AlexElement[], rowNumber: number, columnNumber: number) => {
14
+ //遍历所有的单元格
15
+ AlexElement.flatElements(rowElements).forEach(item => {
16
+ if (item.parsedom == 'td' && item.hasMarks()) {
17
+ //删除被合并的标识
18
+ if (item.marks!['data-editify-merged']) {
19
+ delete item.marks!['data-editify-merged']
20
+ }
21
+ //获取colspan
22
+ const colspan = isNaN(Number(item.marks!['colspan'])) ? 1 : Number(item.marks!['colspan'])
23
+ //获取rowspan
24
+ const rowspan = isNaN(Number(item.marks!['rowspan'])) ? 1 : Number(item.marks!['rowspan'])
25
+ //针对colspan>1的单元格在后面补全隐藏的单元格
26
+ if (colspan > 1) {
27
+ let i = 1
28
+ //补全的数量小于需要补全的数量并且列总数量小于理论数量
29
+ while (i < colspan && item.parent!.children!.length < columnNumber) {
30
+ const column = new AlexElement(
31
+ 'inblock',
32
+ 'td',
33
+ {
34
+ 'data-editify-merged': 'true'
35
+ },
36
+ null,
37
+ null
38
+ )
39
+ const breakElement = new AlexElement('closed', 'br', null, null, null)
40
+ editor.addElementTo(breakElement, column)
41
+ editor.addElementAfter(column, item)
42
+ i++
43
+ }
44
+ }
45
+ //针对rowspan>1的单元格在后面的行中对应位置补全隐藏的单元格
46
+ if (rowspan > 1) {
47
+ let el = item
48
+ let i = 1
49
+ while (i < rowspan && editor.getNextElement(el.parent!) && editor.getNextElement(el.parent!)!.children!.length < columnNumber) {
50
+ //下一行
51
+ const nextRow = editor.getNextElement(el.parent!)!
52
+ //单元格在行中的序列
53
+ const index = el.parent!.children!.findIndex(item => item.isEqual(el))
54
+ //下一行对应的单元格
55
+ const nextCell = nextRow.children![index]
56
+ //根据当前单元格的跨列数补充符合跨列数的隐藏单元格
57
+ for (let j = 0; j < colspan; j++) {
58
+ const column = new AlexElement(
59
+ 'inblock',
60
+ 'td',
61
+ {
62
+ 'data-editify-merged': 'true'
63
+ },
64
+ null,
65
+ null
66
+ )
67
+ const breakElement = new AlexElement('closed', 'br', null, null, null)
68
+ editor.addElementTo(breakElement, column)
69
+ if (nextCell) {
70
+ editor.addElementBefore(column, nextCell)
71
+ } else {
72
+ editor.addElementTo(column, nextRow, nextRow.children!.length)
73
+ }
74
+ }
75
+ el = nextRow.children![index]
76
+ i++
77
+ }
78
+ }
79
+ }
80
+ })
81
+ //遍历每一行,如果还缺少列则在后面补全列
82
+ rowElements.forEach(rowElement => {
83
+ //遍历该行的单元格获取总列数
84
+ const number = rowElement.children!.length
85
+ if (number < columnNumber) {
86
+ for (let i = 0; i < columnNumber - number; i++) {
87
+ const column = new AlexElement('inblock', 'td', null, null, null)
88
+ const breakElement = new AlexElement('closed', 'br', null, null, null)
89
+ editor.addElementTo(breakElement, column)
90
+ editor.addElementTo(column, rowElement, rowElement.children!.length)
91
+ }
92
+ }
93
+ })
94
+ //获取总行数
95
+ const length = rowElements.length
96
+ //判断总行数是否小于实际行数则补全行
97
+ if (length < rowNumber) {
98
+ for (let i = 0; i < rowNumber - length; i++) {
99
+ const row = new AlexElement('inblock', 'tr', null, null, null)
100
+ for (let j = 0; j < columnNumber; j++) {
101
+ const column = new AlexElement('inblock', 'td', null, null, null)
102
+ const breakElement = new AlexElement('closed', 'br', null, null, null)
103
+ editor.addElementTo(breakElement, column)
104
+ editor.addElementTo(column, row)
105
+ }
106
+ rowElements.push(row)
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * 自动隐藏被合并的单元格
113
+ * @param editor
114
+ * @param rowElements
115
+ */
116
+ const autoHideMergedTableCells = (editor: AlexEditor, rowElements: AlexElement[]) => {
117
+ const cells = AlexElement.flatElements(rowElements).filter(item => item.parsedom == 'td')
118
+ cells.forEach(cell => {
119
+ if (cell.hasMarks() && !cell.marks!['data-editify-merged']) {
120
+ //获取colspan
121
+ const colspan = isNaN(Number(cell.marks!['colspan'])) ? 1 : Number(cell.marks!['colspan'])
122
+ //获取rowspan
123
+ const rowspan = isNaN(Number(cell.marks!['rowspan'])) ? 1 : Number(cell.marks!['rowspan'])
124
+ //如果是跨列单元格,隐藏该单元格同行后的colspan-1个单元格
125
+ if (colspan > 1) {
126
+ let el = cell
127
+ let i = 1
128
+ while (i < colspan) {
129
+ const nextCell = editor.getNextElement(el)!
130
+ if (nextCell) {
131
+ if (nextCell.hasMarks()) {
132
+ nextCell.marks!['data-editify-merged'] = 'true'
133
+ } else {
134
+ nextCell.marks = {
135
+ 'data-editify-merged': 'true'
136
+ }
137
+ }
138
+ el = nextCell
139
+ i++
140
+ } else {
141
+ break
142
+ }
143
+ }
144
+ }
145
+ //如果是跨行单元格,隐藏该单元格同列后的rowspan-1行单元格
146
+ if (rowspan > 1) {
147
+ const index = cell.parent!.children!.findIndex(item => item.isEqual(cell))
148
+ let el = cell
149
+ let i = 1
150
+ while (i < rowspan && el && editor.getNextElement(el.parent!)) {
151
+ const nextRow = editor.getNextElement(el.parent!)!
152
+ //根据跨行单元格占据的列数,在后的rowspan-1行中隐藏colspan个单元格
153
+ for (let j = index; j < index + colspan; j++) {
154
+ const current = nextRow.children![j]
155
+ if (current) {
156
+ if (current.hasMarks()) {
157
+ current.marks!['data-editify-merged'] = 'true'
158
+ } else {
159
+ current.marks = {
160
+ 'data-editify-merged': 'true'
161
+ }
162
+ }
163
+ }
164
+ }
165
+ el = nextRow.children![index]
166
+ i++
167
+ }
168
+ }
169
+ }
170
+ })
171
+ }
172
+
6
173
  /**
7
174
  * 更新代码块内的光标位置
8
175
  * @param editor
@@ -94,7 +261,7 @@ export const parseList = (editor: AlexEditor, element: AlexElement) => {
94
261
  * @param editor
95
262
  * @param element
96
263
  */
97
- export const orderdListHandle = function (editor: AlexEditor, element: AlexElement) {
264
+ export const orderdListHandle = (editor: AlexEditor, element: AlexElement) => {
98
265
  //有序列表的序号处理
99
266
  if (isList(element, true)) {
100
267
  //获取前一个元素
@@ -116,7 +283,7 @@ export const orderdListHandle = function (editor: AlexEditor, element: AlexEleme
116
283
  * @param editor
117
284
  * @param element
118
285
  */
119
- export const commonElementHandle = function (editor: AlexEditor, element: AlexElement) {
286
+ export const commonElementHandle = (editor: AlexEditor, element: AlexElement) => {
120
287
  //图片、视频和链接设置marks
121
288
  if (element.parsedom == 'img' || element.parsedom == 'video' || element.parsedom == 'a') {
122
289
  const marks = {
@@ -167,11 +334,22 @@ export const commonElementHandle = function (editor: AlexEditor, element: AlexEl
167
334
  }
168
335
 
169
336
  /**
170
- * 元素格式化时处理表格
337
+ * 元素格式化时处理表格:th转为td
338
+ * @param editor
339
+ * @param element
340
+ */
341
+ export const tableThTdHandle = (_editor: AlexEditor, element: AlexElement) => {
342
+ if (element.parsedom == 'th') {
343
+ element.parsedom = 'td'
344
+ }
345
+ }
346
+
347
+ /**
348
+ * 元素格式化时处理表格:格式化表格
171
349
  * @param editor
172
350
  * @param element
173
351
  */
174
- export const tableHandle = function (editor: AlexEditor, element: AlexElement) {
352
+ export const tableFormatHandle = (editor: AlexEditor, element: AlexElement) => {
175
353
  if (element.parsedom == 'table') {
176
354
  const marks = {
177
355
  'data-editify-element': element.key
@@ -195,16 +373,12 @@ export const tableHandle = function (editor: AlexEditor, element: AlexElement) {
195
373
  const rows = elements.filter(el => {
196
374
  return el.parsedom == 'tr'
197
375
  })
376
+ //获取表格实际应该的规格
377
+ const { rowNumber, columnNumber } = getTableSize(rows)
198
378
  //colgroup元素
199
379
  let colgroup = elements.find(el => {
200
380
  return el.parsedom == 'colgroup'
201
381
  })
202
- //理论上的col的数量:取最多列数
203
- const colNumber = Math.max(
204
- ...rows.map(row => {
205
- return row.children!.length
206
- })
207
- )
208
382
  //如果colgroup元素存在
209
383
  if (colgroup) {
210
384
  //遍历每个col元素设置默认的width:'auto
@@ -222,8 +396,8 @@ export const tableHandle = function (editor: AlexEditor, element: AlexElement) {
222
396
  })
223
397
  //对缺少的col元素进行补全
224
398
  const length = colgroup.children!.length
225
- if (length < colNumber) {
226
- for (let i = 0; i < colNumber - length; i++) {
399
+ if (length < columnNumber) {
400
+ for (let i = 0; i < columnNumber - length; i++) {
227
401
  const col = new AlexElement(
228
402
  'closed',
229
403
  'col',
@@ -240,7 +414,7 @@ export const tableHandle = function (editor: AlexEditor, element: AlexElement) {
240
414
  //如果colgroup元素不存在则新建
241
415
  else {
242
416
  colgroup = new AlexElement('inblock', 'colgroup', null, null, null)
243
- for (let i = colNumber - 1; i >= 0; i--) {
417
+ for (let i = columnNumber - 1; i >= 0; i--) {
244
418
  const col = new AlexElement(
245
419
  'closed',
246
420
  'col',
@@ -253,41 +427,106 @@ export const tableHandle = function (editor: AlexEditor, element: AlexElement) {
253
427
  editor.addElementTo(col, colgroup)
254
428
  }
255
429
  }
430
+ //自动补全表格的单元格
431
+ autocompleteTableCells(editor, rows, rowNumber, columnNumber)
432
+ //清空表格
256
433
  element.children = []
434
+ //创建tbody元素
257
435
  const tbody = new AlexElement('inblock', 'tbody', null, null, null)
258
- rows.reverse().forEach(row => {
259
- //对缺少的列进行补全
260
- const length = row.children!.length
261
- if (length < colNumber) {
262
- for (let i = 0; i < colNumber - length; i++) {
263
- const column = new AlexElement('inblock', 'td', null, null, null)
264
- const breakElement = new AlexElement('closed', 'br', null, null, null)
265
- editor.addElementTo(breakElement, column)
266
- editor.addElementTo(column, row, row.children!.length)
267
- }
268
- }
269
- editor.addElementTo(row, tbody)
436
+ //将rows全部加入表格中
437
+ rows.forEach(row => {
438
+ const index = tbody.hasChildren() ? tbody.children!.length : 0
439
+ editor.addElementTo(row, tbody, index)
270
440
  })
271
441
  editor.addElementTo(tbody, element)
272
442
  editor.addElementTo(colgroup, element)
443
+ //对表格单元格合并状态进行处理
444
+ autoHideMergedTableCells(editor, rows)
273
445
  }
274
- if (element.parsedom == 'th') {
275
- element.parsedom = 'td'
276
- }
277
- if (element.parsedom == 'td') {
278
- //移除列的rowspan和colspan属性
279
- if (element.hasMarks()) {
280
- if (element.marks!['rowspan']) {
281
- delete element.marks!['rowspan']
446
+ }
447
+
448
+ /**
449
+ * 元素格式化时处理表格:处理光标在表格隐藏单元格内的情况
450
+ * @param editor
451
+ * @param element
452
+ */
453
+ export const tableRangeMergedHandle = (editor: AlexEditor, element: AlexElement) => {
454
+ //如果元素是被隐藏的单元格,并且光标在该单元格内
455
+ if (element.parsedom == 'td' && element.hasMarks() && element.marks!['data-editify-merged'] && editor.range) {
456
+ //单元格向左查找设置焦点
457
+ const queryLeftSetRange = (_element: AlexElement, callback: (ele: AlexElement) => void) => {
458
+ //是否已查找到
459
+ let success = false
460
+ //获取前一个单元格
461
+ let el = editor.getPreviousElement(_element)
462
+ let tempIndex = 1
463
+ //如果前一个单元格存在则循环
464
+ while (el) {
465
+ //获取单元格的colspan
466
+ const { colspan } = getCellSpanNumber(el)
467
+ //如果单元格是跨列的并且是跨当前单元格的
468
+ if (el.hasMarks() && !el.marks!['data-editify-merged'] && colspan > tempIndex) {
469
+ success = true
470
+ callback(el)
471
+ break
472
+ }
473
+ //不是则继续向上查找
474
+ else {
475
+ el = editor.getPreviousElement(el)
476
+ tempIndex++
477
+ }
478
+ }
479
+ return success
480
+ }
481
+ //单元格向上查找设置焦点
482
+ const queryUpSetRange = (_element: AlexElement, callback: (ele: AlexElement) => void) => {
483
+ //是否已查找到
484
+ let success = false
485
+ //单元格在行中的序列
486
+ const index = _element.parent!.children!.findIndex(item => item.isEqual(_element))
487
+ //获取前一行元素
488
+ let el = editor.getPreviousElement(_element.parent!)
489
+ let tempIndex = 1
490
+ //如果前一行元素存在则循环
491
+ while (el) {
492
+ //获取前一行中同列的单元格
493
+ const previousColumn = el.children![index]
494
+ //获取单元格的rowspan
495
+ const { rowspan } = getCellSpanNumber(previousColumn)
496
+ //如果单元格是跨行的并且是跨当前单元格的
497
+ if (previousColumn.hasMarks() && !previousColumn.marks!['data-editify-merged'] && rowspan > tempIndex) {
498
+ success = true
499
+ callback(previousColumn)
500
+ break
501
+ }
502
+ //不是则继续向上查找
503
+ else {
504
+ el = editor.getPreviousElement(el)
505
+ tempIndex++
506
+ }
282
507
  }
283
- if (element.marks!['colspan']) {
284
- delete element.marks!['colspan']
508
+ return success
509
+ }
510
+ //起点在该单元格下
511
+ if (element.isContains(editor.range.anchor.element)) {
512
+ const success = queryLeftSetRange(element, ele => {
513
+ editor.range!.anchor.moveToEnd(ele)
514
+ })
515
+ if (!success) {
516
+ queryUpSetRange(element, ele => {
517
+ editor.range!.anchor.moveToEnd(ele)
518
+ })
285
519
  }
286
520
  }
287
- //移除列的display样式
288
- if (element.hasStyles()) {
289
- if (element.styles!['display']) {
290
- delete element.styles!['display']
521
+ //终点在该单元格下
522
+ if (element.isContains(editor.range.focus.element)) {
523
+ const success = queryLeftSetRange(element, ele => {
524
+ editor.range!.focus.moveToEnd(ele)
525
+ })
526
+ if (!success) {
527
+ queryUpSetRange(element, ele => {
528
+ editor.range!.focus.moveToEnd(ele)
529
+ })
291
530
  }
292
531
  }
293
532
  }
@@ -300,7 +539,7 @@ export const tableHandle = function (editor: AlexEditor, element: AlexElement) {
300
539
  * @param highlight
301
540
  * @param languages
302
541
  */
303
- export const preHandle = function (editor: AlexEditor, element: AlexElement, highlight: boolean, languages: (string | LanguagesItemType)[]) {
542
+ export const preHandle = (editor: AlexEditor, element: AlexElement, highlight: boolean, languages: (string | LanguagesItemType)[]) => {
304
543
  //如果是代码块进行处理
305
544
  if (element.parsedom == 'pre') {
306
545
  const marks = {
@@ -365,7 +604,7 @@ export const preHandle = function (editor: AlexEditor, element: AlexElement, hig
365
604
  * @param editor
366
605
  * @param element
367
606
  */
368
- export const specialInblockHandle = function (editor: AlexEditor, element: AlexElement) {
607
+ export const specialInblockHandle = (editor: AlexEditor, element: AlexElement) => {
369
608
  if (element.hasChildren()) {
370
609
  element.children!.forEach(el => {
371
610
  if (isList(el, true) || isList(el, false) || isTask(el) || ['blockquote', 'pre', 'table', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'].includes(el.parsedom!)) {
package/src/core/tool.ts CHANGED
@@ -224,7 +224,7 @@ export type PluginType = (editifyInstance: ComponentInternalInstance, editTrans:
224
224
  * @param o2
225
225
  * @returns
226
226
  */
227
- export const mergeObject = function (o1: ObjectType, o2: ObjectType) {
227
+ export const mergeObject = (o1: ObjectType, o2: ObjectType) => {
228
228
  if (!DapCommon.isObject(o1) && DapCommon.isObject(o2)) {
229
229
  return null
230
230
  }
@@ -248,7 +248,7 @@ export const mergeObject = function (o1: ObjectType, o2: ObjectType) {
248
248
  * @param value
249
249
  * @returns
250
250
  */
251
- export const queryHasValue = function (obj: ObjectType, name: string, value?: string | number) {
251
+ export const queryHasValue = (obj: ObjectType, name: string, value?: string | number) => {
252
252
  //如果value不存在则判断是否拥有属性name
253
253
  if (value == null || value == undefined) {
254
254
  return obj.hasOwnProperty(name)
@@ -293,7 +293,7 @@ export const queryHasValue = function (obj: ObjectType, name: string, value?: st
293
293
  * @param data
294
294
  * @returns
295
295
  */
296
- export const cloneData = function (data: any) {
296
+ export const cloneData = (data: any) => {
297
297
  if (DapCommon.isObject(data) || Array.isArray(data)) {
298
298
  return JSON.parse(JSON.stringify(data))
299
299
  }
@@ -305,7 +305,7 @@ export const cloneData = function (data: any) {
305
305
  * @param editTrans
306
306
  * @returns
307
307
  */
308
- export const getButtonOptionsConfig = function (editTrans: (key: string) => any): ButtonOptionsConfigType {
308
+ export const getButtonOptionsConfig = (editTrans: (key: string) => any): ButtonOptionsConfigType => {
309
309
  return {
310
310
  //标题配置
311
311
  heading: [
@@ -506,7 +506,7 @@ export const getButtonOptionsConfig = function (editTrans: (key: string) => any)
506
506
  * @param editLocale
507
507
  * @returns
508
508
  */
509
- export const getToolbarConfig = function (editTrans: (key: string) => any, editLocale: LocaleType): ToolbarConfigType {
509
+ export const getToolbarConfig = (editTrans: (key: string) => any, editLocale: LocaleType): ToolbarConfigType => {
510
510
  return {
511
511
  //是否使用工具条
512
512
  use: true,
@@ -756,7 +756,7 @@ export const getToolbarConfig = function (editTrans: (key: string) => any, editL
756
756
  * @param editLocale
757
757
  * @returns
758
758
  */
759
- export const getMenuConfig = function (editTrans: (key: string) => any, editLocale: LocaleType): MenuConfigType {
759
+ export const getMenuConfig = (editTrans: (key: string) => any, editLocale: LocaleType): MenuConfigType => {
760
760
  return {
761
761
  //是否使用菜单栏
762
762
  use: true,
@@ -232,6 +232,10 @@
232
232
  cursor: col-resize;
233
233
  user-select: none;
234
234
  }
235
+
236
+ &[data-editify-merged] {
237
+ display: none;
238
+ }
235
239
  }
236
240
  }
237
241
  }
@@ -261,6 +265,11 @@
261
265
  vertical-align: text-bottom;
262
266
  margin: 0 2px;
263
267
  max-width: 100%;
268
+ min-width: 100px;
269
+
270
+ &:hover {
271
+ cursor: pointer;
272
+ }
264
273
  }
265
274
  //视频样式
266
275
  :deep(video) {
@@ -273,6 +282,7 @@
273
282
  object-fit: contain;
274
283
  margin: 0 2px;
275
284
  max-width: 100%;
285
+ min-width: 100px;
276
286
  }
277
287
  //引用样式
278
288
  :deep(blockquote) {