From d65f1aeeb3f386b6a350f038ba59c05e7a2240d1 Mon Sep 17 00:00:00 2001 From: zzxming Date: Wed, 15 Jan 2025 22:13:46 +0800 Subject: [PATCH 1/3] fix: simple merged cell paste wrong colId --- docs/index.js | 4 + src/__tests__/unit/table-clipboard.test.ts | 174 +++++++++++++++++++++ src/index.ts | 22 ++- 3 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 src/__tests__/unit/table-clipboard.test.ts diff --git a/docs/index.js b/docs/index.js index f69349a..b16a4a6 100644 --- a/docs/index.js +++ b/docs/index.js @@ -415,3 +415,7 @@ quill2.setContents([ { attributes: { 'table-up-cell-inner': { tableId: '8v36875pbr6', rowId: 'fow0uajprzw', colId: 'y0epsy6odnm', rowspan: 1, colspan: 1 } }, insert: '\n' }, { insert: '\n' }, ]); + +// quill1.setContents(quill1.clipboard.convert({ +// html: '

1

4

2

3

5

6

7

8

9

', // content is html string +// })); diff --git a/src/__tests__/unit/table-clipboard.test.ts b/src/__tests__/unit/table-clipboard.test.ts new file mode 100644 index 0000000..7d21dcf --- /dev/null +++ b/src/__tests__/unit/table-clipboard.test.ts @@ -0,0 +1,174 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { createQuillWithTableModule, createTableHTML, createTaleColHTML } from './utils'; + +beforeEach(() => { + vi.useFakeTimers(); +}); +afterEach(() => { + vi.useRealTimers(); +}); + +describe('cliboard', () => { + it('cliboard convert table', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ + html: '

1

2

3

4

5

6

7

8

9

', + }), + ); + await vi.runAllTimersAsync(); + expect(quill.root).toEqualHTML( + ` +


+ ${createTableHTML(3, 3, { width: 100, full: false }, { isEmpty: false })} + `, + { ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, + ); + }); + + it('cliboard convert simple row merged cell', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ + html: '

1

4

2

3

5

6

7

8

9

', + }), + ); + await vi.runAllTimersAsync(); + expect(quill.root).toEqualHTML( + ` +


+
+ + + + + + + + + + + + + + + + + + + + + + +
+

1

4

+
+

2

+
+

3

+
+

5

+
+

6

+
+

7

+
+

8

+
+

9

+
+
+ `, + { ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, + ); + }); + + it('cliboard convert multiple merged cell', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ + html: '



















', + }), + ); + await vi.runAllTimersAsync(); + expect(quill.root).toEqualHTML( + ` +


