quill-table-up 3.0.1 → 3.0.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.
@@ -1,3 +1,4 @@
1
+ import type { Parchment as TypeParchment } from 'quill';
1
2
  import type { TableCaptionFormat, TableMainFormat } from '../../formats';
2
3
  import type { ToolOption } from '../../utils';
3
4
  import Quill from 'quill';
@@ -1249,37 +1250,119 @@ describe('table undo', () => {
1249
1250
  { insert: '\n' },
1250
1251
  ];
1251
1252
  quill.setContents(originDelta);
1253
+ const mergedDelta = [
1254
+ { insert: '\n' },
1255
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
1256
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
1257
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
1258
+ { insert: '1' },
1259
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 2, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1260
+ { insert: { video: 'some.com' } },
1261
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 2, tag: 'td', wrapTag: 'tbody' } }, insert: '\n\n' },
1262
+ { insert: '3' },
1263
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1264
+ { insert: '4' },
1265
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1266
+ { insert: '5' },
1267
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1268
+ { insert: '6' },
1269
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1270
+ { insert: '7' },
1271
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1272
+ { insert: '8' },
1273
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1274
+ { insert: '9' },
1275
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1276
+ { insert: '\n' },
1277
+ ];
1252
1278
 
1253
1279
  const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
1254
1280
  tableModule.mergeCells([tds[0], tds[1]]);
1255
1281
  await vi.runAllTimersAsync();
