quill-table-up 3.0.2 → 3.1.0

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.
@@ -88,7 +88,6 @@ extendTest('test TableMenuSelect should update when text change', async ({ page,
88
88
  await expect(menuWrapper).toBeVisible();
89
89
  const newMenuWrapper = (await menuWrapper.boundingBox())!;
90
90
  expect(newMenuWrapper).not.toBeNull();
91
- console.log(newMenuWrapper.y, menuBound.y, lineBound.height);
92
91
  expect(newMenuWrapper.y - menuBound.y).toBeCloseTo(lineBound.height, 0);
93
92
  });
94
93
 
@@ -171,26 +170,3 @@ extendTest('table width switch should work', async ({ page }) => {
171
170
  await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Switch table width' }).first().click();
172
171
  expect(await page.locator('#editor1 .ql-editor .ql-table col:not([data-full])').count()).toBe(4);
173
172
  });
174
-
175
- extendTest('TableSelection should have same boundbox with merge cell', async ({ page, editorPage }) => {
176
- editorPage.index = 0;
177
- await createTableBySelect(page, 'container1', 5, 5);
178
- const cellBoundbox = (await page.locator('#editor1 .ql-editor .ql-table td').nth(0).boundingBox())!;
179
- expect(cellBoundbox).not.toBeNull();
180
- await page.locator('#editor1 .ql-editor .ql-table td').nth(0).click();
181
-
182
- await page.mouse.move(cellBoundbox.x + cellBoundbox.width * 1.5, cellBoundbox.y + cellBoundbox.height * 1.5);
183
- await page.mouse.down();
184
- await page.mouse.move(cellBoundbox.x + cellBoundbox.width * 3.5, cellBoundbox.y + cellBoundbox.height * 3.5);
185
- await page.mouse.up();
186
-
187
- await page.locator('#editor1 .ql-editor .ql-table td').nth(6).click({ button: 'right' });
188
- await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Merge Cell' }).first().click();
189
-
190
- const selectionBoundbox = (await page.locator('#container1 .table-up-toolbox .table-up-selection .table-up-selection__line').boundingBox())!;
191
- expect(selectionBoundbox).not.toBeNull();
192
- const mergeCellBoundbox = (await page.locator('#editor1 .ql-editor .ql-table td').nth(6).boundingBox())!;
193
- expect(mergeCellBoundbox).not.toBeNull();
194
-
195
- expect(selectionBoundbox).toEqual(mergeCellBoundbox);
196
- });
@@ -1,12 +1,48 @@
1
- import type { Page } from '@playwright/test';
1
+ import type { Page, PlaywrightWorkerOptions } from '@playwright/test';
2
2
  import { test } from '@playwright/test';
3
3
  import { EditorPage } from './editor-page';
4
4
 
5
+ declare global {
6
+ interface Window {
7
+ pasteEventTriggered: boolean;
8
+ }
9
+ }
10
+
5
11
  export async function createTableBySelect(page: Page, container: string, row: number, col: number) {
6
12
  await page.locator(`#${container} .ql-toolbar .ql-table-up.ql-picker`).click();
7
13
  await page.locator(`#${container} .ql-toolbar .ql-custom-select .table-up-select-box__item[data-row="${row}"][data-col="${col}"]`).click();
8
14
  }
9
15
 
16
+ export async function pasteHTML(page: Page, html: string, { browserName = 'chromium' }: { browserName: PlaywrightWorkerOptions['browserName'] }) {
17
+ await page.evaluate(() => {
18
+ window.pasteEventTriggered = false;
19
+ document.addEventListener('paste', () => {
20
+ window.pasteEventTriggered = true;
21
+ });
22
+ });
23
+
24
+ await page.evaluate(async ({ html, browserName }) => {
25
+ if (browserName === 'firefox') {
26
+ const clipboardItem = new ClipboardItem({ 'text/html': new Blob([html], { type: 'text/html' }) });
27
+ await navigator.clipboard.write([clipboardItem]);
28
+ }
29
+ else {
30
+ const clipboardData = new DataTransfer();
31
+ clipboardData.setData('text/html', html);
32
+ const pasteEvent = new ClipboardEvent('paste', {
33
+ bubbles: true,
34
+ cancelable: true,
35
+ clipboardData,
36
+ });
37
+ document.dispatchEvent(pasteEvent);
38
+ }
39
+ }, { html, browserName });
40
+ if (browserName === 'firefox') {
41
+ await page.keyboard.press('Control+v');
42
+ }
43
+ await page.waitForFunction(() => window.pasteEventTriggered);
44
+ }
45
+
10
46
  export const extendTest = test.extend<{
11
47
  editorPage: EditorPage;
12
48
  }>({
@@ -1,8 +1,10 @@
1
+ import type { ToolOption } from '../../utils';
1
2
  import Quill from 'quill';
2
3
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { TableCellFormat } from '../../formats';
4
+ import { TableCellFormat, TableCellInnerFormat } from '../../formats';
5
+ import { tableMenuTools } from '../../modules';
4
6
  import { TableUp } from '../../table-up';
5
- import { createQuillWithTableModule, createTableBodyHTML, createTableCaptionHTML, createTableDeltaOps, createTaleColHTML, expectDelta } from './utils';
7
+ import { createQuillWithTableModule, createTable, createTableBodyHTML, createTableCaptionHTML, createTableDeltaOps, createTaleColHTML, datasetWrapTag, expectDelta, replaceAttrEmptyRow } from './utils';
6
8
 
7
9
  const Delta = Quill.import('delta');
8
10
 
@@ -379,3 +381,340 @@ describe('test table around line', () => {
379
381
  );
380
382
  });
381
383
  });