+
+ + ${createTaleColHTML(6, { width: 92, full: false })} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+
+ `, + { ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, + ); + }); +}); diff --git a/src/index.ts b/src/index.ts index b84f58f..52d7824 100644 --- a/src/index.ts +++ b/src/index.ts @@ -375,6 +375,7 @@ export class TableUp { let tableId = randomId(); let rowId = randomId(); let colIds: string[] = []; + let rowspanCount: { rowspan: number; colspan: number }[] = []; let cellCount = 0; let colCount = 0; @@ -436,6 +437,7 @@ export class TableUp { // reset variable to avoid conflict with other table tableId = randomId(); colIds = []; + rowspanCount = []; cellCount = 0; colCount = 0; // insert break line before table and after table @@ -488,11 +490,27 @@ export class TableUp { const matchCell = (node: Node, delta: TypeDelta) => { const cell = node as HTMLElement; const cellFormat = TableCellFormat.formats(cell); - if (!colIds[cellCount]) { + if (!colIds[cellCount] || !rowspanCount[cellCount]) { for (let i = cellCount; i >= 0; i--) { - if (!colIds[i]) colIds[i] = randomId(); + if (!colIds[i]) { + colIds[i] = randomId(); + } + if (!rowspanCount[i]) { + rowspanCount[i] = { rowspan: 0, colspan: 0 }; + } } } + if (rowspanCount[cellCount].rowspan > 0) { + rowspanCount[cellCount].rowspan -= 1; + } + else { + rowspanCount[cellCount] = { rowspan: 0, colspan: 0 }; + } + const { colspan } = rowspanCount[cellCount]; + if (cellFormat.rowspan > 1) { + rowspanCount[cellCount] = { rowspan: cellFormat.rowspan - 1, colspan: cellFormat.colspan }; + } + cellCount += colspan; const colId = colIds[cellCount]; cellCount += cellFormat.colspan; From 6bc962142fff938e8892e851cfd97d669e655400 Mon Sep 17 00:00:00 2001 From: zzxming Date: Thu, 16 Jan 2025 10:11:30 +0800 Subject: [PATCH 2/3] fix: rowspan cell paste convert get wrong colId --- docs/index.js | 18 +- src/__tests__/unit/table-clipboard.test.ts | 331 ++++++++++++++++++- src/__tests__/unit/table-insert-blot.test.ts | 143 -------- src/index.ts | 24 +- 4 files changed, 359 insertions(+), 157 deletions(-) diff --git a/docs/index.js b/docs/index.js index b16a4a6..4d4d98f 100644 --- a/docs/index.js +++ b/docs/index.js @@ -414,8 +414,24 @@ quill2.setContents([ { insert: '25' }, { attributes: { 'table-up-cell-inner': { tableId: '8v36875pbr6', rowId: 'fow0uajprzw', colId: 'y0epsy6odnm', rowspan: 1, colspan: 1 } }, insert: '\n' }, { insert: '\n' }, + + // TODO: balance table loop + // { insert: '\n' }, + // { insert: { 'table-up-col': { full: false, width: 583 } } }, + // { insert: { 'table-up-col': { full: false, width: 583 } } }, + // { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + // { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + // { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + // { insert: 'blockquote' }, + // { attributes: { 'blockquote': true, 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n\n' }, + // { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + // { insert: '\n' }, ]); // quill1.setContents(quill1.clipboard.convert({ -// html: '

1

4

2

3

5

6

7

8

9

', // content is html string +// // html: '












', +// // html: '

1

4

2

3

5

6

7

8

9

', +// // html: '



















', +// // html: '


qweqwe
123123


12345

blank

qwert


  1. check
  2. checked


  1. list
  2. list



qoute




', +// // html: '




blockquote


', // })); diff --git a/src/__tests__/unit/table-clipboard.test.ts b/src/__tests__/unit/table-clipboard.test.ts index 7d21dcf..1564d66 100644 --- a/src/__tests__/unit/table-clipboard.test.ts +++ b/src/__tests__/unit/table-clipboard.test.ts @@ -8,8 +8,8 @@ afterEach(() => { vi.useRealTimers(); }); -describe('cliboard', () => { - it('cliboard convert table', async () => { +describe('clipboard cell structure', () => { + it('clipboard convert table', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ @@ -26,7 +26,7 @@ describe('cliboard', () => { ); }); - it('cliboard convert simple row merged cell', async () => { + it('clipboard convert simple row merged cell', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ @@ -83,7 +83,7 @@ describe('cliboard', () => { ); }); - it('cliboard convert multiple merged cell', async () => { + it('clipboard convert multiple merged cell', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ @@ -171,4 +171,327 @@ describe('cliboard', () => { { ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, ); }); + + it('clipboard convert multiple merged cell 2', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ + html: '












', + }), + ); + await vi.runAllTimersAsync(); + expect(quill.root).toEqualHTML( + ` +


+
+ + ${createTaleColHTML(7, { width: 145, full: false })} + + + + + + + + + + + + + + + + + + + +
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+


