quill-table-up 3.1.2 → 3.2.1
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/README.md +15 -8
- package/dist/index.css +1 -1
- package/dist/index.d.ts +168 -146
- package/dist/index.js +47 -47
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +52 -52
- package/dist/index.umd.js.map +1 -1
- package/package.json +22 -24
- package/src/__tests__/e2e/custom-creator.test.ts +44 -44
- package/src/__tests__/e2e/editor-page.ts +77 -77
- package/src/__tests__/e2e/table-align.test.ts +104 -104
- package/src/__tests__/e2e/table-blots.test.ts +169 -169
- package/src/__tests__/e2e/table-caption.test.ts +134 -134
- package/src/__tests__/e2e/table-clipboard.test.ts +20 -20
- package/src/__tests__/e2e/table-hack.test.ts +151 -151
- package/src/__tests__/e2e/table-keyboard-handler.test.ts +20 -4
- package/src/__tests__/e2e/table-menu.test.ts +172 -172
- package/src/__tests__/e2e/table-resize.test.ts +654 -9
- package/src/__tests__/e2e/table-scrollbar.test.ts +144 -144
- package/src/__tests__/e2e/table-selection.test.ts +563 -563
- package/src/__tests__/e2e/types.d.ts +8 -7
- package/src/__tests__/e2e/utils.ts +52 -52
- package/src/__tests__/unit/table-blots.test.ts +720 -720
- package/src/__tests__/unit/table-caption.test.ts +234 -234
- package/src/__tests__/unit/table-cell-merge.test.ts +713 -724
- package/src/__tests__/unit/table-clipboard.test.ts +2176 -2176
- package/src/__tests__/unit/table-hack.test.ts +1014 -1014
- package/src/__tests__/unit/table-insert.test.ts +915 -926
- package/src/__tests__/unit/table-redo-undo.test.ts +2429 -2429
- package/src/__tests__/unit/table-remove.test.ts +313 -343
- package/src/__tests__/unit/utils.test-d.ts +49 -49
- package/src/__tests__/unit/utils.test.ts +711 -711
- package/src/__tests__/unit/utils.ts +307 -307
- package/src/__tests__/unit/vitest.d.ts +14 -14
- package/src/formats/container-format.ts +107 -107
- package/src/formats/overrides/block-embed.ts +72 -72
- package/src/formats/overrides/block.ts +95 -95
- package/src/formats/overrides/index.ts +3 -3
- package/src/formats/overrides/scroll.ts +70 -70
- package/src/formats/table-body-format.ts +52 -52
- package/src/formats/table-caption-format.ts +116 -116
- package/src/formats/table-cell-format.ts +304 -304
- package/src/formats/table-cell-inner-format.ts +403 -398
- package/src/formats/table-colgroup-format.ts +136 -136
- package/src/formats/table-foot-format.ts +7 -7
- package/src/formats/table-head-format.ts +7 -7
- package/src/formats/table-main-format.ts +1 -1
- package/src/formats/table-row-format.ts +218 -210
- package/src/formats/utils.ts +6 -6
- package/src/index.ts +19 -19
- package/src/modules/index.ts +7 -7
- package/src/modules/table-align.ts +131 -131
- package/src/modules/table-clipboard/table-clipboard.ts +6 -8
- package/src/modules/table-dom-selector.ts +33 -33
- package/src/modules/table-menu/constants.ts +223 -223
- package/src/modules/table-menu/index.ts +4 -4
- package/src/modules/table-menu/table-menu-common.ts +330 -329
- package/src/modules/table-menu/table-menu-contextmenu.ts +111 -118
- package/src/modules/table-menu/table-menu-select.ts +96 -94
- package/src/modules/table-resize/index.ts +5 -5
- package/src/modules/table-resize/table-resize-box.ts +714 -363
- package/src/modules/table-resize/table-resize-common.ts +246 -382
- package/src/modules/table-resize/table-resize-drag.ts +241 -0
- package/src/modules/table-resize/table-resize-line.ts +244 -182
- package/src/modules/table-resize/table-resize-scale.ts +174 -173
- package/src/modules/table-resize/utils.ts +84 -3
- package/src/modules/table-scrollbar.ts +292 -292
- package/src/modules/table-selection.ts +613 -669
- package/src/style/button.less +45 -45
- package/src/style/color-picker.less +136 -136
- package/src/style/dialog.less +53 -53
- package/src/style/functions.less +9 -9
- package/src/style/index.less +120 -120
- package/src/style/input.less +64 -64
- package/src/style/select-box.less +52 -52
- package/src/style/table-creator.less +56 -56
- package/src/style/table-menu.less +125 -125
- package/src/style/table-resize-scale.less +31 -31
- package/src/style/table-resize.less +249 -202
- package/src/style/table-scrollbar.less +49 -49
- package/src/style/table-selection.less +23 -23
- package/src/style/tooltip.less +19 -19
- package/src/style/variables.less +1 -1
- package/src/svg/arrow-up-down.svg +11 -11
- package/src/svg/convert-cell.svg +7 -7
- package/src/table-up.ts +1363 -1360
- package/src/types.d.ts +4 -4
- package/src/utils/bem.ts +23 -23
- package/src/utils/blot-helper.ts +101 -105
- package/src/utils/color.ts +109 -109
- package/src/utils/components/button.ts +22 -22
- package/src/utils/components/color-picker.ts +236 -236
- package/src/utils/components/dialog.ts +83 -41
- package/src/utils/components/index.ts +6 -6
- package/src/utils/components/input.ts +74 -74
- package/src/utils/components/table/creator.ts +89 -89
- package/src/utils/components/table/index.ts +2 -2
- package/src/utils/components/table/select-box.ts +78 -78
- package/src/utils/components/tooltip.ts +179 -189
- package/src/utils/constants.ts +125 -124
- package/src/utils/drag-helper.ts +112 -0
- package/src/utils/index.ts +15 -14
- package/src/utils/is.ts +9 -9
- package/src/utils/position.ts +60 -60
- package/src/utils/resize-observer-helper.ts +47 -47
- package/src/utils/scroll.ts +145 -47
- package/src/utils/style-helper.ts +47 -47
- package/src/utils/transformer.ts +10 -10
- package/src/utils/transition-event-helper.ts +8 -8
- package/src/utils/types.ts +156 -157
- package/src/utils/utils.ts +12 -12
|
@@ -1,398 +1,403 @@
|
|
|
1
|
-
import type { Parchment as TypeParchment } from 'quill';
|
|
2
|
-
import type TypeBlock from 'quill/blots/block';
|
|
3
|
-
import type { BlockEmbed as TypeBlockEmbed } from 'quill/blots/block';
|
|
4
|
-
import type TypeScroll from 'quill/blots/scroll';
|
|
5
|
-
import type { TableBodyTag, TableCellValue } from '../utils';
|
|
6
|
-
import type { TableCellFormat } from './table-cell-format';
|
|
7
|
-
import Quill from 'quill';
|
|
8
|
-
import { blotName, cssTextToObject, findParentBlot, findParentBlots, toCamelCase } from '../utils';
|
|
9
|
-
import { ContainerFormat } from './container-format';
|
|
10
|
-
import { TableBodyFormat } from './table-body-format';
|
|
11
|
-
import { getValidCellspan, isSameCellValue } from './utils';
|
|
12
|
-
|
|
13
|
-
const Block = Quill.import('blots/block') as TypeParchment.BlotConstructor;
|
|
14
|
-
const BlockEmbed = Quill.import('blots/block/embed') as typeof TypeBlockEmbed;
|
|
15
|
-
|
|
16
|
-
export class TableCellInnerFormat extends ContainerFormat {
|
|
17
|
-
static blotName = blotName.tableCellInner;
|
|
18
|
-
static tagName = 'div';
|
|
19
|
-
static className = 'ql-table-cell-inner';
|
|
20
|
-
static allowDataAttrs: Set<string> = new Set(['table-id', 'row-id', 'col-id', 'rowspan', 'colspan', 'empty-row', 'wrap-tag']);
|
|
21
|
-
static defaultChild: TypeParchment.BlotConstructor = Block;
|
|
22
|
-
declare parent: TableCellFormat;
|
|
23
|
-
// keep `isAllowStyle` and `allowStyle` same with TableCellFormat
|
|
24
|
-
static allowStyle = new Set(['background-color', 'border', 'height']);
|
|
25
|
-
static isAllowStyle(str: string): boolean {
|
|
26
|
-
const cssAttrName = toCamelCase(str);
|
|
27
|
-
for (const style of this.allowStyle) {
|
|
28
|
-
// cause `cssTextToObject` will transform css string to camel case style name
|
|
29
|
-
if (cssAttrName.startsWith(toCamelCase(style))) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
static create(value: TableCellValue) {
|
|
37
|
-
const {
|
|
38
|
-
tableId,
|
|
39
|
-
rowId,
|
|
40
|
-
colId,
|
|
41
|
-
rowspan,
|
|
42
|
-
colspan,
|
|
43
|
-
style,
|
|
44
|
-
emptyRow,
|
|
45
|
-
tag = 'td',
|
|
46
|
-
wrapTag = 'tbody',
|
|
47
|
-
} = value;
|
|
48
|
-
const node = super.create() as HTMLElement;
|
|
49
|
-
node.dataset.tableId = tableId;
|
|
50
|
-
node.dataset.rowId = rowId;
|
|
51
|
-
node.dataset.colId = colId;
|
|
52
|
-
node.dataset.rowspan = String(getValidCellspan(rowspan));
|
|
53
|
-
node.dataset.colspan = String(getValidCellspan(colspan));
|
|
54
|
-
node.dataset.tag = tag;
|
|
55
|
-
node.dataset.wrapTag = wrapTag;
|
|
56
|
-
style && (node.dataset.style = style);
|
|
57
|
-
try {
|
|
58
|
-
emptyRow && (node.dataset.emptyRow = JSON.stringify(emptyRow));
|
|
59
|
-
}
|
|
60
|
-
catch {}
|
|
61
|
-
return node;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
static formats(domNode: HTMLElement) {
|
|
65
|
-
const {
|
|
66
|
-
tableId,
|
|
67
|
-
rowId,
|
|
68
|
-
colId,
|
|
69
|
-
rowspan,
|
|
70
|
-
colspan,
|
|
71
|
-
style,
|
|
72
|
-
emptyRow,
|
|
73
|
-
tag = 'td',
|
|
74
|
-
wrapTag = 'tbody',
|
|
75
|
-
} = domNode.dataset;
|
|
76
|
-
const value: Record<string, any> = {
|
|
77
|
-
tableId: String(tableId),
|
|
78
|
-
rowId: String(rowId),
|
|
79
|
-
colId: String(colId),
|
|
80
|
-
rowspan: Number(getValidCellspan(rowspan)),
|
|
81
|
-
colspan: Number(getValidCellspan(colspan)),
|
|
82
|
-
tag,
|
|
83
|
-
wrapTag,
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
style && (value.style = style);
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
emptyRow && (value.emptyRow = JSON.parse(emptyRow));
|
|
90
|
-
}
|
|
91
|
-
catch {}
|
|
92
|
-
|
|
93
|
-
return value;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
constructor(scroll: TypeScroll, domNode: HTMLElement, _value: TableCellValue) {
|
|
97
|
-
super(scroll, domNode);
|
|
98
|
-
domNode.setAttribute('contenteditable', String(scroll.isEnabled()));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
setFormatValue(name: string, value?: any, isStyle: boolean = false) {
|
|
102
|
-
if (isStyle) {
|
|
103
|
-
if (!this.statics.isAllowStyle(name)) return;
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
super.setFormatValue(name, value);
|
|
107
|
-
}
|
|
108
|
-
if (this.parent && this.parent.statics.blotName === blotName.tableCell) {
|
|
109
|
-
this.parent.setFormatValue(name, value);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
this.clearCache();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
clearCache() {
|
|
116
|
-
const blocks = this.descendants(Block, 0);
|
|
117
|
-
for (const child of blocks) {
|
|
118
|
-
(child as TypeBlock).cache = {};
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
get tableId() {
|
|
123
|
-
return this.domNode.dataset.tableId!;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
get rowId() {
|
|
127
|
-
return this.domNode.dataset.rowId!;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
set rowId(value) {
|
|
131
|
-
this.setFormatValue('row-id', value);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
get colId() {
|
|
135
|
-
return this.domNode.dataset.colId!;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
set colId(value) {
|
|
139
|
-
this.setFormatValue('col-id', value);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
get rowspan() {
|
|
143
|
-
return Number(this.domNode.dataset.rowspan);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
set rowspan(value: number) {
|
|
147
|
-
this.setFormatValue('rowspan', value);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
get colspan() {
|
|
151
|
-
return Number(this.domNode.dataset.colspan);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
set colspan(value: number) {
|
|
155
|
-
this.setFormatValue('colspan', value);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
get emptyRow(): string[] {
|
|
159
|
-
try {
|
|
160
|
-
return JSON.parse(this.domNode.dataset.emptyRow!);
|
|
161
|
-
}
|
|
162
|
-
catch {
|
|
163
|
-
return [];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
set emptyRow(value: string[]) {
|
|
168
|
-
// if value same as currentEmptyRow, do nothing
|
|
169
|
-
if (this.emptyRow.toString() === value.toString()) return;
|
|
170
|
-
|
|
171
|
-
try {
|
|
172
|
-
if (value.length > 0) {
|
|
173
|
-
this.setFormatValue('empty-row', JSON.stringify(value), false);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
this.setFormatValue('empty-row', null, false);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
catch {
|
|
180
|
-
this.setFormatValue('empty-row', null, false);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
set wrapTag(value: TableBodyTag) {
|
|
185
|
-
this.setFormatValue('wrap-tag', value);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
get wrapTag() {
|
|
189
|
-
return this.domNode.dataset.wrapTag as TableBodyTag || 'tbody';
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
getColumnIndex() {
|
|
193
|
-
const
|
|
194
|
-
return
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (this.
|
|
312
|
-
this.
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
this.
|
|
318
|
-
}
|
|
319
|
-
else
|
|
320
|
-
|
|
321
|
-
if
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
1
|
+
import type { Parchment as TypeParchment } from 'quill';
|
|
2
|
+
import type TypeBlock from 'quill/blots/block';
|
|
3
|
+
import type { BlockEmbed as TypeBlockEmbed } from 'quill/blots/block';
|
|
4
|
+
import type TypeScroll from 'quill/blots/scroll';
|
|
5
|
+
import type { TableBodyTag, TableCellValue } from '../utils';
|
|
6
|
+
import type { TableCellFormat } from './table-cell-format';
|
|
7
|
+
import Quill from 'quill';
|
|
8
|
+
import { blotName, cssTextToObject, findParentBlot, findParentBlots, toCamelCase } from '../utils';
|
|
9
|
+
import { ContainerFormat } from './container-format';
|
|
10
|
+
import { TableBodyFormat } from './table-body-format';
|
|
11
|
+
import { getValidCellspan, isSameCellValue } from './utils';
|
|
12
|
+
|
|
13
|
+
const Block = Quill.import('blots/block') as TypeParchment.BlotConstructor;
|
|
14
|
+
const BlockEmbed = Quill.import('blots/block/embed') as typeof TypeBlockEmbed;
|
|
15
|
+
|
|
16
|
+
export class TableCellInnerFormat extends ContainerFormat {
|
|
17
|
+
static blotName = blotName.tableCellInner;
|
|
18
|
+
static tagName = 'div';
|
|
19
|
+
static className = 'ql-table-cell-inner';
|
|
20
|
+
static allowDataAttrs: Set<string> = new Set(['table-id', 'row-id', 'col-id', 'rowspan', 'colspan', 'empty-row', 'wrap-tag']);
|
|
21
|
+
static defaultChild: TypeParchment.BlotConstructor = Block;
|
|
22
|
+
declare parent: TableCellFormat;
|
|
23
|
+
// keep `isAllowStyle` and `allowStyle` same with TableCellFormat
|
|
24
|
+
static allowStyle = new Set(['background-color', 'border', 'height']);
|
|
25
|
+
static isAllowStyle(str: string): boolean {
|
|
26
|
+
const cssAttrName = toCamelCase(str);
|
|
27
|
+
for (const style of this.allowStyle) {
|
|
28
|
+
// cause `cssTextToObject` will transform css string to camel case style name
|
|
29
|
+
if (cssAttrName.startsWith(toCamelCase(style))) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static create(value: TableCellValue) {
|
|
37
|
+
const {
|
|
38
|
+
tableId,
|
|
39
|
+
rowId,
|
|
40
|
+
colId,
|
|
41
|
+
rowspan,
|
|
42
|
+
colspan,
|
|
43
|
+
style,
|
|
44
|
+
emptyRow,
|
|
45
|
+
tag = 'td',
|
|
46
|
+
wrapTag = 'tbody',
|
|
47
|
+
} = value;
|
|
48
|
+
const node = super.create() as HTMLElement;
|
|
49
|
+
node.dataset.tableId = tableId;
|
|
50
|
+
node.dataset.rowId = rowId;
|
|
51
|
+
node.dataset.colId = colId;
|
|
52
|
+
node.dataset.rowspan = String(getValidCellspan(rowspan));
|
|
53
|
+
node.dataset.colspan = String(getValidCellspan(colspan));
|
|
54
|
+
node.dataset.tag = tag;
|
|
55
|
+
node.dataset.wrapTag = wrapTag;
|
|
56
|
+
style && (node.dataset.style = style);
|
|
57
|
+
try {
|
|
58
|
+
emptyRow && (node.dataset.emptyRow = JSON.stringify(emptyRow));
|
|
59
|
+
}
|
|
60
|
+
catch {}
|
|
61
|
+
return node;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static formats(domNode: HTMLElement) {
|
|
65
|
+
const {
|
|
66
|
+
tableId,
|
|
67
|
+
rowId,
|
|
68
|
+
colId,
|
|
69
|
+
rowspan,
|
|
70
|
+
colspan,
|
|
71
|
+
style,
|
|
72
|
+
emptyRow,
|
|
73
|
+
tag = 'td',
|
|
74
|
+
wrapTag = 'tbody',
|
|
75
|
+
} = domNode.dataset;
|
|
76
|
+
const value: Record<string, any> = {
|
|
77
|
+
tableId: String(tableId),
|
|
78
|
+
rowId: String(rowId),
|
|
79
|
+
colId: String(colId),
|
|
80
|
+
rowspan: Number(getValidCellspan(rowspan)),
|
|
81
|
+
colspan: Number(getValidCellspan(colspan)),
|
|
82
|
+
tag,
|
|
83
|
+
wrapTag,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
style && (value.style = style);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
emptyRow && (value.emptyRow = JSON.parse(emptyRow));
|
|
90
|
+
}
|
|
91
|
+
catch {}
|
|
92
|
+
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
constructor(scroll: TypeScroll, domNode: HTMLElement, _value: TableCellValue) {
|
|
97
|
+
super(scroll, domNode);
|
|
98
|
+
domNode.setAttribute('contenteditable', String(scroll.isEnabled()));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
setFormatValue(name: string, value?: any, isStyle: boolean = false) {
|
|
102
|
+
if (isStyle) {
|
|
103
|
+
if (!this.statics.isAllowStyle(name)) return;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
super.setFormatValue(name, value);
|
|
107
|
+
}
|
|
108
|
+
if (this.parent && this.parent.statics.blotName === blotName.tableCell) {
|
|
109
|
+
this.parent.setFormatValue(name, value);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.clearCache();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
clearCache() {
|
|
116
|
+
const blocks = this.descendants(Block, 0);
|
|
117
|
+
for (const child of blocks) {
|
|
118
|
+
(child as TypeBlock).cache = {};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get tableId() {
|
|
123
|
+
return this.domNode.dataset.tableId!;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
get rowId() {
|
|
127
|
+
return this.domNode.dataset.rowId!;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
set rowId(value) {
|
|
131
|
+
this.setFormatValue('row-id', value);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get colId() {
|
|
135
|
+
return this.domNode.dataset.colId!;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
set colId(value) {
|
|
139
|
+
this.setFormatValue('col-id', value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get rowspan() {
|
|
143
|
+
return Number(this.domNode.dataset.rowspan);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
set rowspan(value: number) {
|
|
147
|
+
this.setFormatValue('rowspan', value);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get colspan() {
|
|
151
|
+
return Number(this.domNode.dataset.colspan);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
set colspan(value: number) {
|
|
155
|
+
this.setFormatValue('colspan', value);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get emptyRow(): string[] {
|
|
159
|
+
try {
|
|
160
|
+
return JSON.parse(this.domNode.dataset.emptyRow!);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
set emptyRow(value: string[]) {
|
|
168
|
+
// if value same as currentEmptyRow, do nothing
|
|
169
|
+
if (this.emptyRow.toString() === value.toString()) return;
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
if (value.length > 0) {
|
|
173
|
+
this.setFormatValue('empty-row', JSON.stringify(value), false);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
this.setFormatValue('empty-row', null, false);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
this.setFormatValue('empty-row', null, false);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
set wrapTag(value: TableBodyTag) {
|
|
185
|
+
this.setFormatValue('wrap-tag', value);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
get wrapTag() {
|
|
189
|
+
return this.domNode.dataset.wrapTag as TableBodyTag || 'tbody';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getColumnIndex() {
|
|
193
|
+
const tableBlot = findParentBlot(this, blotName.tableMain);
|
|
194
|
+
return tableBlot.getColIds().indexOf(this.colId);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
getRowIndex() {
|
|
198
|
+
const tableBlot = findParentBlot(this, blotName.tableMain);
|
|
199
|
+
return tableBlot.getRowIds().indexOf(this.rowId);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getTableBody() {
|
|
203
|
+
let target: TypeParchment.Parent = this.parent;
|
|
204
|
+
while (target && !(target instanceof TableBodyFormat) && target !== this.scroll) {
|
|
205
|
+
target = target.parent;
|
|
206
|
+
}
|
|
207
|
+
if (target === this.scroll) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
return target as TableBodyFormat;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getTableRow() {
|
|
214
|
+
try {
|
|
215
|
+
return findParentBlot(this, blotName.tableRow);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
setStyleByString(styleStr: string) {
|
|
223
|
+
const style = cssTextToObject(styleStr);
|
|
224
|
+
for (const [name, value] of Object.entries(style)) {
|
|
225
|
+
this.setFormatValue(name, value, true);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
convertTableCell() {
|
|
230
|
+
if (this.parent.statics.blotName !== blotName.tableCell) return;
|
|
231
|
+
this.parent.convertTableCell();
|
|
232
|
+
this.clearCache();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
formatAt(index: number, length: number, name: string, value: any) {
|
|
236
|
+
if (this.children.length === 0) {
|
|
237
|
+
const defaultChild = this.scroll.create(this.statics.defaultChild.blotName);
|
|
238
|
+
this.appendChild(defaultChild);
|
|
239
|
+
// block min length is 1
|
|
240
|
+
length += defaultChild.length();
|
|
241
|
+
}
|
|
242
|
+
super.formatAt(index, length, name, value);
|
|
243
|
+
// set style for `td`
|
|
244
|
+
if (value?.style) {
|
|
245
|
+
this.setStyleByString(value.style);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
insertAt(index: number, value: string, def?: any): void {
|
|
250
|
+
const [child] = this.children.find(index);
|
|
251
|
+
// always keep TableCellInner not empty
|
|
252
|
+
if (!child && this.statics.defaultChild) {
|
|
253
|
+
const defaultChild = this.scroll.create(this.statics.defaultChild.blotName || 'block');
|
|
254
|
+
this.appendChild(defaultChild);
|
|
255
|
+
}
|
|
256
|
+
super.insertAt(index, value, def);
|
|
257
|
+
// BlockEmbed will have a \n in delta, this will effect history stack
|
|
258
|
+
// so when insert a BlockEmbed, if current child length <= 1 then remove it
|
|
259
|
+
const blot = def == null
|
|
260
|
+
? this.scroll.create('text', value)
|
|
261
|
+
: this.scroll.create(value, def);
|
|
262
|
+
if (blot instanceof BlockEmbed && child && child.length() <= 1) {
|
|
263
|
+
child.remove();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
formats(): Record<string, any> {
|
|
268
|
+
const value = this.statics.formats(this.domNode);
|
|
269
|
+
return {
|
|
270
|
+
[this.statics.blotName]: value,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
checkMerge(): boolean {
|
|
275
|
+
const { colId, rowId, colspan, rowspan } = this;
|
|
276
|
+
const next = this.next as TableCellInnerFormat;
|
|
277
|
+
return (
|
|
278
|
+
next !== null
|
|
279
|
+
&& next.statics.blotName === this.statics.blotName
|
|
280
|
+
&& next.rowId === rowId
|
|
281
|
+
&& next.colId === colId
|
|
282
|
+
&& next.colspan === colspan
|
|
283
|
+
&& next.rowspan === rowspan
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
optimize() {
|
|
288
|
+
const parent = this.parent;
|
|
289
|
+
const blotValue = this.statics.formats(this.domNode);
|
|
290
|
+
// handle BlockEmbed to insert tableCellInner when setContents
|
|
291
|
+
if (this.prev && this.prev instanceof BlockEmbed) {
|
|
292
|
+
const prev = this.prev;
|
|
293
|
+
this.insertBefore(prev, this.children.head);
|
|
294
|
+
if (this.length() <= 1) {
|
|
295
|
+
const afterBlock = this.scroll.create('block');
|
|
296
|
+
this.insertBefore(afterBlock, prev.next);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const parentNotTableCell = parent !== null && parent.statics.blotName !== blotName.tableCell;
|
|
300
|
+
if (parentNotTableCell) {
|
|
301
|
+
this.wrap(blotName.tableCell, blotValue);
|
|
302
|
+
// when insert delta like: [ { attributes: { 'table-up-cell-inner': { ... } }, insert: '\n' }, { attributes: { 'table-up-cell-inner': { ... } }, insert: '\n' }, ...]
|
|
303
|
+
// that delta will create dom like: <td><div></div></td>... . that means TableCellInner will be an empty cell without 'block'
|
|
304
|
+
// in this case, a 'block' should to inserted to makesure that the cell will not be remove
|
|
305
|
+
if (this.children.length === 0) {
|
|
306
|
+
const child = this.scroll.create(this.statics.defaultChild.blotName);
|
|
307
|
+
this.appendChild(child);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (this.children.length > 0 && this.next != null && this.checkMerge()) {
|
|
312
|
+
this.next.moveChildren(this);
|
|
313
|
+
this.next.remove();
|
|
314
|
+
}
|
|
315
|
+
// TODO: uiNode not test, maybe have bug
|
|
316
|
+
if (this.uiNode != null && this.uiNode !== this.domNode.firstChild) {
|
|
317
|
+
this.domNode.insertBefore(this.uiNode, this.domNode.firstChild);
|
|
318
|
+
}
|
|
319
|
+
// this is necessary when redo or undo. else will delete or insert wrong index
|
|
320
|
+
if (this.children.length === 0) {
|
|
321
|
+
// if cellInner doesn't have child then remove it. not insert a block
|
|
322
|
+
this.remove();
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
// update delta data
|
|
326
|
+
if (
|
|
327
|
+
this.domNode.dataset.style
|
|
328
|
+
&& parentNotTableCell
|
|
329
|
+
&& parent.domNode.style.cssText !== this.domNode.dataset.style
|
|
330
|
+
) {
|
|
331
|
+
this.setStyleByString(this.domNode.dataset.style);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
insertBefore(blot: TypeParchment.Blot, ref?: TypeParchment.Blot | null) {
|
|
337
|
+
if (blot.statics.blotName === this.statics.blotName) {
|
|
338
|
+
const cellInnerBlot = blot as TableCellInnerFormat;
|
|
339
|
+
const cellInnerBlotValue = this.statics.formats(cellInnerBlot.domNode);
|
|
340
|
+
const selfValue = this.statics.formats(this.domNode);
|
|
341
|
+
const isSame = isSameCellValue(selfValue, cellInnerBlotValue);
|
|
342
|
+
|
|
343
|
+
if (!isSame) {
|
|
344
|
+
const [selfRow, selfCell] = findParentBlots(this, [blotName.tableRow, blotName.tableCell] as const);
|
|
345
|
+
let cellRef: TypeParchment.Blot = selfCell;
|
|
346
|
+
// split current cellInner
|
|
347
|
+
if (ref) {
|
|
348
|
+
const index = ref.offset();
|
|
349
|
+
const length = this.length();
|
|
350
|
+
if (index !== 0 && index < length) {
|
|
351
|
+
const newCellInner = this.split(index)!;
|
|
352
|
+
const newCell = newCellInner.wrap(blotName.tableCell, selfValue);
|
|
353
|
+
selfRow.insertBefore(newCell, selfCell.next);
|
|
354
|
+
cellRef = newCell;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (this.tableId !== cellInnerBlot.tableId) {
|
|
358
|
+
const selfTableWrapper = findParentBlot(this, blotName.tableWrapper);
|
|
359
|
+
const index = this.offset(selfTableWrapper);
|
|
360
|
+
const afterSelfTableWrapper = selfTableWrapper.split(index);
|
|
361
|
+
return selfTableWrapper.parent.insertBefore(cellInnerBlot, afterSelfTableWrapper);
|
|
362
|
+
}
|
|
363
|
+
// different rowId. split current row
|
|
364
|
+
if (this.rowId !== cellInnerBlot.rowId) {
|
|
365
|
+
let rowRef: TypeParchment.Blot | null = selfRow;
|
|
366
|
+
const splitRef = ref;
|
|
367
|
+
if (splitRef) {
|
|
368
|
+
const index = splitRef.offset(selfRow);
|
|
369
|
+
rowRef = selfRow.split(index);
|
|
370
|
+
}
|
|
371
|
+
const row = this.scroll.create(blotName.tableRow, cellInnerBlotValue) as TypeParchment.Parent;
|
|
372
|
+
const cell = this.scroll.create(blotName.tableCell, cellInnerBlotValue) as TypeParchment.Parent;
|
|
373
|
+
cell.appendChild(cellInnerBlot);
|
|
374
|
+
row.appendChild(cell);
|
|
375
|
+
return selfRow.parent.insertBefore(row, rowRef);
|
|
376
|
+
}
|
|
377
|
+
return selfRow.insertBefore(
|
|
378
|
+
cellInnerBlot.wrap(blotName.tableCell, cellInnerBlotValue),
|
|
379
|
+
cellRef,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
const next = this.split(ref ? ref.offset() : 0);
|
|
384
|
+
return this.parent.insertBefore(cellInnerBlot, next);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
else if (blot.statics.blotName === blotName.tableCol) {
|
|
388
|
+
try {
|
|
389
|
+
const bodyBlot = findParentBlot(this, blotName.tableBody);
|
|
390
|
+
const index = this.offset(bodyBlot);
|
|
391
|
+
const next = bodyBlot.split(index);
|
|
392
|
+
bodyBlot.parent.insertBefore(blot, next);
|
|
393
|
+
blot.optimize({});
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
// here should not trigger
|
|
397
|
+
console.warn('TableCellInner not in TableBody');
|
|
398
|
+
}
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
super.insertBefore(blot, ref);
|
|
402
|
+
}
|
|
403
|
+
}
|