384
+
385
+ describe('test table body convert', () => {
386
+ it('table convert body should work correctly', async () => {
387
+ const quill = await createTable(3, 3, { full: false }, {}, { isEmpty: false });
388
+ const table = quill.root.querySelector('table')!;
389
+ const tableModule = quill.getModule(TableUp.moduleName) as TableUp;
390
+ const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
391
+ (tableMenuTools.ConvertTothead as ToolOption).handle.call({ quill, table } as any, tableModule, tds.slice(0, 1), null);
392
+ await vi.runAllTimersAsync();
393
+
394
+ expectDelta(
395
+ quill.getContents(),
396
+ new Delta([
397
+ { insert: '\n' },
398
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
399
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
400
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
401
+ { insert: '1' },
402
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'thead' } }, insert: '\n' },
403
+ { insert: '2' },
404
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'thead' } }, insert: '\n' },
405
+ { insert: '3' },
406
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'thead' } }, insert: '\n' },
407
+ { insert: '4' },
408
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
409
+ { insert: '5' },
410
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
411
+ { insert: '6' },
412
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
413
+ { insert: '7' },
414
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
415
+ { insert: '8' },
416
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
417
+ { insert: '9' },
418
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
419
+ { insert: '\n' },
420
+ ]),
421
+ );
422
+ });
423
+
424
+ it('table convert body with multi body', async () => {
425
+ const quill = createQuillWithTableModule(`<p><br></p>`);
426
+ quill.setContents([
427
+ { insert: '\n' },
428
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', width: 100 } } },
429
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', width: 100 } } },
430
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', width: 100 } } },
431
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', width: 100 } } },
432
+ { insert: { 'table-up-col': { tableId: '1', colId: '5', width: 100 } } },
433
+ { insert: '1' },
434
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', wrapTag: 'thead', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
435
+ { insert: '2' },
436
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', wrapTag: 'thead', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
437
+ { insert: '3' },
438
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', wrapTag: 'thead', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
439
+ { insert: '4' },
440
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', wrapTag: 'thead', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
441
+ { insert: '5' },
442
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', wrapTag: 'thead', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
443
+ { insert: '6' },
444
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', wrapTag: 'thead', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
445
+ { insert: '7' },
446
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', wrapTag: 'thead', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
447
+ { insert: '8' },
448
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', wrapTag: 'thead', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
449
+ { insert: '9' },
450
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', wrapTag: 'thead', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
451
+ { insert: '10' },
452
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', wrapTag: 'thead', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
453
+ { insert: '11' },
454
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
455
+ { insert: '12' },
456
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
457
+ { insert: '13' },
458
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
459
+ { insert: '14' },
460
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
461
+ { insert: '15' },
462
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
463
+ { insert: '16' },
464
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', wrapTag: 'tfoot', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
465
+ { insert: '17' },
466
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', wrapTag: 'tfoot', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
467
+ { insert: '18' },
468
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', wrapTag: 'tfoot', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
469
+ { insert: '19' },
470
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', wrapTag: 'tfoot', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
471
+ { insert: '20' },
472
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', wrapTag: 'tfoot', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
473
+ { insert: '21' },
474
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', wrapTag: 'tfoot', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
475
+ { insert: '22' },
476
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', wrapTag: 'tfoot', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
477
+ { insert: '23' },
478
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', wrapTag: 'tfoot', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
479
+ { insert: '24' },
480
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', wrapTag: 'tfoot', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
481
+ { insert: '25' },
482
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', wrapTag: 'tfoot', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
483
+ { insert: '\n' },
484
+ ]);
485
+ await vi.runAllTimersAsync();
486
+
487
+ const table = quill.root.querySelector('table')!;
488
+ const tableModule = quill.getModule(TableUp.moduleName) as TableUp;
489
+ const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
490
+ (tableMenuTools.ConvertTothead as ToolOption).handle.call({ quill, table } as any, tableModule, tds.slice(5, 20), null);
491
+ await vi.runAllTimersAsync();
492
+
493
+ expectDelta(
494
+ quill.getContents(),
495
+ new Delta([
496
+ { insert: '\n' },
497
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
498
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
499
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
500
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
501
+ { insert: { 'table-up-col': { tableId: '1', colId: '5', full: false, width: 100 } } },
502
+ { insert: '1' },
503
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', tag: 'td', wrapTag: 'thead', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
504
+ { insert: '2' },
505
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', tag: 'td', wrapTag: 'thead', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
506
+ { insert: '3' },
507
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', tag: 'td', wrapTag: 'thead', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
508
+ { insert: '4' },
509
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', tag: 'td', wrapTag: 'thead', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
510
+ { insert: '5' },
511
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', tag: 'td', wrapTag: 'thead', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
512
+ { insert: '6' },
513
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', tag: 'td', wrapTag: 'thead', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
514
+ { insert: '7' },
515
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', tag: 'td', wrapTag: 'thead', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
516
+ { insert: '8' },
517
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', tag: 'td', wrapTag: 'thead', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
518
+ { insert: '9' },
519
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', tag: 'td', wrapTag: 'thead', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
520
+ { insert: '10' },
521
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', tag: 'td', wrapTag: 'thead', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
522
+ { insert: '11' },
523
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', tag: 'td', wrapTag: 'thead', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
524
+ { insert: '12' },
525
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', tag: 'td', wrapTag: 'thead', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
526
+ { insert: '13' },
527
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', tag: 'td', wrapTag: 'thead', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
528
+ { insert: '14' },
529
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', tag: 'td', wrapTag: 'thead', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
530
+ { insert: '15' },
531
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', tag: 'td', wrapTag: 'thead', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
532
+ { insert: '16' },
533
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', tag: 'td', wrapTag: 'thead', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
534
+ { insert: '17' },
535
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', tag: 'td', wrapTag: 'thead', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
536
+ { insert: '18' },
537
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', tag: 'td', wrapTag: 'thead', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
538
+ { insert: '19' },
539
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', tag: 'td', wrapTag: 'thead', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
540
+ { insert: '20' },
541
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '4', tag: 'td', wrapTag: 'thead', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
542
+ { insert: '21' },
543
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', tag: 'td', wrapTag: 'tfoot', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
544
+ { insert: '22' },
545
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', tag: 'td', wrapTag: 'tfoot', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
546
+ { insert: '23' },
547
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', tag: 'td', wrapTag: 'tfoot', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
548
+ { insert: '24' },
549
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', tag: 'td', wrapTag: 'tfoot', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
550
+ { insert: '25' },
551
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', tag: 'td', wrapTag: 'tfoot', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
552
+ { insert: '\n' },
553
+ ]),
554
+ );
555
+ });
556
+
557
+ it('table convert body with emptyRow', async () => {
558
+ const quill = createQuillWithTableModule(`<p><br></p>`, { autoMergeCell: false });
559
+ quill.setContents([
560
+ { insert: '\n' },
561
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
562
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
563
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
564
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
565
+ { insert: { 'table-up-col': { tableId: '1', colId: '5', full: false, width: 100 } } },
566
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 5, colspan: 5, emptyRow: ['2', '3', '4', '5'] } }, insert: '\n' },
567
+ { insert: '\n' },
568
+ ]);
569
+ await vi.runAllTimersAsync();
570
+
571
+ const table = quill.root.querySelector('table')!;
572
+ const tableModule = quill.getModule(TableUp.moduleName) as TableUp;
573
+ const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
574
+ (tableMenuTools.ConvertTothead as ToolOption).handle.call({ quill, table } as any, tableModule, tds.slice(0, 1), null);
575
+ await vi.runAllTimersAsync();
576
+
577
+ expectDelta(
578
+ quill.getContents(),
579
+ new Delta([
580
+ { insert: '\n' },
581
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
582
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
583
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
584
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
585
+ { insert: { 'table-up-col': { tableId: '1', colId: '5', full: false, width: 100 } } },
586
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 5, colspan: 5, tag: 'td', wrapTag: 'thead', emptyRow: ['2', '3', '4', '5'] } }, insert: '\n' },
587
+ { insert: '\n' },
588
+ ]),
589
+ );
590
+ });
591
+
592
+ it('table convert body with next emptyRow', async () => {
593
+ const quill = createQuillWithTableModule(`<p><br></p>`, { autoMergeCell: false });
594
+ quill.setContents([
595
+ { insert: '\n' },
596
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
597
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
598
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
599
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
600
+ { insert: { 'table-up-col': { tableId: '1', colId: '5', full: false, width: 100 } } },
601
+ { insert: '1' },
602
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
603
+ { insert: '2' },
604
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
605
+ { insert: '3' },
606
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
607
+ { insert: '4' },
608
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
609
+ { insert: '5' },
610
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
611
+ { insert: 'merge' },
612
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 3, colspan: 5, emptyRow: ['3', '4'] } }, insert: '\n' },
613
+ { insert: '6' },
614
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
615
+ { insert: '7' },
616
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
617
+ { insert: '8' },
618
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
619
+ { insert: '9' },
620
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
621
+ { insert: '10' },
622
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '5', rowspan: 1, colspan: 1 } }, insert: '\n' },
623
+ { insert: '\n' },
624
+ ]);
625
+ await vi.runAllTimersAsync();
626
+
627
+ const table = quill.root.querySelector('table')!;
628
+ const tableModule = quill.getModule(TableUp.moduleName) as TableUp;
629
+ const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
630
+ (tableMenuTools.ConvertTothead as ToolOption).handle.call({ quill, table } as any, tableModule, tds.slice(0, 6), null);
631
+ await vi.runAllTimersAsync();
632
+
633
+ expect(quill.root).toEqualHTML(
634
+ `
635
+ <p><br></p>
636
+ <div>
637
+ <table cellpadding="0" cellspacing="0" style="margin-right: auto; width: 500px;">
638
+ ${createTaleColHTML(5, { full: false, width: 100 })}
639
+ <thead>
640
+ <tr ${datasetWrapTag('thead')}>
641
+ ${
642
+ new Array(5).fill(0).map((_, i) => `<td rowspan="1" colspan="1" ${datasetWrapTag('thead')}>
643
+ <div ${datasetWrapTag('thead')}>
644
+ <p>
645
+ ${i + 1}
646
+ </p>
647
+ </div>
648
+ </td>`).join('\n')
649
+ }
650
+ </tr>
651
+ <tr ${datasetWrapTag('thead')}>
652
+ <td rowspan="3" colspan="5" ${datasetWrapTag('thead')} data-empty-row="length:2">
653
+ <div ${datasetWrapTag('thead')} data-empty-row="length:2">
654
+ <p>merge</p>
655
+ </div>
656
+ </td>
657
+ </tr>
658
+ <tr ${datasetWrapTag('thead')}></tr>
659
+ <tr ${datasetWrapTag('thead')}></tr>
660
+ </thead>
661
+ <tbody>
662
+ <tr ${datasetWrapTag('tbody')}>
663
+ ${
664
+ new Array(5).fill(0).map((_, i) => `<td rowspan="1" colspan="1" ${datasetWrapTag('tbody')}>
665
+ <div ${datasetWrapTag('tbody')}>
666
+ <p>
667
+ ${5 + i + 1}
668
+ </p>
669
+ </div>
670
+ </td>`).join('\n')
671
+ }
672
+ </tr>
673
+ </tbody>
674
+ </table>
675
+ </div>
676
+ <p><br></p>
677
+ `,
678
+ {
679
+ ignoreAttrs: ['data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'],
680
+ replaceAttrs: {
681
+ 'data-empty-row': replaceAttrEmptyRow,
682
+ },
683
+ },
684
+ );
685
+ expectDelta(
686
+ quill.getContents(),
687
+ new Delta([
688
+ { insert: '\n' },
689
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
690
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
691
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
692
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
693
+ { insert: { 'table-up-col': { tableId: '1', colId: '5', full: false, width: 100 } } },
694
+ { insert: '1' },
695
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'thead' } }, insert: '\n' },
696
+ { insert: '2' },
697
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'thead' } }, insert: '\n' },
698
+ { insert: '3' },
699
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'thead' } }, insert: '\n' },
700
+ { insert: '4' },
701
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '4', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'thead' } }, insert: '\n' },
702
+ { insert: '5' },
703
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '5', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'thead' } }, insert: '\n' },
704
+ { insert: 'merge' },
705
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 3, colspan: 5, tag: 'td', wrapTag: 'thead', emptyRow: ['3', '4'] } }, insert: '\n' },
706
+ { insert: '6' },
707
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
708
+ { insert: '7' },
709
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
710
+ { insert: '8' },
711
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '3', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
712
+ { insert: '9' },
713
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '4', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
714
+ { insert: '10' },
715
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '5', colId: '5', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
716
+ { insert: '\n' },
717
+ ]),
718
+ );
719
+ });
720
+ });
@@ -1,6 +1,6 @@
1
1
  import Quill from 'quill';
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { TableCellInnerFormat } from '../../formats';
3
+ import { TableCellInnerFormat, TableMainFormat } from '../../formats';
4
4
  import { TableUp } from '../../table-up';