+
+
+ `, + { ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, + ); + }); +}); + +describe('clipboard content format', () => { + it('should convert html code-block correctly', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ html: '

1

2

3

4

5
5
5

5

5

5

6

7

8

9

' }), + ); + await vi.runAllTimersAsync(); + + const ops = quill.getContents().ops; + const resultOps = [ + { insert: '\n' }, + { insert: { 'table-up-col': { full: false, width: 121 } } }, + { insert: { 'table-up-col': { full: false, width: 121 } } }, + { insert: { 'table-up-col': { full: false, width: 121 } } }, + { insert: '1' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '2' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '3' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '4' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '5' }, + { attributes: { 'code-block': 'plain', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '5' }, + { attributes: { 'code-block': 'plain', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '5' }, + { attributes: { 'code-block': 'plain', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '5' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '5' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '5' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '6' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '7' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '8' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '9' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '\n' }, + ]; + for (const [i, op] of ops.entries()) { + expect(op).toMatchObject(resultOps[i]); + } + }); + + it('should convert html header correctly', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ html: '

header1

header3

' }), + ); + await vi.runAllTimersAsync(); + + const ops = quill.getContents().ops; + const resultOps = [ + { insert: '\n' }, + { insert: { 'table-up-col': { full: false, width: 583 } } }, + { insert: { 'table-up-col': { full: false, width: 583 } } }, + { insert: 'header1' }, + { attributes: { 'header': 1, 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: 'header3' }, + { attributes: { 'header': 3, 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '\n' }, + ]; + for (const [i, op] of ops.entries()) { + expect(op).toMatchObject(resultOps[i]); + } + }); + + it('should convert html image correctly', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ html: '

' }), + ); + await vi.runAllTimersAsync(); + + const ops = quill.getContents().ops; + const resultOps = [ + { insert: '\n' }, + { insert: { 'table-up-col': { full: true, width: 100 } } }, + { insert: { image: 'https://upload-bbs.miyoushe.com/upload/2024/06/18/5556092/73b7bae28fded7a72d93a35d5559b24c_3979852353547906724.png' } }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '\n' }, + ]; + for (const [i, op] of ops.entries()) { + expect(op).toMatchObject(resultOps[i]); + } + }); + + it('should convert html video correctly', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ html: '


' }), + ); + await vi.runAllTimersAsync(); + + const ops = quill.getContents().ops; + const resultOps = [ + { insert: '\n' }, + { insert: { 'table-up-col': { full: true, width: 100 } } }, + { insert: { video: 'http://127.0.0.1:5500/docs/index.html' } }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '\n' }, + ]; + for (const [i, op] of ops.entries()) { + expect(op).toMatchObject(resultOps[i]); + } + }); + + it('should convert html list correctly', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ html: '
  1. list order
  2. aaa
  1. list bullet
  1. list checkbox
  2. checkbox checked


' }), + ); + await vi.runAllTimersAsync(); + + const ops = quill.getContents().ops; + const resultOps = [ + { insert: '\n' }, + { insert: { 'table-up-col': { full: false, width: 583 } } }, + { insert: { 'table-up-col': { full: false, width: 583 } } }, + { insert: 'list order' }, + { attributes: { 'list': 'ordered', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: 'aaa' }, + { attributes: { 'indent': 1, 'list': 'ordered', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: 'list bullet' }, + { attributes: { 'list': 'bullet', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: 'list checkbox' }, + { attributes: { 'list': 'unchecked', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: 'checkbox checked' }, + { attributes: { 'list': 'checked', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '\n' }, + ]; + for (const [i, op] of ops.entries()) { + expect(op).toMatchObject(resultOps[i]); + } + }); + + it('should convert html blockquote correctly', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents(quill.clipboard.convert({ + html: '




blockquote


', + })); + await vi.runAllTimersAsync(); + + const ops = quill.getContents().ops; + const resultOps = [ + { insert: '\n' }, + { insert: { 'table-up-col': { full: false, width: 583 } } }, + { insert: { 'table-up-col': { full: false, width: 583 } } }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: 'blockquote' }, + { attributes: { 'blockquote': true, 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n\n' }, + { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, + { insert: '\n' }, + ]; + for (const [i, op] of ops.entries()) { + expect(op).toMatchObject(resultOps[i]); + } + }); + + it('clipboard convert cell with block format html', async () => { + const quill = createQuillWithTableModule(`


