quill-table-up 3.4.0 → 3.5.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 +12 -10
- package/dist/index.d.ts +6 -1
- package/dist/index.js +29 -29
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +27 -27
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/unit/table-clipboard.test.ts +674 -108
- package/src/__tests__/unit/table-hack.test.ts +402 -1
- package/src/modules/table-clipboard/table-clipboard.ts +142 -34
- package/src/modules/table-selection.ts +22 -2
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/src/table-up.ts +44 -10
- package/src/utils/index.ts +1 -1
- package/src/utils/{style-helper.ts → style/helper.ts} +1 -1
- package/src/utils/style/index.ts +2 -0
- package/src/utils/style/inline-core.ts +80 -0
- package/src/utils/types.ts +2 -0
|
@@ -2,6 +2,7 @@ import Quill from 'quill';
|
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
import { TableCellInnerFormat } from '../../formats';
|
|
4
4
|
import { TableUp } from '../../table-up';
|
|
5
|
+
import { parseCSSRules } from '../../utils';
|
|
5
6
|
import { createQuillWithTableModule, createTableBodyHTML, createTableCaptionHTML, createTableDeltaOps, createTableHTML, createTaleColHTML, datasetTag, expectDelta, replaceAttrEmptyRow, simulatePasteHTML } from './utils';
|
|
6
7
|
|
|
7
8
|
const Delta = Quill.import('delta');
|
|
@@ -246,7 +247,7 @@ describe('clipboard cell structure', () => {
|
|
|
246
247
|
});
|
|
247
248
|
|
|
248
249
|
it('clipboard convert multiple merged cell 3', async () => {
|
|
249
|
-
const quill = createQuillWithTableModule(`<p><br></p
|
|
250
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
250
251
|
quill.setContents(
|
|
251
252
|
quill.clipboard.convert({
|
|
252
253
|
html: '<table><tbody><tr><td rowspan="3">merge1</td><td colspan="2">merge2</td><td>3</td></tr><tr><td rowspan="2">merge3</td><td>1</td><td>4</td></tr><tr><td>2</td><td>5</td></tr></tbody></table>',
|
|
@@ -579,7 +580,7 @@ describe('clipboard cell structure', () => {
|
|
|
579
580
|
});
|
|
580
581
|
|
|
581
582
|
it('clipboard convert empty cell should not ignore', async () => {
|
|
582
|
-
const quill = createQuillWithTableModule(`<p><br></p
|
|
583
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
583
584
|
quill.setContents(
|
|
584
585
|
quill.clipboard.convert({
|
|
585
586
|
html: `<table><tbody><tr><th>q</th><th>w</th><th>e</th></tr><tr><th></th><td>2</td><td>3</td></tr><tr><th></th><td>4</td><td>5</td></tr></tbody></table>`,
|
|
@@ -744,7 +745,7 @@ describe('clipboard cell structure', () => {
|
|
|
744
745
|
});
|
|
745
746
|
|
|
746
747
|
it('convert background on table/tbody/tr/td', async () => {
|
|
747
|
-
const quill = createQuillWithTableModule(`<p><br></p
|
|
748
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
748
749
|
quill.setContents(
|
|
749
750
|
quill.clipboard.convert({
|
|
750
751
|
html: `
|
|
@@ -825,7 +826,7 @@ describe('clipboard cell structure', () => {
|
|
|
825
826
|
});
|
|
826
827
|
|
|
827
828
|
it('clipboard convert should generate colgroup at correct position', async () => {
|
|
828
|
-
const quill = createQuillWithTableModule(`<p><br></p
|
|
829
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
829
830
|
quill.setContents(
|
|
830
831
|
quill.clipboard.convert({
|
|
831
832
|
html: '<table class="ql-table" data-table-id="0u473v7j5th" cellpadding="0" cellspacing="0"><tbody data-table-id="0u473v7j5th"><tr class="ql-table-row" data-table-id="0u473v7j5th" data-row-id="1de78ie70hj"><td class="ql-table-cell" data-table-id="0u473v7j5th" data-row-id="1de78ie70hj" data-col-id="0025lmzkmn85x" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="0u473v7j5th" data-row-id="1de78ie70hj" data-col-id="0025lmzkmn85x" data-rowspan="1" data-colspan="1" contenteditable="true"><p>1</p></div></td><td class="ql-table-cell" data-table-id="0u473v7j5th" data-row-id="1de78ie70hj" data-col-id="g8v4waukxpe" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="0u473v7j5th" data-row-id="1de78ie70hj" data-col-id="g8v4waukxpe" data-rowspan="1" data-colspan="1" contenteditable="true"><p>2</p></div></td><td class="ql-table-cell" data-table-id="0u473v7j5th" data-row-id="1de78ie70hj" data-col-id="7ubw564uue5" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="0u473v7j5th" data-row-id="1de78ie70hj" data-col-id="7ubw564uue5" data-rowspan="1" data-colspan="1" contenteditable="true"><p>3</p></div></td></tr></tbody><caption class="ql-table-caption" data-table-id="0u473v7j5th" contenteditable="true">title</caption></table>',
|
|
@@ -958,7 +959,7 @@ describe('clipboard cell structure', () => {
|
|
|
958
959
|
});
|
|
959
960
|
|
|
960
961
|
it('clipboard convert empty multiple tr to `emptyRow`', async () => {
|
|
961
|
-
const quill = createQuillWithTableModule('<p><br></p>', { autoMergeCell: false });
|
|
962
|
+
const quill = createQuillWithTableModule('<p><br></p>', { autoMergeCell: false, full: false });
|
|
962
963
|
quill.setContents(
|
|
963
964
|
quill.clipboard.convert({
|
|
964
965
|
html: `<table><tbody><tr><td rowspan="3" colspan="3">1</td></tr><tr></tr><tr></tr><tr><td>2</td><td>3</td><td>4</td></tr></tbody></table>`,
|
|
@@ -1117,7 +1118,7 @@ describe('clipboard cell structure', () => {
|
|
|
1117
1118
|
});
|
|
1118
1119
|
|
|
1119
1120
|
it('clipboard convert empty tr to `emptyRow` in thead', async () => {
|
|
1120
|
-
const quill = createQuillWithTableModule(`<p><br></p>`, { autoMergeCell: false });
|
|
1121
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { autoMergeCell: false, full: false });
|
|
1121
1122
|
quill.setContents(
|
|
1122
1123
|
quill.clipboard.convert({
|
|
1123
1124
|
html: `<table><thead><tr><td rowspan="2" colspan="2">1</td></tr><tr></tr></thead><tbody><tr><td>1</td><td>2</td></tr><tr><td>1</td><td>2</td></tr></tbody></table>`,
|
|
@@ -1190,106 +1191,8 @@ describe('clipboard cell structure', () => {
|
|
|
1190
1191
|
);
|
|
1191
1192
|
});
|
|
1192
1193
|
|
|
1193
|
-
it('clipboard convert col with span attribute', async () => {
|
|
1194
|
-
const quill = createQuillWithTableModule(`<p><br></p>`, { autoMergeCell: false });
|
|
1195
|
-
quill.setContents(
|
|
1196
|
-
quill.clipboard.convert({
|
|
1197
|
-
html: `
|
|
1198
|
-
<body link=blue vlink=purple>
|
|
1199
|
-
|
|
1200
|
-
<table border=0 cellpadding=0 cellspacing=0 width=252 style='border-collapse:
|
|
1201
|
-
collapse;width:188pt'>
|
|
1202
|
-
<!--StartFragment-->
|
|
1203
|
-
<col width=63 span=4 style='width:47pt'>
|
|
1204
|
-
<tr height=19 style='height:14.4pt'>
|
|
1205
|
-
<td colspan=2 rowspan=6 height=114 class=xl65 width=126 style='height:86.4pt;
|
|
1206
|
-
width:94pt'>1</td>
|
|
1207
|
-
<td colspan=2 rowspan=2 class=xl65 width=126 style='width:94pt'>2</td>
|
|
1208
|
-
</tr>
|
|
1209
|
-
<tr height=19 style='height:14.4pt'>
|
|
1210
|
-
</tr>
|
|
1211
|
-
<tr height=19 style='height:14.4pt'>
|
|
1212
|
-
<td colspan=2 rowspan=2 height=38 class=xl65 style='height:28.8pt'>3</td>
|
|
1213
|
-
</tr>
|
|
1214
|
-
<tr height=19 style='height:14.4pt'>
|
|
1215
|
-
</tr>
|
|
1216
|
-
<tr height=19 style='height:14.4pt'>
|
|
1217
|
-
<td colspan=2 rowspan=2 height=38 class=xl65 style='height:28.8pt'>4</td>
|
|
1218
|
-
</tr>
|
|
1219
|
-
<tr height=19 style='height:14.4pt'>
|
|
1220
|
-
</tr>
|
|
1221
|
-
<!--EndFragment-->
|
|
1222
|
-
</table>
|
|
1223
|
-
|
|
1224
|
-
</body>
|
|
1225
|
-
`,
|
|
1226
|
-
}),
|
|
1227
|
-
);
|
|
1228
|
-
await vi.runAllTimersAsync();
|
|
1229
|
-
|
|
1230
|
-
expect(quill.root).toEqualHTML(
|
|
1231
|
-
`
|
|
1232
|
-
<p><br></p>
|
|
1233
|
-
<div>
|
|
1234
|
-
<table cellpadding="0" cellspacing="0">
|
|
1235
|
-
${createTaleColHTML(4, { full: false, width: 63 })}
|
|
1236
|
-
<tbody>
|
|
1237
|
-
<tr>
|
|
1238
|
-
<td rowspan="6" colspan="2" data-empty-row="length:1">
|
|
1239
|
-
<div data-empty-row="length:1"><p>1</p></div>
|
|
1240
|
-
</td>
|
|
1241
|
-
<td rowspan="2" colspan="2" data-empty-row="length:1">
|
|
1242
|
-
<div data-empty-row="length:1"><p>2</p></div>
|
|
1243
|
-
</td>
|
|
1244
|
-
</tr>
|
|
1245
|
-
<tr></tr>
|
|
1246
|
-
<tr>
|
|
1247
|
-
<td rowspan="2" colspan="2" data-empty-row="length:1">
|
|
1248
|
-
<div data-empty-row="length:1"><p>3</p></div>
|
|
1249
|
-
</td>
|
|
1250
|
-
</tr>
|
|
1251
|
-
<tr></tr>
|
|
1252
|
-
<tr>
|
|
1253
|
-
<td rowspan="2" colspan="2" data-empty-row="length:1">
|
|
1254
|
-
<div data-empty-row="length:1"><p>4</p></div>
|
|
1255
|
-
</td>
|
|
1256
|
-
</tr>
|
|
1257
|
-
<tr></tr>
|
|
1258
|
-
</tbody>
|
|
1259
|
-
</table>
|
|
1260
|
-
</div>
|
|
1261
|
-
<p><br></p>
|
|
1262
|
-
`,
|
|
1263
|
-
{
|
|
1264
|
-
ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'data-style', 'style', 'contenteditable'],
|
|
1265
|
-
replaceAttrs: {
|
|
1266
|
-
'data-empty-row': replaceAttrEmptyRow,
|
|
1267
|
-
},
|
|
1268
|
-
},
|
|
1269
|
-
);
|
|
1270
|
-
expectDelta(
|
|
1271
|
-
new Delta([
|
|
1272
|
-
{ insert: '\n' },
|
|
1273
|
-
{ insert: { 'table-up-col': { full: false, width: 63 } } },
|
|
1274
|
-
{ insert: { 'table-up-col': { full: false, width: 63 } } },
|
|
1275
|
-
{ insert: { 'table-up-col': { full: false, width: 63 } } },
|
|
1276
|
-
{ insert: { 'table-up-col': { full: false, width: 63 } } },
|
|
1277
|
-
{ insert: '1' },
|
|
1278
|
-
{ attributes: { 'table-up-cell-inner': { rowspan: 6, colspan: 2 } }, insert: '\n' },
|
|
1279
|
-
{ insert: '2' },
|
|
1280
|
-
{ attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' },
|
|
1281
|
-
{ insert: '3' },
|
|
1282
|
-
{ attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' },
|
|
1283
|
-
{ insert: '4' },
|
|
1284
|
-
{ attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' },
|
|
1285
|
-
{ insert: '\n' },
|
|
1286
|
-
]),
|
|
1287
|
-
quill.getContents(),
|
|
1288
|
-
);
|
|
1289
|
-
});
|
|
1290
|
-
|
|
1291
1194
|
it('clipboard convert th correctly', async () => {
|
|
1292
|
-
const quill = createQuillWithTableModule(`<p><br></p
|
|
1195
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1293
1196
|
quill.setContents(
|
|
1294
1197
|
quill.clipboard.convert({
|
|
1295
1198
|
html: `
|
|
@@ -1385,7 +1288,7 @@ describe('clipboard cell structure', () => {
|
|
|
1385
1288
|
});
|
|
1386
1289
|
|
|
1387
1290
|
it('convert thead and tfoot correctly', async () => {
|
|
1388
|
-
const quill = createQuillWithTableModule(`<p><br></p
|
|
1291
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1389
1292
|
quill.setContents(
|
|
1390
1293
|
quill.clipboard.convert({
|
|
1391
1294
|
html: `
|
|
@@ -1509,7 +1412,7 @@ describe('clipboard cell structure', () => {
|
|
|
1509
1412
|
});
|
|
1510
1413
|
|
|
1511
1414
|
it('convert thead rowspan to tbody', async () => {
|
|
1512
|
-
const quill = createQuillWithTableModule(`<p><br></p
|
|
1415
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1513
1416
|
quill.setContents(
|
|
1514
1417
|
quill.clipboard.convert({
|
|
1515
1418
|
html: `
|
|
@@ -1585,6 +1488,442 @@ describe('clipboard cell structure', () => {
|
|
|
1585
1488
|
});
|
|
1586
1489
|
});
|
|
1587
1490
|
|
|
1491
|
+
describe('clipboard column', () => {
|
|
1492
|
+
it('clipboard convert col with span attribute', async () => {
|
|
1493
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { autoMergeCell: false });
|
|
1494
|
+
quill.setContents(
|
|
1495
|
+
quill.clipboard.convert({
|
|
1496
|
+
html: `
|
|
1497
|
+
<body link=blue vlink=purple>
|
|
1498
|
+
|
|
1499
|
+
<table border=0 cellpadding=0 cellspacing=0 width=252 style='border-collapse:
|
|
1500
|
+
collapse;width:188pt'>
|
|
1501
|
+
<!--StartFragment-->
|
|
1502
|
+
<col width=63 span=4 style='width:47pt'>
|
|
1503
|
+
<tr height=19 style='height:14.4pt'>
|
|
1504
|
+
<td colspan=2 rowspan=6 height=114 class=xl65 width=126 style='height:86.4pt;
|
|
1505
|
+
width:94pt'>1</td>
|
|
1506
|
+
<td colspan=2 rowspan=2 class=xl65 width=126 style='width:94pt'>2</td>
|
|
1507
|
+
</tr>
|
|
1508
|
+
<tr height=19 style='height:14.4pt'>
|
|
1509
|
+
</tr>
|
|
1510
|
+
<tr height=19 style='height:14.4pt'>
|
|
1511
|
+
<td colspan=2 rowspan=2 height=38 class=xl65 style='height:28.8pt'>3</td>
|
|
1512
|
+
</tr>
|
|
1513
|
+
<tr height=19 style='height:14.4pt'>
|
|
1514
|
+
</tr>
|
|
1515
|
+
<tr height=19 style='height:14.4pt'>
|
|
1516
|
+
<td colspan=2 rowspan=2 height=38 class=xl65 style='height:28.8pt'>4</td>
|
|
1517
|
+
</tr>
|
|
1518
|
+
<tr height=19 style='height:14.4pt'>
|
|
1519
|
+
</tr>
|
|
1520
|
+
<!--EndFragment-->
|
|
1521
|
+
</table>
|
|
1522
|
+
|
|
1523
|
+
</body>
|
|
1524
|
+
`,
|
|
1525
|
+
}),
|
|
1526
|
+
);
|
|
1527
|
+
await vi.runAllTimersAsync();
|
|
1528
|
+
|
|
1529
|
+
expect(quill.root).toEqualHTML(
|
|
1530
|
+
`
|
|
1531
|
+
<p><br></p>
|
|
1532
|
+
<div>
|
|
1533
|
+
<table cellpadding="0" cellspacing="0">
|
|
1534
|
+
${createTaleColHTML(4, { full: false, width: 63 })}
|
|
1535
|
+
<tbody>
|
|
1536
|
+
<tr>
|
|
1537
|
+
<td rowspan="6" colspan="2" data-empty-row="length:1">
|
|
1538
|
+
<div data-empty-row="length:1"><p>1</p></div>
|
|
1539
|
+
</td>
|
|
1540
|
+
<td rowspan="2" colspan="2" data-empty-row="length:1">
|
|
1541
|
+
<div data-empty-row="length:1"><p>2</p></div>
|
|
1542
|
+
</td>
|
|
1543
|
+
</tr>
|
|
1544
|
+
<tr></tr>
|
|
1545
|
+
<tr>
|
|
1546
|
+
<td rowspan="2" colspan="2" data-empty-row="length:1">
|
|
1547
|
+
<div data-empty-row="length:1"><p>3</p></div>
|
|
1548
|
+
</td>
|
|
1549
|
+
</tr>
|
|
1550
|
+
<tr></tr>
|
|
1551
|
+
<tr>
|
|
1552
|
+
<td rowspan="2" colspan="2" data-empty-row="length:1">
|
|
1553
|
+
<div data-empty-row="length:1"><p>4</p></div>
|
|
1554
|
+
</td>
|
|
1555
|
+
</tr>
|
|
1556
|
+
<tr></tr>
|
|
1557
|
+
</tbody>
|
|
1558
|
+
</table>
|
|
1559
|
+
</div>
|
|
1560
|
+
<p><br></p>
|
|
1561
|
+
`,
|
|
1562
|
+
{
|
|
1563
|
+
ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'data-style', 'style', 'contenteditable'],
|
|
1564
|
+
replaceAttrs: {
|
|
1565
|
+
'data-empty-row': replaceAttrEmptyRow,
|
|
1566
|
+
},
|
|
1567
|
+
},
|
|
1568
|
+
);
|
|
1569
|
+
expectDelta(
|
|
1570
|
+
new Delta([
|
|
1571
|
+
{ insert: '\n' },
|
|
1572
|
+
{ insert: { 'table-up-col': { full: false, width: 63 } } },
|
|
1573
|
+
{ insert: { 'table-up-col': { full: false, width: 63 } } },
|
|
1574
|
+
{ insert: { 'table-up-col': { full: false, width: 63 } } },
|
|
1575
|
+
{ insert: { 'table-up-col': { full: false, width: 63 } } },
|
|
1576
|
+
{ insert: '1' },
|
|
1577
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 6, colspan: 2 } }, insert: '\n' },
|
|
1578
|
+
{ insert: '2' },
|
|
1579
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' },
|
|
1580
|
+
{ insert: '3' },
|
|
1581
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' },
|
|
1582
|
+
{ insert: '4' },
|
|
1583
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' },
|
|
1584
|
+
{ insert: '\n' },
|
|
1585
|
+
]),
|
|
1586
|
+
quill.getContents(),
|
|
1587
|
+
);
|
|
1588
|
+
});
|
|
1589
|
+
|
|
1590
|
+
it('convert col width with option `full: false`', async () => {
|
|
1591
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1592
|
+
quill.setContents(
|
|
1593
|
+
quill.clipboard.convert({
|
|
1594
|
+
html: `
|
|
1595
|
+
<table class="ws-table-all" id="customers">
|
|
1596
|
+
<tbody>
|
|
1597
|
+
<tr>
|
|
1598
|
+
<td>content</td>
|
|
1599
|
+
<td>content</td>
|
|
1600
|
+
<td>content</td>
|
|
1601
|
+
</tr>
|
|
1602
|
+
</tbody>
|
|
1603
|
+
</table>
|
|
1604
|
+
`,
|
|
1605
|
+
}),
|
|
1606
|
+
);
|
|
1607
|
+
await vi.runAllTimersAsync();
|
|
1608
|
+
|
|
1609
|
+
expectDelta(
|
|
1610
|
+
new Delta([
|
|
1611
|
+
{ insert: '\n' },
|
|
1612
|
+
{ insert: { 'table-up-col': { full: false, width: 100 } } },
|
|
1613
|
+
{ insert: { 'table-up-col': { full: false, width: 100 } } },
|
|
1614
|
+
{ insert: { 'table-up-col': { full: false, width: 100 } } },
|
|
1615
|
+
{ insert: 'content' },
|
|
1616
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1617
|
+
{ insert: 'content' },
|
|
1618
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1619
|
+
{ insert: 'content' },
|
|
1620
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1621
|
+
{ insert: '\n' },
|
|
1622
|
+
]),
|
|
1623
|
+
quill.getContents(),
|
|
1624
|
+
);
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
it('convert col width with option `full: true`', async () => {
|
|
1628
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: true });
|
|
1629
|
+
quill.setContents(
|
|
1630
|
+
quill.clipboard.convert({
|
|
1631
|
+
html: `
|
|
1632
|
+
<table class="ws-table-all" id="customers">
|
|
1633
|
+
<tbody>
|
|
1634
|
+
<tr>
|
|
1635
|
+
<td>content</td>
|
|
1636
|
+
<td>content</td>
|
|
1637
|
+
<td>content</td>
|
|
1638
|
+
</tr>
|
|
1639
|
+
</tbody>
|
|
1640
|
+
</table>
|
|
1641
|
+
`,
|
|
1642
|
+
}),
|
|
1643
|
+
);
|
|
1644
|
+
await vi.runAllTimersAsync();
|
|
1645
|
+
|
|
1646
|
+
expectDelta(
|
|
1647
|
+
new Delta([
|
|
1648
|
+
{ insert: '\n' },
|
|
1649
|
+
{ insert: { 'table-up-col': { full: true, width: 33.3333 } } },
|
|
1650
|
+
{ insert: { 'table-up-col': { full: true, width: 33.3333 } } },
|
|
1651
|
+
{ insert: { 'table-up-col': { full: true, width: 33.3333 } } },
|
|
1652
|
+
{ insert: 'content' },
|
|
1653
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1654
|
+
{ insert: 'content' },
|
|
1655
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1656
|
+
{ insert: 'content' },
|
|
1657
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1658
|
+
{ insert: '\n' },
|
|
1659
|
+
]),
|
|
1660
|
+
quill.getContents(),
|
|
1661
|
+
);
|
|
1662
|
+
});
|
|
1663
|
+
|
|
1664
|
+
it('convert table without colgroup should ignore td width when option `full: false`', async () => {
|
|
1665
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1666
|
+
quill.setContents(
|
|
1667
|
+
quill.clipboard.convert({
|
|
1668
|
+
html: `
|
|
1669
|
+
<table class="ws-table-all" id="customers">
|
|
1670
|
+
<tbody>
|
|
1671
|
+
<tr>
|
|
1672
|
+
<td width="220">content</td>
|
|
1673
|
+
<td width="140">content</td>
|
|
1674
|
+
<td width="180">content</td>
|
|
1675
|
+
</tr>
|
|
1676
|
+
</tbody>
|
|
1677
|
+
</table>
|
|
1678
|
+
`,
|
|
1679
|
+
}),
|
|
1680
|
+
);
|
|
1681
|
+
await vi.runAllTimersAsync();
|
|
1682
|
+
|
|
1683
|
+
expectDelta(
|
|
1684
|
+
new Delta([
|
|
1685
|
+
{ insert: '\n' },
|
|
1686
|
+
{ insert: { 'table-up-col': { full: false, width: 100 } } },
|
|
1687
|
+
{ insert: { 'table-up-col': { full: false, width: 100 } } },
|
|
1688
|
+
{ insert: { 'table-up-col': { full: false, width: 100 } } },
|
|
1689
|
+
{ insert: 'content' },
|
|
1690
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1691
|
+
{ insert: 'content' },
|
|
1692
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1693
|
+
{ insert: 'content' },
|
|
1694
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1695
|
+
{ insert: '\n' },
|
|
1696
|
+
]),
|
|
1697
|
+
quill.getContents(),
|
|
1698
|
+
);
|
|
1699
|
+
});
|
|
1700
|
+
|
|
1701
|
+
it('convert table without colgroup should ignore td width when option `full: true`', async () => {
|
|
1702
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: true });
|
|
1703
|
+
quill.setContents(
|
|
1704
|
+
quill.clipboard.convert({
|
|
1705
|
+
html: `
|
|
1706
|
+
<table class="ws-table-all" id="customers">
|
|
1707
|
+
<tbody>
|
|
1708
|
+
<tr>
|
|
1709
|
+
<td width="220">content</td>
|
|
1710
|
+
<td width="140">content</td>
|
|
1711
|
+
<td width="180">content</td>
|
|
1712
|
+
</tr>
|
|
1713
|
+
</tbody>
|
|
1714
|
+
</table>
|
|
1715
|
+
`,
|
|
1716
|
+
}),
|
|
1717
|
+
);
|
|
1718
|
+
await vi.runAllTimersAsync();
|
|
1719
|
+
|
|
1720
|
+
expectDelta(
|
|
1721
|
+
new Delta([
|
|
1722
|
+
{ insert: '\n' },
|
|
1723
|
+
{ insert: { 'table-up-col': { full: true, width: 33.3333 } } },
|
|
1724
|
+
{ insert: { 'table-up-col': { full: true, width: 33.3333 } } },
|
|
1725
|
+
{ insert: { 'table-up-col': { full: true, width: 33.3333 } } },
|
|
1726
|
+
{ insert: 'content' },
|
|
1727
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1728
|
+
{ insert: 'content' },
|
|
1729
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1730
|
+
{ insert: 'content' },
|
|
1731
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1732
|
+
{ insert: '\n' },
|
|
1733
|
+
]),
|
|
1734
|
+
quill.getContents(),
|
|
1735
|
+
);
|
|
1736
|
+
});
|
|
1737
|
+
|
|
1738
|
+
it('convert col percent width should be `full: true`', async () => {
|
|
1739
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1740
|
+
quill.setContents(
|
|
1741
|
+
quill.clipboard.convert({
|
|
1742
|
+
html: `
|
|
1743
|
+
<table class="ws-table-all" id="customers">
|
|
1744
|
+
<colgroup>
|
|
1745
|
+
<col width="25%">
|
|
1746
|
+
<col width="25%">
|
|
1747
|
+
<col width="25%">
|
|
1748
|
+
<col width="25%">
|
|
1749
|
+
</colgroup>
|
|
1750
|
+
<tbody>
|
|
1751
|
+
<tr>
|
|
1752
|
+
<td>content</td>
|
|
1753
|
+
<td>content</td>
|
|
1754
|
+
<td>content</td>
|
|
1755
|
+
<td>content</td>
|
|
1756
|
+
</tr>
|
|
1757
|
+
</tbody>
|
|
1758
|
+
</table>
|
|
1759
|
+
`,
|
|
1760
|
+
}),
|
|
1761
|
+
);
|
|
1762
|
+
await vi.runAllTimersAsync();
|
|
1763
|
+
|
|
1764
|
+
expectDelta(
|
|
1765
|
+
new Delta([
|
|
1766
|
+
{ insert: '\n' },
|
|
1767
|
+
{ insert: { 'table-up-col': { full: true, width: 25 } } },
|
|
1768
|
+
{ insert: { 'table-up-col': { full: true, width: 25 } } },
|
|
1769
|
+
{ insert: { 'table-up-col': { full: true, width: 25 } } },
|
|
1770
|
+
{ insert: { 'table-up-col': { full: true, width: 25 } } },
|
|
1771
|
+
{ insert: 'content' },
|
|
1772
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1773
|
+
{ insert: 'content' },
|
|
1774
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1775
|
+
{ insert: 'content' },
|
|
1776
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1777
|
+
{ insert: 'content' },
|
|
1778
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1779
|
+
{ insert: '\n' },
|
|
1780
|
+
]),
|
|
1781
|
+
quill.getContents(),
|
|
1782
|
+
);
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1785
|
+
it('convert col fixed width should be `full: false`', async () => {
|
|
1786
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1787
|
+
quill.setContents(
|
|
1788
|
+
quill.clipboard.convert({
|
|
1789
|
+
html: `
|
|
1790
|
+
<table class="ws-table-all" id="customers">
|
|
1791
|
+
<colgroup>
|
|
1792
|
+
<col width="120px">
|
|
1793
|
+
<col width="120px">
|
|
1794
|
+
<col width="120px">
|
|
1795
|
+
<col width="120px">
|
|
1796
|
+
</colgroup>
|
|
1797
|
+
<tbody>
|
|
1798
|
+
<tr>
|
|
1799
|
+
<td>content</td>
|
|
1800
|
+
<td>content</td>
|
|
1801
|
+
<td>content</td>
|
|
1802
|
+
<td>content</td>
|
|
1803
|
+
</tr>
|
|
1804
|
+
</tbody>
|
|
1805
|
+
</table>
|
|
1806
|
+
`,
|
|
1807
|
+
}),
|
|
1808
|
+
);
|
|
1809
|
+
await vi.runAllTimersAsync();
|
|
1810
|
+
|
|
1811
|
+
expectDelta(
|
|
1812
|
+
new Delta([
|
|
1813
|
+
{ insert: '\n' },
|
|
1814
|
+
{ insert: { 'table-up-col': { full: false, width: 120 } } },
|
|
1815
|
+
{ insert: { 'table-up-col': { full: false, width: 120 } } },
|
|
1816
|
+
{ insert: { 'table-up-col': { full: false, width: 120 } } },
|
|
1817
|
+
{ insert: { 'table-up-col': { full: false, width: 120 } } },
|
|
1818
|
+
{ insert: 'content' },
|
|
1819
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1820
|
+
{ insert: 'content' },
|
|
1821
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1822
|
+
{ insert: 'content' },
|
|
1823
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1824
|
+
{ insert: 'content' },
|
|
1825
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1826
|
+
{ insert: '\n' },
|
|
1827
|
+
]),
|
|
1828
|
+
quill.getContents(),
|
|
1829
|
+
);
|
|
1830
|
+
});
|
|
1831
|
+
|
|
1832
|
+
it('convert mixed col width should follow option `full: false`', async () => {
|
|
1833
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1834
|
+
quill.setContents(
|
|
1835
|
+
quill.clipboard.convert({
|
|
1836
|
+
html: `
|
|
1837
|
+
<table class="ws-table-all" id="customers" style="width: 500px;">
|
|
1838
|
+
<colgroup>
|
|
1839
|
+
<col width="100px">
|
|
1840
|
+
<col width="20%">
|
|
1841
|
+
<col width="30%">
|
|
1842
|
+
<col width="150px">
|
|
1843
|
+
</colgroup>
|
|
1844
|
+
<tbody>
|
|
1845
|
+
<tr>
|
|
1846
|
+
<td>content</td>
|
|
1847
|
+
<td>content</td>
|
|
1848
|
+
<td>content</td>
|
|
1849
|
+
<td>content</td>
|
|
1850
|
+
</tr>
|
|
1851
|
+
</tbody>
|
|
1852
|
+
</table>
|
|
1853
|
+
`,
|
|
1854
|
+
}),
|
|
1855
|
+
);
|
|
1856
|
+
await vi.runAllTimersAsync();
|
|
1857
|
+
|
|
1858
|
+
expectDelta(
|
|
1859
|
+
new Delta([
|
|
1860
|
+
{ insert: '\n' },
|
|
1861
|
+
{ insert: { 'table-up-col': { full: false, width: 100 } } },
|
|
1862
|
+
{ insert: { 'table-up-col': { full: false, width: 100 } } },
|
|
1863
|
+
{ insert: { 'table-up-col': { full: false, width: 150 } } },
|
|
1864
|
+
{ insert: { 'table-up-col': { full: false, width: 150 } } },
|
|
1865
|
+
{ insert: 'content' },
|
|
1866
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1867
|
+
{ insert: 'content' },
|
|
1868
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1869
|
+
{ insert: 'content' },
|
|
1870
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1871
|
+
{ insert: 'content' },
|
|
1872
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1873
|
+
{ insert: '\n' },
|
|
1874
|
+
]),
|
|
1875
|
+
quill.getContents(),
|
|
1876
|
+
);
|
|
1877
|
+
});
|
|
1878
|
+
|
|
1879
|
+
it('convert mixed col width should follow option `full: true`', async () => {
|
|
1880
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: true });
|
|
1881
|
+
quill.setContents(
|
|
1882
|
+
quill.clipboard.convert({
|
|
1883
|
+
html: `
|
|
1884
|
+
<table class="ws-table-all" id="customers" style="width: 500px;">
|
|
1885
|
+
<colgroup>
|
|
1886
|
+
<col width="100px">
|
|
1887
|
+
<col width="20%">
|
|
1888
|
+
<col width="30%">
|
|
1889
|
+
<col width="150px">
|
|
1890
|
+
</colgroup>
|
|
1891
|
+
<tbody>
|
|
1892
|
+
<tr>
|
|
1893
|
+
<td>content</td>
|
|
1894
|
+
<td>content</td>
|
|
1895
|
+
<td>content</td>
|
|
1896
|
+
<td>content</td>
|
|
1897
|
+
</tr>
|
|
1898
|
+
</tbody>
|
|
1899
|
+
</table>
|
|
1900
|
+
`,
|
|
1901
|
+
}),
|
|
1902
|
+
);
|
|
1903
|
+
await vi.runAllTimersAsync();
|
|
1904
|
+
|
|
1905
|
+
expectDelta(
|
|
1906
|
+
new Delta([
|
|
1907
|
+
{ insert: '\n' },
|
|
1908
|
+
{ insert: { 'table-up-col': { full: true, width: 20 } } },
|
|
1909
|
+
{ insert: { 'table-up-col': { full: true, width: 20 } } },
|
|
1910
|
+
{ insert: { 'table-up-col': { full: true, width: 30 } } },
|
|
1911
|
+
{ insert: { 'table-up-col': { full: true, width: 30 } } },
|
|
1912
|
+
{ insert: 'content' },
|
|
1913
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1914
|
+
{ insert: 'content' },
|
|
1915
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1916
|
+
{ insert: 'content' },
|
|
1917
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1918
|
+
{ insert: 'content' },
|
|
1919
|
+
{ attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' },
|
|
1920
|
+
{ insert: '\n' },
|
|
1921
|
+
]),
|
|
1922
|
+
quill.getContents(),
|
|
1923
|
+
);
|
|
1924
|
+
});
|
|
1925
|
+
});
|
|
1926
|
+
|
|
1588
1927
|
describe('clipboard content format', () => {
|
|
1589
1928
|
it('should convert html code-block correctly', async () => {
|
|
1590
1929
|
const quill = createQuillWithTableModule(`<p><br></p>`);
|
|
@@ -1921,7 +2260,7 @@ describe('clipboard content format', () => {
|
|
|
1921
2260
|
});
|
|
1922
2261
|
|
|
1923
2262
|
it('clipboard convert cell with background on tr', async () => {
|
|
1924
|
-
const quill = createQuillWithTableModule(`<p><br></p
|
|
2263
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { full: false });
|
|
1925
2264
|
// color convert hex in quill internal
|
|
1926
2265
|
quill.setContents(
|
|
1927
2266
|
quill.clipboard.convert({
|
|
@@ -2174,3 +2513,230 @@ describe('test TableUp `getHTMLByCell`', () => {
|
|
|
2174
2513
|
}
|
|
2175
2514
|
});
|
|
2176
2515
|
});
|
|
2516
|
+
|
|
2517
|
+
describe('clipboard style block resolution', () => {
|
|
2518
|
+
it('class-based background-color is preserved on table cell', () => {
|
|
2519
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2520
|
+
const delta = quill.clipboard.convert({
|
|
2521
|
+
html: '<style>.xl65{background-color:#FFC000}</style><table><tr><td class="xl65">text</td></tr></table>',
|
|
2522
|
+
});
|
|
2523
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2524
|
+
expect(cellOp).toBeDefined();
|
|
2525
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2526
|
+
expect(style).toContain('background-color');
|
|
2527
|
+
expect(style).toMatch(/#FFC000|rgb\(255, 192, 0\)/i);
|
|
2528
|
+
});
|
|
2529
|
+
|
|
2530
|
+
it('class-based color is preserved as Quill inline format', () => {
|
|
2531
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2532
|
+
const delta = quill.clipboard.convert({
|
|
2533
|
+
html: '<style>.xl65{color:red}</style><table><tr><td class="xl65">text</td></tr></table>',
|
|
2534
|
+
});
|
|
2535
|
+
// text and \n may be merged into a single op when attributes match
|
|
2536
|
+
const textOp = delta.ops.find(op => typeof op.insert === 'string' && (op.insert as string).includes('text'));
|
|
2537
|
+
expect(textOp).toBeDefined();
|
|
2538
|
+
expect(textOp!.attributes?.color).toBeTruthy();
|
|
2539
|
+
});
|
|
2540
|
+
|
|
2541
|
+
it('class-based bold is preserved as Quill inline format', () => {
|
|
2542
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2543
|
+
const delta = quill.clipboard.convert({
|
|
2544
|
+
html: '<style>.xl65{font-weight:bold}</style><table><tr><td class="xl65">text</td></tr></table>',
|
|
2545
|
+
});
|
|
2546
|
+
// text and \n may be merged into a single op when attributes match
|
|
2547
|
+
const textOp = delta.ops.find(op => typeof op.insert === 'string' && (op.insert as string).includes('text'));
|
|
2548
|
+
expect(textOp).toBeDefined();
|
|
2549
|
+
expect(textOp!.attributes?.bold).toBe(true);
|
|
2550
|
+
});
|
|
2551
|
+
|
|
2552
|
+
it('inline style takes priority over class style', () => {
|
|
2553
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2554
|
+
const delta = quill.clipboard.convert({
|
|
2555
|
+
html: '<style>.xl65{background-color:red}</style><table><tr><td class="xl65" style="background-color:blue">text</td></tr></table>',
|
|
2556
|
+
});
|
|
2557
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2558
|
+
expect(cellOp).toBeDefined();
|
|
2559
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2560
|
+
expect(style).toContain('background-color');
|
|
2561
|
+
expect(style).toMatch(/blue/i);
|
|
2562
|
+
expect(style).not.toMatch(/red/i);
|
|
2563
|
+
});
|
|
2564
|
+
|
|
2565
|
+
it('@-rules are skipped without error', () => {
|
|
2566
|
+
const rules = parseCSSRules('@page{margin:1in} .xl65{background:red}');
|
|
2567
|
+
expect(rules.length).toBe(1);
|
|
2568
|
+
expect(rules[0].selector).toBe('.xl65');
|
|
2569
|
+
expect(rules[0].styles.background).toBe('red');
|
|
2570
|
+
});
|
|
2571
|
+
|
|
2572
|
+
it('multiple style blocks are all processed', () => {
|
|
2573
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2574
|
+
const delta = quill.clipboard.convert({
|
|
2575
|
+
html: '<style>.a{background-color:red}</style><style>.b{background-color:blue}</style><table><tr><td class="a">A</td><td class="b">B</td></tr></table>',
|
|
2576
|
+
});
|
|
2577
|
+
const cellOps = delta.ops.filter(op => op.attributes?.['table-up-cell-inner']);
|
|
2578
|
+
expect(cellOps.length).toBeGreaterThanOrEqual(2);
|
|
2579
|
+
expect((cellOps[0].attributes!['table-up-cell-inner'] as any).style).toContain('background-color');
|
|
2580
|
+
expect((cellOps[1].attributes!['table-up-cell-inner'] as any).style).toContain('background-color');
|
|
2581
|
+
});
|
|
2582
|
+
|
|
2583
|
+
it('simple tag selectors (td) are skipped by default', () => {
|
|
2584
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2585
|
+
const delta = quill.clipboard.convert({
|
|
2586
|
+
html: '<style>td{background-color:red} .xl65{background-color:blue}</style><table><tr><td class="xl65">text</td></tr></table>',
|
|
2587
|
+
});
|
|
2588
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2589
|
+
expect(cellOp).toBeDefined();
|
|
2590
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2591
|
+
// class selector applied, tag selector skipped
|
|
2592
|
+
expect(style).toMatch(/blue/i);
|
|
2593
|
+
});
|
|
2594
|
+
|
|
2595
|
+
it('descendant tag selectors (table td) are skipped by default', () => {
|
|
2596
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2597
|
+
const delta = quill.clipboard.convert({
|
|
2598
|
+
html: '<style>table td{background-color:red} .xl65{background-color:blue}</style><table><tr><td class="xl65">text</td></tr></table>',
|
|
2599
|
+
});
|
|
2600
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2601
|
+
expect(cellOp).toBeDefined();
|
|
2602
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2603
|
+
expect(style).toMatch(/blue/i);
|
|
2604
|
+
expect(style).not.toMatch(/red/i);
|
|
2605
|
+
});
|
|
2606
|
+
|
|
2607
|
+
it('child combinator tag selectors (tr > td) are skipped by default', () => {
|
|
2608
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2609
|
+
const delta = quill.clipboard.convert({
|
|
2610
|
+
html: '<style>tr > td{background-color:red}</style><table><tr><td>text</td></tr></table>',
|
|
2611
|
+
});
|
|
2612
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2613
|
+
expect(cellOp).toBeDefined();
|
|
2614
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style || '';
|
|
2615
|
+
expect(style).not.toContain('background-color');
|
|
2616
|
+
});
|
|
2617
|
+
|
|
2618
|
+
it('deep combinator tag selectors (table > tbody > tr > td) are skipped by default', () => {
|
|
2619
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2620
|
+
const delta = quill.clipboard.convert({
|
|
2621
|
+
html: '<style>table > tbody > tr > td{background-color:red}</style><table><tbody><tr><td>text</td></tr></tbody></table>',
|
|
2622
|
+
});
|
|
2623
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2624
|
+
expect(cellOp).toBeDefined();
|
|
2625
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style || '';
|
|
2626
|
+
expect(style).not.toContain('background-color');
|
|
2627
|
+
});
|
|
2628
|
+
|
|
2629
|
+
it('sibling combinator tag selectors (td + td) are skipped by default', () => {
|
|
2630
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2631
|
+
const delta = quill.clipboard.convert({
|
|
2632
|
+
html: '<style>td + td{background-color:red}</style><table><tr><td>a</td><td>b</td></tr></table>',
|
|
2633
|
+
});
|
|
2634
|
+
const cellOps = delta.ops.filter(op => op.attributes?.['table-up-cell-inner']);
|
|
2635
|
+
for (const op of cellOps) {
|
|
2636
|
+
const style = (op.attributes!['table-up-cell-inner'] as any).style || '';
|
|
2637
|
+
expect(style).not.toContain('background-color');
|
|
2638
|
+
}
|
|
2639
|
+
});
|
|
2640
|
+
|
|
2641
|
+
it('tag+class selectors (td.xl65) are NOT skipped', () => {
|
|
2642
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2643
|
+
const delta = quill.clipboard.convert({
|
|
2644
|
+
html: '<style>td.xl65{background-color:red}</style><table><tr><td class="xl65">text</td></tr></table>',
|
|
2645
|
+
});
|
|
2646
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2647
|
+
expect(cellOp).toBeDefined();
|
|
2648
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2649
|
+
expect(style).toContain('background-color');
|
|
2650
|
+
});
|
|
2651
|
+
|
|
2652
|
+
it('tag+id selectors (td#main) are NOT skipped', () => {
|
|
2653
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2654
|
+
const delta = quill.clipboard.convert({
|
|
2655
|
+
html: '<style>td#main{background-color:red}</style><table><tr><td id="main">text</td></tr></table>',
|
|
2656
|
+
});
|
|
2657
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2658
|
+
expect(cellOp).toBeDefined();
|
|
2659
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2660
|
+
expect(style).toContain('background-color');
|
|
2661
|
+
});
|
|
2662
|
+
|
|
2663
|
+
it('tag+attribute selectors (td[data-x]) are NOT skipped', () => {
|
|
2664
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2665
|
+
const delta = quill.clipboard.convert({
|
|
2666
|
+
html: '<style>td[data-x]{background-color:red}</style><table><tr><td data-x="1">text</td></tr></table>',
|
|
2667
|
+
});
|
|
2668
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2669
|
+
expect(cellOp).toBeDefined();
|
|
2670
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2671
|
+
expect(style).toContain('background-color');
|
|
2672
|
+
});
|
|
2673
|
+
|
|
2674
|
+
it('class descendant tag selectors (.cls td) are NOT skipped', () => {
|
|
2675
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2676
|
+
const delta = quill.clipboard.convert({
|
|
2677
|
+
html: '<style>.wrap td{background-color:#FFC000}</style><table class="wrap"><tr><td>text</td></tr></table>',
|
|
2678
|
+
});
|
|
2679
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2680
|
+
expect(cellOp).toBeDefined();
|
|
2681
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2682
|
+
expect(style).toContain('background-color');
|
|
2683
|
+
expect(style).toMatch(/#FFC000|rgb\(255, 192, 0\)/i);
|
|
2684
|
+
});
|
|
2685
|
+
|
|
2686
|
+
it('pseudo selectors (td:first-child) are NOT skipped', () => {
|
|
2687
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2688
|
+
const delta = quill.clipboard.convert({
|
|
2689
|
+
html: '<style>td:first-child{background-color:red}</style><table><tr><td>a</td><td>b</td></tr></table>',
|
|
2690
|
+
});
|
|
2691
|
+
const cellOps = delta.ops.filter(op => op.attributes?.['table-up-cell-inner']);
|
|
2692
|
+
// first cell should have background-color, second should not
|
|
2693
|
+
const styles = cellOps.map(op => (op.attributes!['table-up-cell-inner'] as any).style || '');
|
|
2694
|
+
expect(styles.some(s => s.includes('background-color'))).toBe(true);
|
|
2695
|
+
expect(styles.some(s => !s.includes('background-color'))).toBe(true);
|
|
2696
|
+
});
|
|
2697
|
+
|
|
2698
|
+
it('comma-separated mixed selectors skip only the tag-only parts', () => {
|
|
2699
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true });
|
|
2700
|
+
const delta = quill.clipboard.convert({
|
|
2701
|
+
html: '<style>td, .xl65{background-color:red}</style><table><tr><td class="xl65">text</td></tr></table>',
|
|
2702
|
+
});
|
|
2703
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2704
|
+
expect(cellOp).toBeDefined();
|
|
2705
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2706
|
+
// ".xl65" part applied (tag "td" part skipped, but .xl65 matches the same element)
|
|
2707
|
+
expect(style).toContain('background-color');
|
|
2708
|
+
});
|
|
2709
|
+
|
|
2710
|
+
it('complex tag selectors are applied when pasteDefaultTagStyle is true', () => {
|
|
2711
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true, pasteDefaultTagStyle: true });
|
|
2712
|
+
const delta = quill.clipboard.convert({
|
|
2713
|
+
html: '<style>table td{background-color:red}</style><table><tr><td>text</td></tr></table>',
|
|
2714
|
+
});
|
|
2715
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2716
|
+
expect(cellOp).toBeDefined();
|
|
2717
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2718
|
+
expect(style).toContain('background-color');
|
|
2719
|
+
});
|
|
2720
|
+
|
|
2721
|
+
it('pasteStyleSheet=false disables style resolution', () => {
|
|
2722
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: false });
|
|
2723
|
+
const delta = quill.clipboard.convert({
|
|
2724
|
+
html: '<style>.xl65{background-color:#FFC000}</style><table><tr><td class="xl65">text</td></tr></table>',
|
|
2725
|
+
});
|
|
2726
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2727
|
+
expect(cellOp).toBeDefined();
|
|
2728
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style || '';
|
|
2729
|
+
expect(style).not.toContain('background-color');
|
|
2730
|
+
});
|
|
2731
|
+
|
|
2732
|
+
it('pasteDefaultTagStyle=true enables tag selector styles', () => {
|
|
2733
|
+
const quill = createQuillWithTableModule(`<p><br></p>`, { pasteStyleSheet: true, pasteDefaultTagStyle: true });
|
|
2734
|
+
const delta = quill.clipboard.convert({
|
|
2735
|
+
html: '<style>td{background-color:#FFC000}</style><table><tr><td>text</td></tr></table>',
|
|
2736
|
+
});
|
|
2737
|
+
const cellOp = delta.ops.find(op => op.attributes?.['table-up-cell-inner']);
|
|
2738
|
+
expect(cellOp).toBeDefined();
|
|
2739
|
+
const style = (cellOp!.attributes!['table-up-cell-inner'] as any).style;
|
|
2740
|
+
expect(style).toContain('background-color');
|
|
2741
|
+
});
|
|
2742
|
+
});
|