5
5
  import { createQuillWithTableModule, createTable, createTableDeltaOps, createTaleColHTML, expectDelta } from './utils';
6
6
 
@@ -700,4 +700,25 @@ describe('disable auto merge', () => {
700
700
  ]),
701
701
  );
702
702
  });
703
+
704
+ it('`emptyRow` should have same order with tr', async () => {
705
+ const quill = createQuillWithTableModule(`<p><br></p>`, { autoMergeCell: false });
706
+ quill.setContents(createTableDeltaOps(5, 3, { full: false }, {}, { isEmpty: false }));
707
+ const tableModule = quill.getModule(TableUp.moduleName) as TableUp;
708
+ const tds = quill.scroll.descendants(TableCellInnerFormat, 0);
709
+ tableModule.mergeCells([tds[3], tds[4], tds[5], tds[6], tds[7], tds[8], tds[9], tds[10], tds[11]]);
710
+ await vi.runAllTimersAsync();
711
+
712
+ const tableBlot = quill.scroll.descendants(TableMainFormat, 0)[0];
713
+ const emptyRowIds = tds[3].emptyRow;
714
+ const rowIds = tableBlot.getRowIds();
715
+ const startRowIndex = rowIds.indexOf(tds[3].rowId);
716
+
717
+ expect(emptyRowIds.length).toEqual(2);
718
+ expect(tds[3].rowspan).toEqual(3);
719
+ expect(startRowIndex).toEqual(1);
720
+ for (let i = startRowIndex + 1; i < startRowIndex + emptyRowIds.length; i++) {
721
+ expect(rowIds[i]).toEqual(emptyRowIds[i - startRowIndex - 1]);
722
+ }
723
+ });
703
724
  });