`); + quill.setContents( + quill.clipboard.convert({ + html: '


qweqwe
123123


12345

blank

qwert


  1. check
  2. checked


  1. list
  2. list



qoute




', + }), + ); + await vi.runAllTimersAsync(); + expect(quill.root).toEqualHTML( + ` +


+
+ + ${createTaleColHTML(5, { width: 233, full: false })} + + + + + + + + + + + + + + + + + + + + + + + +
+
+


+
+
qweqwe
+
123123
+
+
+
+


+
+
+

12345

+

blank

+

qwert

+
+
+


+
+
+
    +
  1. check
  2. +
  3. checked
  4. +
+
+
+


+
+
+
    +
  1. list
  2. +
  3. list
  4. +
+
+
+


+
+


+
+
+
qoute
+

+
+
+


+
+


+
+


+
+
+ `, + { ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, + ); + }); }); diff --git a/src/__tests__/unit/table-insert-blot.test.ts b/src/__tests__/unit/table-insert-blot.test.ts index 1cc6150..14180c3 100644 --- a/src/__tests__/unit/table-insert-blot.test.ts +++ b/src/__tests__/unit/table-insert-blot.test.ts @@ -319,146 +319,3 @@ describe('column width calculate', () => { expect(quill.root.querySelectorAll('table')[0].style.width).toBe('300px'); }); }); - -describe('html convert', () => { - it('should convert html code-block correctly', async () => { - const quill = createQuillWithTableModule(`


`); - quill.setContents( - quill.clipboard.convert({ html: '

1

2

3

4

5
5
5

5

5

5

6

7

8

9

' }), - ); - await vi.runAllTimersAsync(); - - const ops = quill.getContents().ops; - const resultOps = [ - { insert: '\n' }, - { insert: { 'table-up-col': { full: false, width: 121 } } }, - { insert: { 'table-up-col': { full: false, width: 121 } } }, - { insert: { 'table-up-col': { full: false, width: 121 } } }, - { insert: '1' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '2' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '3' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '4' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '5' }, - { attributes: { 'code-block': 'plain', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '5' }, - { attributes: { 'code-block': 'plain', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '5' }, - { attributes: { 'code-block': 'plain', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '5' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '5' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '5' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '6' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '7' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '8' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '9' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '\n' }, - ]; - for (const [i, op] of ops.entries()) { - expect(op).toMatchObject(resultOps[i]); - } - }); - - it('should convert html header correctly', async () => { - const quill = createQuillWithTableModule(`


`); - quill.setContents( - quill.clipboard.convert({ html: '

header1

header3

' }), - ); - await vi.runAllTimersAsync(); - - const ops = quill.getContents().ops; - const resultOps = [ - { insert: '\n' }, - { insert: { 'table-up-col': { full: false, width: 583 } } }, - { insert: { 'table-up-col': { full: false, width: 583 } } }, - { insert: 'header1' }, - { attributes: { 'header': 1, 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: 'header3' }, - { attributes: { 'header': 3, 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '\n' }, - ]; - for (const [i, op] of ops.entries()) { - expect(op).toMatchObject(resultOps[i]); - } - }); - - it('should convert html image correctly', async () => { - const quill = createQuillWithTableModule(`


`); - quill.setContents( - quill.clipboard.convert({ html: '

' }), - ); - await vi.runAllTimersAsync(); - - const ops = quill.getContents().ops; - const resultOps = [ - { insert: '\n' }, - { insert: { 'table-up-col': { full: true, width: 100 } } }, - { insert: { image: 'https://upload-bbs.miyoushe.com/upload/2024/06/18/5556092/73b7bae28fded7a72d93a35d5559b24c_3979852353547906724.png' } }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '\n' }, - ]; - for (const [i, op] of ops.entries()) { - expect(op).toMatchObject(resultOps[i]); - } - }); - - it('should convert html video correctly', async () => { - const quill = createQuillWithTableModule(`


