quill-table-up 2.4.1 → 2.4.2
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 +8 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +30 -23
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +34 -27
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -4
- package/src/__tests__/e2e/table-blots.test.ts +47 -0
- package/src/__tests__/e2e/table-hack.test.ts +5 -5
- package/src/__tests__/e2e/table-keyboard-handler.test.ts +157 -3
- package/src/__tests__/e2e/table-selection.test.ts +0 -109
- package/src/__tests__/unit/table-cell-merge.test.ts +79 -6
- package/src/__tests__/unit/table-clipboard.test.ts +138 -182
- package/src/__tests__/unit/table-hack.test.ts +73 -73
- package/src/__tests__/unit/table-insert.test.ts +35 -32
- package/src/__tests__/unit/table-redo-undo.test.ts +98 -20
- package/src/__tests__/unit/table-remove.test.ts +8 -8
- package/src/__tests__/unit/utils.test.ts +4 -4
- package/src/__tests__/unit/utils.ts +1 -1
- package/src/formats/table-cell-format.ts +33 -7
- package/src/formats/table-cell-inner-format.ts +23 -1
- package/src/modules/table-menu/constants.ts +12 -1
- package/src/modules/table-selection.ts +6 -4
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/src/style/index.less +6 -3
- package/src/svg/convert-cell.svg +7 -0
- package/src/utils/is.ts +1 -0
- package/src/utils/types.ts +1 -0
|
@@ -160,7 +160,7 @@ describe('table undo', () => {
|
|
|
160
160
|
</div>
|
|
161
161
|
<p><br></p>
|
|
162
162
|
`,
|
|
163
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
163
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
164
164
|
);
|
|
165
165
|
});
|
|
166
166
|
|
|
@@ -234,7 +234,7 @@ describe('table undo', () => {
|
|
|
234
234
|
</div>
|
|
235
235
|
<p><br></p>
|
|
236
236
|
`,
|
|
237
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
237
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
238
238
|
);
|
|
239
239
|
});
|
|
240
240
|
|
|
@@ -374,7 +374,7 @@ describe('table undo', () => {
|
|
|
374
374
|
</div>
|
|
375
375
|
<p><br></p>
|
|
376
376
|
`,
|
|
377
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
377
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
378
378
|
);
|
|
379
379
|
quill.history.undo();
|
|
380
380
|
await vi.runAllTimersAsync();
|
|
@@ -384,7 +384,7 @@ describe('table undo', () => {
|
|
|
384
384
|
${createTableHTML(4, 4)}
|
|
385
385
|
<p><br></p>
|
|
386
386
|
`,
|
|
387
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
387
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
388
388
|
);
|
|
389
389
|
});
|
|
390
390
|
|
|
@@ -467,7 +467,7 @@ describe('table undo', () => {
|
|
|
467
467
|
</div>
|
|
468
468
|
<p><br></p>
|
|
469
469
|
`,
|
|
470
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
470
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
471
471
|
);
|
|
472
472
|
quill.history.undo();
|
|
473
473
|
await vi.runAllTimersAsync();
|
|
@@ -477,7 +477,7 @@ describe('table undo', () => {
|
|
|
477
477
|
${createTableHTML(5, 5)}
|
|
478
478
|
<p><br></p>
|
|
479
479
|
`,
|
|
480
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
480
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
481
481
|
);
|
|
482
482
|
});
|
|
483
483
|
|
|
@@ -564,7 +564,7 @@ describe('table undo', () => {
|
|
|
564
564
|
</div>
|
|
565
565
|
<p><br></p>
|
|
566
566
|
`,
|
|
567
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
567
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
568
568
|
);
|
|
569
569
|
quill.history.undo();
|
|
570
570
|
await vi.runAllTimersAsync();
|
|
@@ -574,7 +574,7 @@ describe('table undo', () => {
|
|
|
574
574
|
${createTableHTML(5, 5)}
|
|
575
575
|
<p><br></p>
|
|
576
576
|
`,
|
|
577
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
577
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
578
578
|
);
|
|
579
579
|
});
|
|
580
580
|
|
|
@@ -654,7 +654,7 @@ describe('table undo', () => {
|
|
|
654
654
|
</div>
|
|
655
655
|
<p><br></p>
|
|
656
656
|
`,
|
|
657
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] },
|
|
657
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] },
|
|
658
658
|
);
|
|
659
659
|
quill.history.undo();
|
|
660
660
|
await vi.runAllTimersAsync();
|
|
@@ -664,7 +664,7 @@ describe('table undo', () => {
|
|
|
664
664
|
${createTableHTML(5, 5)}
|
|
665
665
|
<p><br></p>
|
|
666
666
|
`,
|
|
667
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
667
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
668
668
|
);
|
|
669
669
|
});
|
|
670
670
|
|
|
@@ -717,7 +717,7 @@ describe('table undo', () => {
|
|
|
717
717
|
`;
|
|
718
718
|
expect(quill.root).toEqualHTML(
|
|
719
719
|
afterColHtml,
|
|
720
|
-
{ ignoreAttrs: ['class', 'style', 'data-full', 'data-table-id', 'data-row-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
720
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-full', 'data-table-id', 'data-row-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
721
721
|
);
|
|
722
722
|
quill.history.undo();
|
|
723
723
|
await vi.runAllTimersAsync();
|
|
@@ -733,7 +733,85 @@ describe('table undo', () => {
|
|
|
733
733
|
await vi.runAllTimersAsync();
|
|
734
734
|
expect(quill.root).toEqualHTML(
|
|
735
735
|
afterColHtml,
|
|
736
|
-
{ ignoreAttrs: ['class', 'style', 'data-full', 'data-table-id', 'data-row-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
736
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-full', 'data-table-id', 'data-row-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
737
|
+
);
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
it('undo and redo cell convert', async () => {
|
|
741
|
+
const quill = await createTable(3, 3, { full: false }, {}, { isEmpty: false });
|
|
742
|
+
const originDelta = [
|
|
743
|
+
{ insert: '\n' },
|
|
744
|
+
{ insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
|
|
745
|
+
{ insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
|
|
746
|
+
{ insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
|
|
747
|
+
{ insert: '1' },
|
|
748
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
749
|
+
{ insert: '2' },
|
|
750
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
751
|
+
{ insert: '3' },
|
|
752
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
753
|
+
{ insert: '4' },
|
|
754
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
755
|
+
{ insert: '5' },
|
|
756
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
757
|
+
{ insert: '6' },
|
|
758
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
759
|
+
{ insert: '7' },
|
|
760
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
761
|
+
{ insert: '8' },
|
|
762
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
763
|
+
{ insert: '9' },
|
|
764
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
765
|
+
{ insert: '\n' },
|
|
766
|
+
];
|
|
767
|
+
const thDelta = [
|
|
768
|
+
{ insert: '\n' },
|
|
769
|
+
{ insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
|
|
770
|
+
{ insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
|
|
771
|
+
{ insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
|
|
772
|
+
{ insert: '1' },
|
|
773
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
774
|
+
{ insert: '2' },
|
|
775
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
776
|
+
{ insert: '3' },
|
|
777
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
778
|
+
{ insert: '4' },
|
|
779
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
780
|
+
{ insert: '5' },
|
|
781
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
782
|
+
{ insert: '6' },
|
|
783
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
784
|
+
{ insert: '7' },
|
|
785
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
786
|
+
{ insert: '8' },
|
|
787
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
788
|
+
{ insert: '9' },
|
|
789
|
+
{ attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1, tag: 'th' } }, insert: '\n' },
|
|
790
|
+
{ insert: '\n' },
|
|
791
|
+
];
|
|
792
|
+
quill.setContents(originDelta);
|
|
793
|
+
const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
|
|
794
|
+
for (const td of tds) {
|
|
795
|
+
td.convertTableCell();
|
|
796
|
+
}
|
|
797
|
+
await vi.runAllTimersAsync();
|
|
798
|
+
expectDelta(
|
|
799
|
+
new Delta(thDelta),
|
|
800
|
+
quill.getContents(),
|
|
801
|
+
);
|
|
802
|
+
|
|
803
|
+
quill.history.undo();
|
|
804
|
+
await vi.runAllTimersAsync();
|
|
805
|
+
expectDelta(
|
|
806
|
+
new Delta(originDelta),
|
|
807
|
+
quill.getContents(),
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
quill.history.redo();
|
|
811
|
+
await vi.runAllTimersAsync();
|
|
812
|
+
expectDelta(
|
|
813
|
+
new Delta(thDelta),
|
|
814
|
+
quill.getContents(),
|
|
737
815
|
);
|
|
738
816
|
});
|
|
739
817
|
});
|
|
@@ -799,7 +877,7 @@ describe('undo cell attribute', () => {
|
|
|
799
877
|
</div>
|
|
800
878
|
<p><br></p>
|
|
801
879
|
`,
|
|
802
|
-
{ ignoreAttrs: ['class', 'data-table-id', 'contenteditable'] },
|
|
880
|
+
{ ignoreAttrs: ['data-tag', 'class', 'data-table-id', 'contenteditable'] },
|
|
803
881
|
);
|
|
804
882
|
quill.history.undo();
|
|
805
883
|
await vi.runAllTimersAsync();
|
|
@@ -809,7 +887,7 @@ describe('undo cell attribute', () => {
|
|
|
809
887
|
${createTableHTML(2, 2)}
|
|
810
888
|
<p><br></p>
|
|
811
889
|
`,
|
|
812
|
-
{ ignoreAttrs: ['class', 'data-table-id', 'contenteditable'] },
|
|
890
|
+
{ ignoreAttrs: ['data-tag', 'class', 'data-table-id', 'contenteditable'] },
|
|
813
891
|
);
|
|
814
892
|
});
|
|
815
893
|
|
|
@@ -953,7 +1031,7 @@ describe('undo cell attribute', () => {
|
|
|
953
1031
|
</div>
|
|
954
1032
|
<p><br></p>
|
|
955
1033
|
`,
|
|
956
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1034
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
957
1035
|
);
|
|
958
1036
|
|
|
959
1037
|
quill.history.undo();
|
|
@@ -996,7 +1074,7 @@ describe('undo cell attribute', () => {
|
|
|
996
1074
|
</div>
|
|
997
1075
|
<p><br></p>
|
|
998
1076
|
`,
|
|
999
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1077
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1000
1078
|
);
|
|
1001
1079
|
|
|
1002
1080
|
quill.history.redo();
|
|
@@ -1037,7 +1115,7 @@ describe('undo cell attribute', () => {
|
|
|
1037
1115
|
</div>
|
|
1038
1116
|
<p><br></p>
|
|
1039
1117
|
`,
|
|
1040
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1118
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1041
1119
|
);
|
|
1042
1120
|
});
|
|
1043
1121
|
|
|
@@ -1101,7 +1179,7 @@ describe('undo cell attribute', () => {
|
|
|
1101
1179
|
</div>
|
|
1102
1180
|
<p><br></p>
|
|
1103
1181
|
`,
|
|
1104
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1182
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1105
1183
|
);
|
|
1106
1184
|
|
|
1107
1185
|
quill.history.undo();
|
|
@@ -1144,7 +1222,7 @@ describe('undo cell attribute', () => {
|
|
|
1144
1222
|
</div>
|
|
1145
1223
|
<p><br></p>
|
|
1146
1224
|
`,
|
|
1147
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1225
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1148
1226
|
);
|
|
1149
1227
|
|
|
1150
1228
|
quill.history.redo();
|
|
@@ -1185,7 +1263,7 @@ describe('undo cell attribute', () => {
|
|
|
1185
1263
|
</div>
|
|
1186
1264
|
<p><br></p>
|
|
1187
1265
|
`,
|
|
1188
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1266
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
1189
1267
|
);
|
|
1190
1268
|
});
|
|
1191
1269
|
|
|
@@ -40,7 +40,7 @@ describe('remove column from table', () => {
|
|
|
40
40
|
</div>
|
|
41
41
|
<p><br></p>
|
|
42
42
|
`,
|
|
43
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
43
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
44
44
|
);
|
|
45
45
|
});
|
|
46
46
|
|
|
@@ -70,7 +70,7 @@ describe('remove column from table', () => {
|
|
|
70
70
|
</div>
|
|
71
71
|
<p><br></p>
|
|
72
72
|
`,
|
|
73
|
-
{ ignoreAttrs: ['class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
73
|
+
{ ignoreAttrs: ['data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
74
74
|
);
|
|
75
75
|
});
|
|
76
76
|
|
|
@@ -131,7 +131,7 @@ describe('remove column from table', () => {
|
|
|
131
131
|
</div>
|
|
132
132
|
<p><br></p>
|
|
133
133
|
`,
|
|
134
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
134
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
135
135
|
);
|
|
136
136
|
});
|
|
137
137
|
});
|
|
@@ -162,7 +162,7 @@ describe('remove row from table', () => {
|
|
|
162
162
|
</div>
|
|
163
163
|
<p><br></p>
|
|
164
164
|
`,
|
|
165
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
165
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
166
166
|
);
|
|
167
167
|
});
|
|
168
168
|
|
|
@@ -197,7 +197,7 @@ describe('remove row from table', () => {
|
|
|
197
197
|
</div>
|
|
198
198
|
<p><br></p>
|
|
199
199
|
`,
|
|
200
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
200
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
201
201
|
);
|
|
202
202
|
});
|
|
203
203
|
});
|
|
@@ -217,7 +217,7 @@ describe('unusual delete', () => {
|
|
|
217
217
|
await vi.runAllTimersAsync();
|
|
218
218
|
expect(quill.root).toEqualHTML(
|
|
219
219
|
`<p><br></p>`,
|
|
220
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
220
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
221
221
|
);
|
|
222
222
|
});
|
|
223
223
|
|
|
@@ -279,7 +279,7 @@ describe('unusual delete', () => {
|
|
|
279
279
|
</div>
|
|
280
280
|
<p><br></p>
|
|
281
281
|
`,
|
|
282
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
282
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
283
283
|
);
|
|
284
284
|
});
|
|
285
285
|
|
|
@@ -338,7 +338,7 @@ describe('unusual delete', () => {
|
|
|
338
338
|
</div>
|
|
339
339
|
<p><br></p>
|
|
340
340
|
`,
|
|
341
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
341
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] },
|
|
342
342
|
);
|
|
343
343
|
});
|
|
344
344
|
});
|
|
@@ -283,7 +283,7 @@ describe('test override format', () => {
|
|
|
283
283
|
${createTableHTML(2, 2)}
|
|
284
284
|
<p><br></p>
|
|
285
285
|
`,
|
|
286
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
286
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
287
287
|
);
|
|
288
288
|
const tableModule = quill.getModule(TableUp.moduleName) as TableUp;
|
|
289
289
|
const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
|
|
@@ -391,7 +391,7 @@ describe('test override format', () => {
|
|
|
391
391
|
</div>
|
|
392
392
|
<p><br></p>
|
|
393
393
|
`,
|
|
394
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
394
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
395
395
|
);
|
|
396
396
|
});
|
|
397
397
|
|
|
@@ -544,7 +544,7 @@ describe('test override format', () => {
|
|
|
544
544
|
</div>
|
|
545
545
|
<p><br></p>
|
|
546
546
|
`,
|
|
547
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
547
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
548
548
|
);
|
|
549
549
|
});
|
|
550
550
|
|
|
@@ -705,7 +705,7 @@ describe('test override format', () => {
|
|
|
705
705
|
</div>
|
|
706
706
|
<p><br></p>
|
|
707
707
|
`,
|
|
708
|
-
{ ignoreAttrs: ['class', 'style', 'data-table-id', 'contenteditable'] },
|
|
708
|
+
{ ignoreAttrs: ['data-tag', 'class', 'style', 'data-table-id', 'contenteditable'] },
|
|
709
709
|
);
|
|
710
710
|
});
|
|
711
711
|
});
|
|
@@ -215,7 +215,7 @@ export function createTableBodyHTML(row: number, col: number, options?: Partial<
|
|
|
215
215
|
<tr ${datasetTableId(tableId)} data-row-id="${i + 1}">
|
|
216
216
|
${
|
|
217
217
|
new Array(col).fill(0).map((_, j) => `<td rowspan="1" colspan="1" ${datasetTableId(tableId)} data-row-id="${i + 1}" data-col-id="${j + 1}">
|
|
218
|
-
<div ${datasetTableId(tableId)} data-rowspan="1" data-colspan="1" data-row-id="${i + 1}" data-col-id="${j + 1}"${contenteditableString(editable)}>
|
|
218
|
+
<div data-tag="td" ${datasetTableId(tableId)} data-rowspan="1" data-colspan="1" data-row-id="${i + 1}" data-col-id="${j + 1}"${contenteditableString(editable)}>
|
|
219
219
|
<p>
|
|
220
220
|
${isEmpty ? '<br>' : i * row + j + 1}
|
|
221
221
|
</p>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TableCellValue } from '../utils';
|
|
2
|
-
import { blotName, findParentBlot, toCamelCase } from '../utils';
|
|
2
|
+
import { blotName, ensureArray, findParentBlot, toCamelCase } from '../utils';
|
|
3
3
|
import { ContainerFormat } from './container-format';
|
|
4
4
|
import { TableCellInnerFormat } from './table-cell-inner-format';
|
|
5
5
|
import { TableRowFormat } from './table-row-format';
|
|
@@ -34,8 +34,10 @@ export class TableCellFormat extends ContainerFormat {
|
|
|
34
34
|
colspan,
|
|
35
35
|
style,
|
|
36
36
|
emptyRow,
|
|
37
|
+
tag = 'td',
|
|
37
38
|
} = value;
|
|
38
|
-
const node =
|
|
39
|
+
const node = document.createElement(tag);
|
|
40
|
+
node.classList.add(...ensureArray(this.className));
|
|
39
41
|
node.dataset.tableId = tableId;
|
|
40
42
|
node.dataset.rowId = rowId;
|
|
41
43
|
node.dataset.colId = colId;
|
|
@@ -59,6 +61,7 @@ export class TableCellFormat extends ContainerFormat {
|
|
|
59
61
|
colId,
|
|
60
62
|
rowspan: getValidCellspan(rowspan),
|
|
61
63
|
colspan: getValidCellspan(colspan),
|
|
64
|
+
tag: domNode.tagName.toLowerCase(),
|
|
62
65
|
};
|
|
63
66
|
|
|
64
67
|
const inlineStyles: Record<string, any> = {};
|
|
@@ -82,6 +85,11 @@ export class TableCellFormat extends ContainerFormat {
|
|
|
82
85
|
return value;
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
isChildHeadTableCellInner() {
|
|
89
|
+
const headChild = this.children.head;
|
|
90
|
+
return headChild && headChild.statics.blotName === blotName.tableCellInner;
|
|
91
|
+
}
|
|
92
|
+
|
|
85
93
|
setFormatValue(name: string, value?: any) {
|
|
86
94
|
if (this.statics.allowAttrs.has(name) || this.statics.allowDataAttrs.has(name)) {
|
|
87
95
|
let attrName = name;
|
|
@@ -104,15 +112,14 @@ export class TableCellFormat extends ContainerFormat {
|
|
|
104
112
|
}
|
|
105
113
|
}
|
|
106
114
|
|
|
107
|
-
const headChild = this.children.head
|
|
115
|
+
const headChild = this.children.head!;
|
|
108
116
|
if (
|
|
109
|
-
this.
|
|
110
|
-
&&
|
|
111
|
-
&& headChild.statics.blotName === blotName.tableCellInner
|
|
117
|
+
this.isChildHeadTableCellInner()
|
|
118
|
+
&& this.domNode.style.cssText
|
|
112
119
|
// only update if data not match. avoid optimize circular updates
|
|
113
120
|
&& this.domNode.style.cssText !== (headChild.domNode as HTMLElement).dataset.style
|
|
114
121
|
) {
|
|
115
|
-
(headChild
|
|
122
|
+
(headChild.domNode as HTMLElement).dataset.style = this.domNode.style.cssText;
|
|
116
123
|
}
|
|
117
124
|
}
|
|
118
125
|
|
|
@@ -230,6 +237,25 @@ export class TableCellFormat extends ContainerFormat {
|
|
|
230
237
|
return this.children.head as TableCellInnerFormat;
|
|
231
238
|
}
|
|
232
239
|
|
|
240
|
+
convertTableCell() {
|
|
241
|
+
const value = this.statics.formats(this.domNode);
|
|
242
|
+
const tag = value.tag === 'td' ? 'th' : 'td';
|
|
243
|
+
|
|
244
|
+
const headChild = this.children.head!;
|
|
245
|
+
if (
|
|
246
|
+
this.isChildHeadTableCellInner()
|
|
247
|
+
// only update if data not match. avoid optimize circular updates
|
|
248
|
+
&& (headChild.domNode as HTMLElement).dataset.tag !== tag
|
|
249
|
+
) {
|
|
250
|
+
(headChild.domNode as HTMLElement).dataset.tag = tag;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
this.replaceWith(blotName.tableCell, {
|
|
254
|
+
...value,
|
|
255
|
+
tag,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
233
259
|
checkMerge(): boolean {
|
|
234
260
|
const { colId, rowId, colspan, rowspan } = this;
|
|
235
261
|
const next = this.next as TableCellFormat;
|
|
@@ -40,6 +40,7 @@ export class TableCellInnerFormat extends ContainerFormat {
|
|
|
40
40
|
colspan,
|
|
41
41
|
style,
|
|
42
42
|
emptyRow,
|
|
43
|
+
tag = 'td',
|
|
43
44
|
} = value;
|
|
44
45
|
const node = super.create() as HTMLElement;
|
|
45
46
|
node.dataset.tableId = tableId;
|
|
@@ -47,6 +48,7 @@ export class TableCellInnerFormat extends ContainerFormat {
|
|
|
47
48
|
node.dataset.colId = colId;
|
|
48
49
|
node.dataset.rowspan = String(getValidCellspan(rowspan));
|
|
49
50
|
node.dataset.colspan = String(getValidCellspan(colspan));
|
|
51
|
+
node.dataset.tag = tag;
|
|
50
52
|
style && (node.dataset.style = style);
|
|
51
53
|
try {
|
|
52
54
|
emptyRow && (node.dataset.emptyRow = JSON.stringify(emptyRow));
|
|
@@ -56,13 +58,23 @@ export class TableCellInnerFormat extends ContainerFormat {
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
static formats(domNode: HTMLElement) {
|
|
59
|
-
const {
|
|
61
|
+
const {
|
|
62
|
+
tableId,
|
|
63
|
+
rowId,
|
|
64
|
+
colId,
|
|
65
|
+
rowspan,
|
|
66
|
+
colspan,
|
|
67
|
+
style,
|
|
68
|
+
emptyRow,
|
|
69
|
+
tag = 'td',
|
|
70
|
+
} = domNode.dataset;
|
|
60
71
|
const value: Record<string, any> = {
|
|
61
72
|
tableId: String(tableId),
|
|
62
73
|
rowId: String(rowId),
|
|
63
74
|
colId: String(colId),
|
|
64
75
|
rowspan: Number(getValidCellspan(rowspan)),
|
|
65
76
|
colspan: Number(getValidCellspan(colspan)),
|
|
77
|
+
tag,
|
|
66
78
|
};
|
|
67
79
|
style && (value.style = style);
|
|
68
80
|
try {
|
|
@@ -98,6 +110,10 @@ export class TableCellInnerFormat extends ContainerFormat {
|
|
|
98
110
|
}
|
|
99
111
|
}
|
|
100
112
|
|
|
113
|
+
this.clearCache();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
clearCache() {
|
|
101
117
|
const blocks = this.descendants(Block, 0);
|
|
102
118
|
for (const child of blocks) {
|
|
103
119
|
(child as TypeBlock).cache = {};
|
|
@@ -178,6 +194,12 @@ export class TableCellInnerFormat extends ContainerFormat {
|
|
|
178
194
|
}
|
|
179
195
|
}
|
|
180
196
|
|
|
197
|
+
convertTableCell() {
|
|
198
|
+
if (this.parent.statics.blotName !== blotName.tableCell) return;
|
|
199
|
+
this.parent.convertTableCell();
|
|
200
|
+
this.clearCache();
|
|
201
|
+
}
|
|
202
|
+
|
|
181
203
|
formatAt(index: number, length: number, name: string, value: any) {
|
|
182
204
|
if (this.children.length === 0) {
|
|
183
205
|
this.appendChild(this.scroll.create(this.statics.defaultChild.blotName));
|
|
@@ -4,6 +4,7 @@ import Quill from 'quill';
|
|
|
4
4
|
import AutoFull from '../../svg/auto-full.svg';
|
|
5
5
|
import Background from '../../svg/background.svg';
|
|
6
6
|
import Border from '../../svg/border.svg';
|
|
7
|
+
import ConvertCell from '../../svg/convert-cell.svg';
|
|
7
8
|
import Copy from '../../svg/copy.svg';
|
|
8
9
|
import Cut from '../../svg/cut.svg';
|
|
9
10
|
import InsertBottom from '../../svg/insert-bottom.svg';
|
|
@@ -176,7 +177,7 @@ export const tableMenuTools: Record<string, Tool> = {
|
|
|
176
177
|
name: 'InsertCaption',
|
|
177
178
|
icon: TableHead,
|
|
178
179
|
tip: 'Insert table caption',
|
|
179
|
-
handle(tableModule) {
|
|
180
|
+
handle: (tableModule) => {
|
|
180
181
|
if (!tableModule.table) return;
|
|
181
182
|
const tableMainBlot = Quill.find(tableModule.table) as TableMainFormat;
|
|
182
183
|
if (!tableMainBlot) return;
|
|
@@ -187,6 +188,16 @@ export const tableMenuTools: Record<string, Tool> = {
|
|
|
187
188
|
tableMainBlot.insertBefore(tableCaption, tableMainBlot.children.head);
|
|
188
189
|
},
|
|
189
190
|
},
|
|
191
|
+
ToggleTdBetweenTh: {
|
|
192
|
+
name: 'ToggleTdBetweenTh',
|
|
193
|
+
icon: ConvertCell,
|
|
194
|
+
tip: 'Toggle td between th',
|
|
195
|
+
handle: (tableModule, selectedTds) => {
|
|
196
|
+
for (const td of selectedTds) {
|
|
197
|
+
td.convertTableCell();
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
},
|
|
190
201
|
};
|
|
191
202
|
|
|
192
203
|
export const maxSaveColorCount = 10;
|
|
@@ -525,18 +525,20 @@ export class TableSelection {
|
|
|
525
525
|
|
|
526
526
|
removeCell = (e: KeyboardEvent) => {
|
|
527
527
|
const range = this.quill.getSelection();
|
|
528
|
-
|
|
528
|
+
const activeElement = document.activeElement;
|
|
529
|
+
if (range || (e.key !== 'Backspace' && e.key !== 'Delete') || !this.quill.root.contains(activeElement)) return;
|
|
529
530
|
|
|
530
|
-
for (const td of this.selectedTds) {
|
|
531
|
-
td.deleteAt(0, td.length() - 1);
|
|
532
|
-
}
|
|
533
531
|
if (this.table) {
|
|
534
532
|
const tableMain = Quill.find(this.table) as TableMainFormat;
|
|
535
533
|
const cells = tableMain.descendants(TableCellInnerFormat);
|
|
536
534
|
if (this.selectedTds.length === cells.length) {
|
|
537
535
|
tableMain.remove();
|
|
536
|
+
return;
|
|
538
537
|
}
|
|
539
538
|
}
|
|
539
|
+
for (const td of this.selectedTds) {
|
|
540
|
+
td.deleteAt(0, td.length() - 1);
|
|
541
|
+
}
|
|
540
542
|
};
|
|
541
543
|
|
|
542
544
|
showDisplay() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"3.2.3","results":[[":__tests__/unit/utils.test-d.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-clipboard.test.ts",{"duration":
|
|
1
|
+
{"version":"3.2.3","results":[[":__tests__/unit/utils.test-d.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-clipboard.test.ts",{"duration":7348.2325000000055,"failed":false}],[":__tests__/unit/table-redo-undo.test.ts",{"duration":7314.907299999999,"failed":false}],[":__tests__/unit/table-hack.test.ts",{"duration":2628.3711000000003,"failed":false}],[":__tests__/unit/table-cell-merge.test.ts",{"duration":2576.8806999999997,"failed":false}],[":__tests__/unit/table-insert.test.ts",{"duration":4933.0411,"failed":false}],[":__tests__/unit/table-blots.test.ts",{"duration":2238.9622,"failed":false}],[":__tests__/unit/utils.test.ts",{"duration":1362.8192000000004,"failed":false}],[":__tests__/unit/table-remove.test.ts",{"duration":1996.3753999999994,"failed":false}],[":__tests__/unit/table-caption.test.ts",{"duration":1237.1392,"failed":false}]]}
|
package/src/style/index.less
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
|
2
|
+
<!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
|
|
3
|
+
<path
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
d="M11 21V9H3V5q0-.825.588-1.412T5 3h14q.825 0 1.413.588T21 5v14q0 .825-.587 1.413T19 21zm2-2h6v-4h-6zm0-6h6V9h-6zM5 7h14V5H5zM3 22v-2h2.55q-1.2-.575-1.937-1.7t-.738-2.55q0-1.975 1.388-3.363T7.625 11v2q-1.125 0-1.937.8t-.813 1.95q0 .975.6 1.725t1.525.95V16h2v6z"
|
|
6
|
+
/>
|
|
7
|
+
</svg>
|
package/src/utils/is.ts
CHANGED
|
@@ -5,3 +5,4 @@ export const isString = (val: unknown): val is string => typeof val === 'string'
|
|
|
5
5
|
export const isNumber = (val: unknown): val is number => typeof val === 'number';
|
|
6
6
|
export const isObject = (val: unknown): val is Record<any, any> => val !== null && typeof val === 'object';
|
|
7
7
|
export const isValidCellspan = (val: unknown): boolean => !Number.isNaN(val) && Number(val) > 0;
|
|
8
|
+
export const ensureArray = <T>(val: T | T[]): T[] => isArray(val) ? val : [val];
|