1256
1282
  expectDelta(
1257
1283
  quill.getContents(),
1258
- new Delta([
1259
- { insert: '\n' },
1260
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
1261
- { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
1262
- { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
1263
- { insert: '1' },
1264
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 2, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1265
- { insert: { video: 'some.com' } },
1266
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 2, tag: 'td', wrapTag: 'tbody' } }, insert: '\n\n' },
1267
- { insert: '3' },
1268
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1269
- { insert: '4' },
1270
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1271
- { insert: '5' },
1272
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1273
- { insert: '6' },
1274
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1275
- { insert: '7' },
1276
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1277
- { insert: '8' },
1278
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1279
- { insert: '9' },
1280
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1281
- { insert: '\n' },
1282
- ]),
1284
+ new Delta(mergedDelta),
1285
+ );
1286
+
1287
+ quill.history.undo();
1288
+ await vi.runAllTimersAsync();
1289
+ expectDelta(
1290
+ quill.getContents(),
1291
+ new Delta(originDelta),
1292
+ );
1293
+
1294
+ quill.history.redo();
1295
+ await vi.runAllTimersAsync();
1296
+ expectDelta(
1297
+ quill.getContents(),
1298
+ new Delta(mergedDelta),
1299
+ );
1300
+ });
1301
+
1302
+ it('undo remove cell with BlockEmbed', async () => {
1303
+ const quill = createQuillWithTableModule('<p><br></p>');
1304
+ const originDelta = [
1305
+ { insert: '\n' },
1306
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
1307
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
1308
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
1309
+ { insert: '1' },
1310
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1311
+ { insert: { video: 'some.com' } },
1312
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1313
+ { insert: '123' },
1314
+ { attributes: { 'code-block': 'plain', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1315
+ { insert: '3' },
1316
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1317
+ { insert: '4' },
1318
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1319
+ { insert: '5' },
1320
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1321
+ { insert: '6' },
1322
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1323
+ { insert: '7' },
1324
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1325
+ { insert: '8' },
1326
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1327
+ { insert: '9' },
1328
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1329
+ { insert: '\n' },
1330
+ ];
1331
+ const removedDelta = [
1332
+ { insert: '\n' },
1333
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
1334
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
1335
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
1336
+ { insert: '1' },
1337
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1338
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1339
+ { insert: '3' },
1340
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1341
+ { insert: '4' },
1342
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1343
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1344
+ { insert: '6' },
1345
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1346
+ { insert: '7' },
1347
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1348
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1349
+ { insert: '9' },
1350
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
1351
+ { insert: '\n' },
1352
+ ];
1353
+ quill.setContents(originDelta);
1354
+
1355
+ const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
1356
+ for (const td of [tds[1], tds[4], tds[7]]) {
1357
+ const clearTd = td.clone() as TypeParchment.Parent;
1358
+ clearTd.appendChild(td.scroll.create('block'));
1359
+ td.parent.insertBefore(clearTd, td);
1360
+ td.remove();
1361
+ }
1362
+ await vi.runAllTimersAsync();
1363
+ expectDelta(
1364
+ quill.getContents(),
1365
+ new Delta(removedDelta),
1283
1366
  );
1284
1367
 
1285
1368
  quill.history.undo();
@@ -1288,6 +1371,115 @@ describe('table undo', () => {
1288
1371
  quill.getContents(),
1289
1372
  new Delta(originDelta),
1290
1373
  );
1374
+
1375
+ quill.history.redo();
1376
+ await vi.runAllTimersAsync();
1377
+ expectDelta(
1378
+ quill.getContents(),
1379
+ new Delta(removedDelta),
1380
+ );
1381
+ });
1382
+
1383
+ it('undo paste table', async () => {
1384
+ const quill = createQuillWithTableModule('<p><br></p>');
1385
+ quill.setContents(
1386
+ quill.clipboard.convert({ html: '<div class="ql-table-wrapper" data-table-id="1" contenteditable="false"><table class="ql-table" data-table-id="1" cellpadding="0" cellspacing="0" style="margin-right: auto; width: 363px;"><colgroup data-table-id="1" contenteditable="false"><col width="121px" data-table-id="1" data-col-id="1"><col width="121px" data-table-id="1" data-col-id="2"><col width="121px" data-table-id="1" data-col-id="3"></colgroup><tbody data-table-id="1"><tr class="ql-table-row" data-table-id="1" data-row-id="1" data-wrap-tag="tbody"><td class="ql-table-cell" data-table-id="1" data-row-id="1" data-col-id="1" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="1" data-col-id="1" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>1</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="1" data-col-id="2" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="1" data-col-id="2" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><h1>2</h1></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="1" data-col-id="3" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="1" data-col-id="3" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><iframe class="ql-video" frameborder="0" allowfullscreen="true" src="some.com"></iframe></div></td></tr><tr class="ql-table-row" data-table-id="1" data-row-id="2" data-wrap-tag="tbody"><td class="ql-table-cell" data-table-id="1" data-row-id="2" data-col-id="1" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="2" data-col-id="1" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>4</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="2" data-col-id="2" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="2" data-col-id="2" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>5</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="2" data-col-id="3" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="2" data-col-id="3" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>6</p></div></td></tr><tr class="ql-table-row" data-table-id="1" data-row-id="3" data-wrap-tag="tbody"><td class="ql-table-cell" data-table-id="1" data-row-id="3" data-col-id="1" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="3" data-col-id="1" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>7</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="3" data-col-id="2" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="3" data-col-id="2" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>8</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="3" data-col-id="3" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="3" data-col-id="3" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><ol><li data-list="ordered"><span class="ql-ui" contenteditable="false"></span>9</li><li data-list="ordered"><span class="ql-ui" contenteditable="false"></span>end</li></ol></div></td></tr></tbody></table></div>' }),
1387
+ );
1388
+ await vi.runAllTimersAsync();
1389
+ quill.setContents(
1390
+ quill.getContents().insert('\n').concat(
1391
+ quill.clipboard.convert({ html: '<div class="ql-table-wrapper" data-table-id="1" contenteditable="false"><table class="ql-table" data-table-id="1" cellpadding="0" cellspacing="0" style="margin-right: auto; width: 363px;"><colgroup data-table-id="1" contenteditable="false"><col width="121px" data-table-id="1" data-col-id="1"><col width="121px" data-table-id="1" data-col-id="2"><col width="121px" data-table-id="1" data-col-id="3"></colgroup><tbody data-table-id="1"><tr class="ql-table-row" data-table-id="1" data-row-id="1" data-wrap-tag="tbody"><td class="ql-table-cell" data-table-id="1" data-row-id="1" data-col-id="1" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="1" data-col-id="1" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>1</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="1" data-col-id="2" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="1" data-col-id="2" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><h1>2</h1></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="1" data-col-id="3" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="1" data-col-id="3" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><iframe class="ql-video" frameborder="0" allowfullscreen="true" src="some.com"></iframe></div></td></tr><tr class="ql-table-row" data-table-id="1" data-row-id="2" data-wrap-tag="tbody"><td class="ql-table-cell" data-table-id="1" data-row-id="2" data-col-id="1" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="2" data-col-id="1" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>4</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="2" data-col-id="2" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="2" data-col-id="2" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>5</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="2" data-col-id="3" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="2" data-col-id="3" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>6</p></div></td></tr><tr class="ql-table-row" data-table-id="1" data-row-id="3" data-wrap-tag="tbody"><td class="ql-table-cell" data-table-id="1" data-row-id="3" data-col-id="1" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="3" data-col-id="1" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>7</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="3" data-col-id="2" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="3" data-col-id="2" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><p>8</p></div></td><td class="ql-table-cell" data-table-id="1" data-row-id="3" data-col-id="3" data-wrap-tag="tbody" rowspan="1" colspan="1"><div class="ql-table-cell-inner" data-table-id="1" data-row-id="3" data-col-id="3" data-rowspan="1" data-colspan="1" data-tag="td" data-wrap-tag="tbody" contenteditable="true"><ol><li data-list="ordered"><span class="ql-ui" contenteditable="false"></span>9</li><li data-list="ordered"><span class="ql-ui" contenteditable="false"></span>end</li></ol></div></td></tr></tbody></table></div>' }),
1392
+ ),
1393
+ );
1394
+ await vi.runAllTimersAsync();
1395
+ const pasteTableHTML = `
1396
+ <div>
1397
+ <table cellpadding="0" cellspacing="0" style="margin-right: auto; width: 363px;">
1398
+ ${createTaleColHTML(3, { full: false, width: 121 })}
1399
+ <tbody>
1400
+ <tr>
1401
+ <td>
1402
+ <div><p>1</p></div>
1403
+ </td>
1404
+ <td>
1405
+ <div><h1>2</h1></div>
1406
+ </td>
1407
+ <td>
1408
+ <div>
1409
+ <iframe src="some.com" frameborder="0" allowfullscreen="true"></iframe>
1410
+ </div>
1411
+ </td>
1412
+ </tr>
1413
+ <tr>
1414
+ <td>
1415
+ <div><p>4</p></div>
1416
+ </td>
1417
+ <td>
1418
+ <div><p>5</p></div>
1419
+ </td>
1420
+ <td>
1421
+ <div><p>6</p></div>
1422
+ </td>
1423
+ </tr>
1424
+ <tr>
1425
+ <td>
1426
+ <div><p>7</p></div>
1427
+ </td>
1428
+ <td>
1429
+ <div><p>8</p></div>
1430
+ </td>
1431
+ <td>
1432
+ <div>
1433
+ <ol>
1434
+ <li data-list="ordered">9</li>
1435
+ <li data-list="ordered">end</li>
1436
+ </ol>
1437
+ </div>
1438
+ </td>
1439
+ </tr>
1440
+ </tbody>
1441
+ </table>
1442
+ </div>
1443
+ `;
1444
+ expect(quill.root).toEqualHTML(
1445
+ `
1446
+ <p><br></p>
1447
+ ${pasteTableHTML}
1448
+ <p><br></p>
1449
+ <p><br></p>
1450
+ ${pasteTableHTML}
1451
+ <p><br></p>
1452
+ `,
1453
+ { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'rowspan', 'data-colspan', 'colspan', 'contenteditable'] },
1454
+ );
1455
+
1456
+ quill.history.undo();
1457
+ await vi.runAllTimersAsync();
1458
+ expect(quill.root).toEqualHTML(
1459
+ `
1460
+ <p><br></p>
1461
+ ${pasteTableHTML}
1462
+ <p><br></p>
1463
+ <p><br></p>
1464
+ ${pasteTableHTML}
1465
+ <p><br></p>
1466
+ `,
1467
+ { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'rowspan', 'data-colspan', 'colspan', 'contenteditable'] },
1468
+ );
1469
+
1470
+ quill.history.undo();
1471
+ await vi.runAllTimersAsync();
1472
+ expect(quill.root).toEqualHTML(
1473
+ `
1474
+ <p><br></p>
1475
+ ${pasteTableHTML}
1476
+ <p><br></p>
1477
+ <p><br></p>
1478
+ ${pasteTableHTML}
1479
+ <p><br></p>
1480
+ `,
1481
+ { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'rowspan', 'data-colspan', 'colspan', 'contenteditable'] },
1482
+ );
1291
1483
  });