`); - quill.setContents( - quill.clipboard.convert({ html: '


' }), - ); - await vi.runAllTimersAsync(); - - const ops = quill.getContents().ops; - const resultOps = [ - { insert: '\n' }, - { insert: { 'table-up-col': { full: true, width: 100 } } }, - { insert: { video: 'http://127.0.0.1:5500/docs/index.html' } }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '\n' }, - ]; - for (const [i, op] of ops.entries()) { - expect(op).toMatchObject(resultOps[i]); - } - }); - - it('should convert html list correctly', async () => { - const quill = createQuillWithTableModule(`


`); - quill.setContents( - quill.clipboard.convert({ html: '
  1. list order
  2. aaa
  1. list bullet
  1. list checkbox
  2. checkbox checked


' }), - ); - await vi.runAllTimersAsync(); - - const ops = quill.getContents().ops; - const resultOps = [ - { insert: '\n' }, - { insert: { 'table-up-col': { full: false, width: 583 } } }, - { insert: { 'table-up-col': { full: false, width: 583 } } }, - { insert: 'list order' }, - { attributes: { 'list': 'ordered', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: 'aaa' }, - { attributes: { 'indent': 1, 'list': 'ordered', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: 'list bullet' }, - { attributes: { 'list': 'bullet', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: 'list checkbox' }, - { attributes: { 'list': 'unchecked', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: 'checkbox checked' }, - { attributes: { 'list': 'checked', 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, - { insert: '\n' }, - ]; - for (const [i, op] of ops.entries()) { - expect(op).toMatchObject(resultOps[i]); - } - }); -}); diff --git a/src/index.ts b/src/index.ts index 52d7824..d437698 100644 --- a/src/index.ts +++ b/src/index.ts @@ -287,6 +287,7 @@ export class TableUp { } catch {} + // TODO: selection some times will be reject mouse drag select // only can select inside table or select all table if (startBlot instanceof TableColFormat) { if (!oldRange) { @@ -484,6 +485,15 @@ export class TableUp { (op.attributes[blotName.tableCellInner] as Record).style = `background:${op.attributes.background};${cellAttrs.style}`; } } + // minus rowspan + for (const [i, span] of rowspanCount.entries()) { + if (span.rowspan > 0) { + span.rowspan -= 1; + } + if (span.rowspan <= 0) { + rowspanCount[i] = { rowspan: 0, colspan: 0 }; + } + } return delta; }); @@ -500,17 +510,14 @@ export class TableUp { } } } - if (rowspanCount[cellCount].rowspan > 0) { - rowspanCount[cellCount].rowspan -= 1; - } - else { - rowspanCount[cellCount] = { rowspan: 0, colspan: 0 }; - } + // skip the colspan of the cell in the previous row const { colspan } = rowspanCount[cellCount]; + cellCount += colspan; + // add current cell rowspan in `rowspanCount` to calculate next row cell if (cellFormat.rowspan > 1) { - rowspanCount[cellCount] = { rowspan: cellFormat.rowspan - 1, colspan: cellFormat.colspan }; + rowspanCount[cellCount] = { rowspan: cellFormat.rowspan, colspan: cellFormat.colspan }; } - cellCount += colspan; + const colId = colIds[cellCount]; cellCount += cellFormat.colspan; @@ -538,7 +545,6 @@ export class TableUp { } return new Delta(ops); }; - this.quill.clipboard.addMatcher('td', matchCell); this.quill.clipboard.addMatcher('th', matchCell); } From 80137b6b5eb9c348b15a34501ced2305260c1d76 Mon Sep 17 00:00:00 2001 From: zzxming Date: Thu, 16 Jan 2025 10:13:48 +0800 Subject: [PATCH 3/3] style: remove test code --- docs/index.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/index.js b/docs/index.js index 4d4d98f..fceecda 100644 --- a/docs/index.js +++ b/docs/index.js @@ -427,11 +427,3 @@ quill2.setContents([ // { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, // { insert: '\n' }, ]); - -// quill1.setContents(quill1.clipboard.convert({ -// // html: '












', -// // html: '

1

4

2

3

5

6

7

8

9

', -// // html: '



















', -// // html: '


qweqwe
123123


12345

blank

qwert


  1. check
  2. checked


  1. list
  2. list



qoute




', -// // html: '




blockquote


', -// }));