1292
1484
  });
1293
1485
 
@@ -215,7 +215,9 @@ describe('unusual delete', () => {
215
215
  await vi.runAllTimersAsync();
216
216
  quill.deleteText(0, 16);
217
217
  await vi.runAllTimersAsync();
218
- expect(quill.root).toEqualHTML(`<p><br></p>`);
218
+ // After remove all `col`, `fixUnusuaDeletelTable` will remove whole table.
219
+ // The remaining two rows around
220
+ expect(quill.root).toEqualHTML(`<p><br></p><p><br></p>`);
219
221
  });
220
222
 
221
223
  it('delete tail from inside table to outside', async () => {
@@ -129,6 +129,7 @@ interface TableCaptionCreatorOptions extends Omit<TableCaptionValue, 'tableId'>
129
129
  text: string;
130
130
  }
131
131
  export const datasetWrapTag = (tag: string = 'tbody') => `data-wrap-tag="${tag}"`;
132
+ export const datasetTag = (tag: string = 'td') => `data-tag="${tag}"`;
132
133
  export const datasetTableId = (id: string) => `data-table-id="${id}"`;
133
134
  export const datasetFull = (full: boolean) => full ? ' data-full="true"' : '';
134
135
  export const datasetAlign = (align: string) => align === 'left' ? '' : ` data-align="${align}"`;
@@ -216,7 +217,7 @@ export function createTableBodyHTML(row: number, col: number, options?: Partial<
216
217
  <tr ${datasetTableId(tableId)} data-row-id="${i + 1}" ${datasetWrapTag('tbody')}>
217
218
  ${
218
219
  new Array(col).fill(0).map((_, j) => `<td rowspan="1" colspan="1" ${datasetTableId(tableId)} data-row-id="${i + 1}" data-col-id="${j + 1}" ${datasetWrapTag('tbody')}>
219
- <div data-tag="td" ${datasetTableId(tableId)} data-rowspan="1" data-colspan="1" data-row-id="${i + 1}" data-col-id="${j + 1}" ${datasetWrapTag('tbody')}${contenteditableString(editable)}>
220
+ <div ${datasetTag('td')} ${datasetTableId(tableId)} data-rowspan="1" data-colspan="1" data-row-id="${i + 1}" data-col-id="${j + 1}" ${datasetWrapTag('tbody')}${contenteditableString(editable)}>
220
221
  <p>
221
222
  ${isEmpty ? '<br>' : i * row + j + 1}
222
223
  </p>
@@ -18,9 +18,8 @@ export class BlockEmbedOverride extends BlockEmbed {
18
18
  }
19
19
 
20
20
  length() {
21
- // because BlockEmbed is the last line of the tableCellInner. need add value in delta, also need add 1 to length
22
21
  const formats = bubbleFormats(this);
23
- if (formats[blotName.tableCellInner] && (!this.next || this.next.length() <= 1)) {
22
+ if (formats[blotName.tableCellInner]) {
24
23
  return super.length() + 1;
25
24
  }
26
25
  return super.length();
@@ -1,5 +1,6 @@
1
1
  import type { Parchment as TypeParchment } from 'quill';
2
2
  import type TypeBlock from 'quill/blots/block';
3
+ import type { BlockEmbed as TypeBlockEmbed } from 'quill/blots/block';
3
4
  import type TypeContainer from 'quill/blots/container';
4
5
  import type { TableCellInnerFormat } from '../table-cell-inner-format';
5
6
  import Quill from 'quill';
@@ -8,6 +9,7 @@ import { isSameCellValue } from '../utils';
8
9
 
9
10
  const Parchment = Quill.import('parchment');
10
11
  const Block = Quill.import('blots/block') as typeof TypeBlock;
12
+ const BlockEmbed = Quill.import('blots/block/embed') as typeof TypeBlockEmbed;
11
13
  const Container = Quill.import('blots/container') as typeof TypeContainer;
12
14
 
13
15
  export class BlockOverride extends Block {
@@ -36,6 +38,9 @@ export class BlockOverride extends Block {
36
38
  // use TableCellInner insertBefore to find the correct position
37
39
  currentTableCellInner.insertBefore(replacement, this);
38
40
  replacement.appendChild(this);
41
+ if (currentTableCellInner.children.length === 0) {
42
+ currentTableCellInner.remove();
43
+ }
39
44
  }
40
45
  else {
41
46
  // find the first parent not container
@@ -52,8 +57,7 @@ export class BlockOverride extends Block {
52
57
  // split current block as a separate "line" and wrap tableCellInner
53
58
  const index = this.offset(currentParent);
54
59
  const length = this.length();
55
- currentParent.split(index + length);
56
- const selfParent = currentParent.split(index);
60
+ const selfParent = currentParent.isolate(index, length);
57
61
  if (selfParent && selfParent.parent) {
58
62
  selfParent.parent.insertBefore(replacement, selfParent.next);
59
63
  }
@@ -75,6 +79,7 @@ export class BlockOverride extends Block {
75
79
 
76
80
  format(name: string, value: any): void {
77
81
  if (name === blotName.tableCellInner && this.parent.statics.blotName === name && !value) {
82
+ if (this.prev && this.prev instanceof BlockEmbed) return;
78
83
  try {
79
84
  const cellInner = findParentBlot(this, blotName.tableCellInner);
80
85
  cellInner.unwrap();
@@ -1,5 +1,6 @@
1
1
  import type { Parchment as TypeParchment } from 'quill';
2
2
  import type TypeBlock from 'quill/blots/block';
3
+ import type { BlockEmbed as TypeBlockEmbed } from 'quill/blots/block';
3
4
  import type TypeScroll from 'quill/blots/scroll';
4
5
  import type { TableBodyTag, TableCellValue } from '../utils';
5
6
  import type { TableCellFormat } from './table-cell-format';
@@ -10,7 +11,7 @@ import { TableBodyFormat } from './table-body-format';
10
11
  import { getValidCellspan, isSameCellValue } from './utils';
11
12
 
12
13
  const Block = Quill.import('blots/block') as TypeParchment.BlotConstructor;
13
- const BlockEmbed = Quill.import('blots/block/embed') as TypeParchment.BlotConstructor;
14
+ const BlockEmbed = Quill.import('blots/block/embed') as typeof TypeBlockEmbed;
14
15
 
15
16
  export class TableCellInnerFormat extends ContainerFormat {
16
17
  static blotName = blotName.tableCellInner;
@@ -228,9 +229,10 @@ export class TableCellInnerFormat extends ContainerFormat {
228
229
 
229
230
  formatAt(index: number, length: number, name: string, value: any) {
230
231
  if (this.children.length === 0) {
231
- this.appendChild(this.scroll.create(this.statics.defaultChild.blotName));
232
+ const defaultChild = this.scroll.create(this.statics.defaultChild.blotName);
233
+ this.appendChild(defaultChild);
232
234
  // block min length is 1
233
- length += 1;
235
+ length += defaultChild.length();
234
236
  }
235
237
  super.formatAt(index, length, name, value);
236
238
  // set style for `td`
@@ -247,6 +249,14 @@ export class TableCellInnerFormat extends ContainerFormat {
247
249
  this.appendChild(defaultChild);
248
250
  }
249
251
  super.insertAt(index, value, def);
252
+ // BlockEmbed will have a \n in delta, this will effect history stack
253
+ // so when insert a BlockEmbed, if current child length <= 1 then remove it
254
+ const blot = def == null
255
+ ? this.scroll.create('text', value)
256
+ : this.scroll.create(value, def);
257
+ if (blot instanceof BlockEmbed && child && child.length() <= 1) {
258
+ child.remove();
259
+ }
250
260
  }
251
261
 
252
262
  formats(): Record<string, any> {
@@ -339,10 +349,16 @@ export class TableCellInnerFormat extends ContainerFormat {
339
349
  cellRef = newCell;
340
350
  }
341
351
  }
352
+ if (this.tableId !== cellInnerBlot.tableId) {
353
+ const selfTableWrapper = findParentBlot(this, blotName.tableWrapper);
354
+ const index = this.offset(selfTableWrapper);
355
+ const afterSelfTableWrapper = selfTableWrapper.split(index);
356
+ return selfTableWrapper.parent.insertBefore(cellInnerBlot, afterSelfTableWrapper);
357
+ }
342
358
  // different rowId. split current row
343
359
  if (this.rowId !== cellInnerBlot.rowId) {
344
360
  let rowRef: TypeParchment.Blot | null = selfRow;
345
- const splitRef = ref || selfCell;
361
+ const splitRef = ref;
346
362
  if (splitRef) {
347
363
  const index = splitRef.offset(selfRow);
348
364
  rowRef = selfRow.split(index);
@@ -3,7 +3,6 @@ import type { BlockEmbed as TypeBlockEmbed } from 'quill/blots/block';
3
3
  import type { TableColValue } from '../utils';
4
4
  import Quill from 'quill';
5
5
  import { blotName, findParentBlot, tableUpSize } from '../utils';
6
- import { TableCellInnerFormat } from './table-cell-inner-format';
7
6
 
8
7
  const BlockEmbed = Quill.import('blots/block/embed') as typeof TypeBlockEmbed;
9
8
 
@@ -144,43 +143,40 @@ export class TableColFormat extends BlockEmbed {
144
143
 
145
144
  insertAt(index: number, value: string, def?: any): void {
146
145
  if (def != null) {
147
- super.insertAt(index, value, def);
146
+ if (value === this.statics.blotName && def.tableId !== this.tableId) {
147
+ try {
148
+ const tableWrapperBlot = findParentBlot(this, blotName.tableWrapper);
149
+ const parentBlot = tableWrapperBlot.split(this.offset(tableWrapperBlot)) as TypeParchment.Parent;
150
+
151
+ const blot = this.scroll.create(value, def);
152
+ parentBlot.parent.insertBefore(blot, parentBlot);
153
+ }
154
+ catch {
155
+ // here should not trigger
156
+ console.warn('TableCol not in TableColgroup');
157
+ }
158
+ }
159
+ else {
160
+ super.insertAt(index, value, def);
161
+ }
148
162
  return;
149
163
  }
150
164
  try {
165
+ const tableWrapperBlot = findParentBlot(this, blotName.tableWrapper);
166
+ const parentBlot = tableWrapperBlot.split(this.offset(tableWrapperBlot)) as TypeParchment.Parent;
167
+
151
168
  const lines = value.split('\n');
152
169
  const text = lines.pop();
153
- const tableColgroupBlot = findParentBlot(this, blotName.tableColgroup);
154
- const tableBodyBlot = tableColgroupBlot.next;
155
-
156
- // create tbody
157
- let insertBlot: TypeParchment.Parent = this.scroll;
158
- // split colgroup
159
- const nextBlotRef: TypeParchment.Blot | null = tableColgroupBlot.split(this.offset(tableColgroupBlot));
160
- if (tableBodyBlot) {
161
- const cellInners = tableBodyBlot.descendants(TableCellInnerFormat);
162
- if (cellInners.length > 0) {
163
- const cellInnerBlot = cellInners[0];
164
- const value = TableCellInnerFormat.formats(cellInnerBlot.domNode);
165
- const newTableCellInner = this.scroll.create(blotName.tableCellInner, value) as TableCellInnerFormat;
166
- const newTableCell = newTableCellInner.wrap(blotName.tableCell, value);
167
- const newTableRow = newTableCell.wrap(blotName.tableRow, value);
168
- const newTableBody = newTableRow.wrap(blotName.tableBody, value.tableId);
169
- tableColgroupBlot.parent.insertBefore(newTableBody, nextBlotRef);
170
-
171
- insertBlot = newTableCellInner;
172
- }
173
- }
174
-
175
- for (const line of lines) {
176
- const block = this.scroll.create('block');
170
+ const blocks = lines.map((line) => {
171
+ const block = this.scroll.create('block') as TypeParchment.ParentBlot;
177
172
  block.insertAt(0, line);
178
- insertBlot.appendChild(block);
173
+ return block;
174
+ });
175
+ for (const block of blocks) {
176
+ parentBlot.parent.insertBefore(block, parentBlot);
179
177
  }
180
178
  if (text) {
181
- const lineBlock = this.scroll.create('block') as TypeParchment.ParentBlot;
182
- lineBlock.appendChild(this.scroll.create('text', text));
183
- insertBlot.appendChild(lineBlock);
179
+ parentBlot.parent.insertBefore(this.scroll.create('text', text), parentBlot);
184
180
  }
185
181
  }
186
182
  catch {
@@ -55,11 +55,19 @@ export class TableWrapperFormat extends ContainerFormat {
55
55
  );
56
56
  }
57
57
 
58
+ optimize(context: Record<string, any>) {
59
+ if (this.length() === 0) {
60
+ this.remove();
61
+ return;
62
+ }
63
+ super.optimize(context);
64
+ }
65
+
58
66
  deleteAt(index: number, length: number) {
59
67
  super.deleteAt(index, length);
60
68
  const tableBodys = this.descendants(TableBodyFormat);
61
69
  const tableColgroups = this.descendants(TableColgroupFormat);
62
- if (tableBodys.length === 0 || tableColgroups.length === 0) {
70
+ if (tableBodys.length === 0 && tableColgroups.length === 0) {
63
71
  this.remove();
64
72
  }
65
73
  }
@@ -108,7 +108,10 @@ export class TableSelection extends TableDomSelector {
108
108
  }
109
109
  }
110
110
  for (const td of this.selectedTds) {
111
- td.deleteAt(0, td.length() - 1);
111
+ const clearTd = td.clone() as TypeParchment.Parent;
112
+ clearTd.appendChild(td.scroll.create('block'));
113
+ td.parent.insertBefore(clearTd, td);
114
+ td.remove();
112
115
  }
113
116
  };
114
117
 
@@ -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":5040.086000000001,"failed":false}],[":__tests__/unit/table-redo-undo.test.ts",{"duration":9514.4945,"failed":false}],[":__tests__/unit/table-hack.test.ts",{"duration":1992.2028000000005,"failed":false}],[":__tests__/unit/table-cell-merge.test.ts",{"duration":2552.8873,"failed":false}],[":__tests__/unit/table-insert.test.ts",{"duration":4285.707699999999,"failed":false}],[":__tests__/unit/table-blots.test.ts",{"duration":1592.2781,"failed":false}],[":__tests__/unit/utils.test.ts",{"duration":528.3724000000002,"failed":false}],[":__tests__/unit/table-caption.test.ts",{"duration":854.4884999999999,"failed":false}],[":__tests__/unit/table-remove.test.ts",{"duration":1868.6178999999997,"failed":false}]]}
1
+ {"version":"3.2.3","results":[[":__tests__/unit/utils.test-d.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-clipboard.test.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-redo-undo.test.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-hack.test.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-cell-merge.test.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-insert.test.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-blots.test.ts",{"duration":0,"failed":false}],[":__tests__/unit/utils.test.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-caption.test.ts",{"duration":834.3326999999999,"failed":false}],[":__tests__/unit/table-remove.test.ts",{"duration":1954.0650999999998,"failed":false}]]}
package/src/table-up.ts CHANGED
@@ -244,10 +244,8 @@ export class TableUp {
244
244
  const blotName = name.split('formats/')[1];
245
245
  return name.startsWith('formats/')
246
246
  && !excludeFormat.has(blotName)
247
- && !isSubclassOf(blot, Parchment.Attributor)
248
247
  && (isSubclassOf(blot, Block) || isSubclassOf(blot, BlockEmbed));
249
- },
250
- );
248
+ });
251
249
  const overrides = overrideFormats.reduce((pre, [name, blot]) => {
252
250
  const extendsClass = isSubclassOf(blot, BlockEmbed) ? BlockEmbedOverride : BlockOverride;
253
251
  pre[name] = class extends mixinClass(blot, [extendsClass]) {
@@ -847,8 +845,12 @@ export class TableUp {
847
845
 
848
846
  // handle unusual delete cell
849
847
  fixUnusuaDeletelTable(tableBlot: TableMainFormat) {
850
- const bodys = tableBlot.getBodys();
851
848
  const tableColIds = tableBlot.getColIds();
849
+ if (tableColIds.length === 0) {
850
+ tableBlot.remove();
851
+ return;
852
+ }
853
+ const bodys = tableBlot.getBodys();
852
854
  const tableId = tableBlot.tableId;
853
855
  for (const body of bodys) {
854
856
  // calculate all cells in body
@@ -857,7 +859,6 @@ export class TableUp {
857
859
  body.remove();
858
860
  continue;
859
861
  }
860
- if (tableColIds.length === 0) continue;
861
862
  // append by col
862
863
  const cellSpanMap = new Array(trBlots.length).fill(0).map(() => new Array(tableColIds.length).fill(false));
863
864
  for (const [indexTr, tr] of trBlots.entries()) {
@@ -101,5 +101,5 @@ export function mixinClass<
101
101
  return targetClass;
102
102
  }
103
103
  export function isSubclassOf(childClass: any, parentClass: any): boolean {
104
- return childClass.prototype instanceof parentClass;
104
+ return childClass.prototype && childClass.prototype instanceof parentClass;
105
105
  }