import Quill from 'quill'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { TableCellInnerFormat } from '../../formats'; import { TableUp } from '../../table-up'; import { createQuillWithTableModule, createTableBodyHTML, createTableCaptionHTML, createTableDeltaOps, createTableHTML, createTaleColHTML, datasetTag, expectDelta, replaceAttrEmptyRow, simulatePasteHTML } from './utils'; const Delta = Quill.import('delta'); beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); }); describe('clipboard cell structure', () => { it('clipboard convert table', async () => { Quill.register({ [`modules/${TableUp.moduleName}`]: TableUp }, true); const container = document.body.appendChild(document.createElement('div')); const quill = new Quill(container); 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 }, undefined, { isEmpty: false })}


`, { ignoreAttrs: ['class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, ); }); it('clipboard 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: ['data-wrap-tag', 'data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, ); }); it('clipboard 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: ['data-wrap-tag', 'data-tag', '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: ['data-wrap-tag', 'data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, ); }); it('clipboard convert multiple merged cell 3', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ html: '
merge1merge23
merge314
25
', }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(4, { width: 100, full: false })}

merge1

merge2

3

merge3

1

4

2

5


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, ); }); it('clipboard convert table without new line', async () => { const quill = createQuillWithTableModule(`


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

123

1

2

3

4

5

6

7

8

9

123

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

123

${createTableHTML(3, 3, { width: 100, full: false }, undefined, { isEmpty: false })}

123

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


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

Col 1

Data 1

`, }), ); await vi.runAllTimersAsync(); // string convert html style have different behavior. in node will merge same attribute // like: border-left-color:;border-right-color:;border-top-color:;border-bottom-color:; will merge to border-color:; expect(quill.root).toEqualHTML( `


Col 1

Data 1


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('clipboard convert cell border with different cell', async () => { const quill = createQuillWithTableModule(`


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










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


${createTaleColHTML(3, { full: false, width: 211 })}











`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('clipboard convert cell background', async () => { const quill = createQuillWithTableModule(`


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










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


${createTaleColHTML(3, { full: false, width: 211 })}











`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('clipboard convert cell height', async () => { const quill = createQuillWithTableModule(`


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





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


${createTaleColHTML(2, { full: false, width: 317 })}






`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('clipboard convert empty cell should not ignore', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ html: `
qwe
23
45
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(3, { full: false, width: 100 })}

q

w

e


2

3


4

5


`, { ignoreAttrs: ['data-wrap-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('clipboard convert cell background with default background', async () => { const quill = createQuillWithTableModule(`


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

123456789

head

2

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


${createTaleColHTML(2, { full: false, width: 121 })}

123456789

head

2


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 121 } } }, { insert: { 'table-up-col': { full: false, width: 121 } } }, { attributes: { background: '#e60000' }, insert: '123' }, { insert: '456' }, { attributes: { background: '#008a00' }, insert: '789' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, style: 'background-color: rgb(41, 114, 244);' } }, insert: '\n' }, { insert: 'h' }, { attributes: { background: '#000000' }, insert: 'ea' }, { insert: 'd' }, { attributes: { 'header': 1, 'table-up-cell-inner': { rowspan: 1, colspan: 1, style: 'background-color: rgb(41, 114, 244);' } }, insert: '\n' }, { insert: '2' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); it('clipboard convert cell background if text background equal cell background then clean text background', async () => { const quill = createQuillWithTableModule(`


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

123

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


${createTaleColHTML(1, { full: false, width: 100 })}

123


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('convert background on table/tbody/tr/td', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ html: `
1 2
3 4
5 6
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(2, { full: false, width: 100 })}

1

2

3

4

5

6


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('clipboard convert should generate colgroup at correct position', async () => { const quill = createQuillWithTableModule(`


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

1

2

3

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


${createTableCaptionHTML({ text: 'title' })} ${createTaleColHTML(3, { full: false, width: 100 })} ${createTableBodyHTML(1, 3, { isEmpty: false })}


`, { ignoreAttrs: ['class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); expectDelta( new Delta([ { insert: '\ntitle' }, { attributes: { 'table-up-caption': { side: 'top' } }, insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: '1' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' }, { insert: '2' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' }, { insert: '3' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); it('clipboard convert rowspan and struct have empty tr', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ html: `
合并1 合并2
合并3
合并4
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(2, { full: false, width: 63 })}

合并1

合并2

合并3

合并4


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'data-style', 'style', 'contenteditable'] }, ); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 63 } } }, { insert: { 'table-up-col': { full: false, width: 63 } } }, { insert: '合并1' }, { attributes: { 'table-up-cell-inner': { rowspan: 3, 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: '\n' }, ]), quill.getContents(), ); }); it('clipboard convert empty multiple tr to `emptyRow`', async () => { const quill = createQuillWithTableModule('


', { autoMergeCell: false }); quill.setContents( quill.clipboard.convert({ html: `
1
234
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(3, { full: false, width: 100 })}

1

2

3

4


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'data-style', 'style', 'contenteditable'], replaceAttrs: { 'data-empty-row': replaceAttrEmptyRow, }, }, ); }); it('clipboard convert `emptyRow` cell', async () => { const quill = createQuillWithTableModule('


', { autoMergeCell: false }); quill.setContents( quill.clipboard.convert({ html: `

1

2

3

4

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


${createTaleColHTML(3, { full: false, width: 100 })}

1

2

3

4


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'data-style', 'style', 'contenteditable'], replaceAttrs: { 'data-empty-row': replaceAttrEmptyRow, }, }, ); }); it('clipboard convert continuous `emptyRow`', async () => { const quill = createQuillWithTableModule('


', { autoMergeCell: false }); quill.setContents( quill.clipboard.convert({ html: `

1

1

2

3

4

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


${createTaleColHTML(3, { full: false, width: 100 })}

1

1

2

3

4


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'data-style', 'style', 'contenteditable'], replaceAttrs: { 'data-empty-row': replaceAttrEmptyRow, }, }, ); }); it('clipboard convert empty tr to `emptyRow` in thead', async () => { const quill = createQuillWithTableModule(`


`, { autoMergeCell: false }); quill.setContents( quill.clipboard.convert({ html: `
1
12
12
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(2, { full: false, width: 100 })}

1

1

2

1

2


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'data-style', 'style', 'contenteditable'], replaceAttrs: { 'data-empty-row': replaceAttrEmptyRow, }, }, ); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: '1' }, { attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2, wrapTag: 'thead' } }, insert: '\n' }, { insert: '1' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, wrapTag: 'tbody' } }, insert: '\n' }, { insert: '2' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, wrapTag: 'tbody' } }, insert: '\n' }, { insert: '1' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, wrapTag: 'tbody' } }, insert: '\n' }, { insert: '2' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, wrapTag: 'tbody' } }, insert: '\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); it('clipboard convert col with span attribute', async () => { const quill = createQuillWithTableModule(`


`, { autoMergeCell: false }); quill.setContents( quill.clipboard.convert({ html: `
1 2
3
4
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(4, { full: false, width: 63 })}

1

2

3

4


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'data-style', 'style', 'contenteditable'], replaceAttrs: { 'data-empty-row': replaceAttrEmptyRow, }, }, ); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 63 } } }, { insert: { 'table-up-col': { full: false, width: 63 } } }, { insert: { 'table-up-col': { full: false, width: 63 } } }, { insert: { 'table-up-col': { full: false, width: 63 } } }, { insert: '1' }, { attributes: { 'table-up-cell-inner': { rowspan: 6, colspan: 2 } }, insert: '\n' }, { insert: '2' }, { attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' }, { insert: '3' }, { attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' }, { insert: '4' }, { attributes: { 'table-up-cell-inner': { rowspan: 2, colspan: 2 } }, insert: '\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); it('clipboard convert th correctly', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ html: `
Company Contact Country
Alfreds Futterkiste Maria Anders Germany
Centro comercial Moctezuma Francisco Chang Mexico
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(3, { full: false, width: 100 })}

Company

Contact

Country

Alfreds Futterkiste

Maria Anders

Germany

Centro comercial Moctezuma

Francisco Chang

Mexico


`, { ignoreAttrs: ['data-wrap-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('convert thead and tfoot correctly', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ html: `
head1 head2 head3
body1 body2 body3
body4 body5 body6
foot1 foot2 foot3
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(3, { full: false, width: 100 })}

head1

head2

head3

body1

body2

body3

body4

body5

body6

foot1

foot2

foot3


`, { ignoreAttrs: ['class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'] }, ); }); it('convert thead rowspan to tbody', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ html: `
123
1 2
1 2
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(2, { full: false, width: 100 })}

123

1

2

1

2


`, { ignoreAttrs: ['class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', '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(); expectDelta( new Delta([ { 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' }, ]), quill.getContents(), ); }); it('should convert html header correctly', async () => { const quill = createQuillWithTableModule(`


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

header1

header3

' }), ); await vi.runAllTimersAsync(); expectDelta( new Delta([ { 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' }, ]), quill.getContents(), ); }); it('should convert html image correctly', async () => { const quill = createQuillWithTableModule(`


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

' }), ); await vi.runAllTimersAsync(); expectDelta( new Delta([ { 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' }, ]), quill.getContents(), ); }); it('should convert html video correctly', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents( quill.clipboard.convert({ html: '
' }), ); await vi.runAllTimersAsync(); expectDelta( new Delta([ { 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' }, ]), quill.getContents(), ); }); 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(); expectDelta( new Delta([ { 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' }, ]), quill.getContents(), ); }); it('should convert html blockquote correctly', async () => { const quill = createQuillWithTableModule(`


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




blockquote


', })); await vi.runAllTimersAsync(); expectDelta( new Delta([ { 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' }, ]), quill.getContents(), ); }); 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. checked


  1. list
  2. list



qoute





`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'style', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, ); }); it('clipboard conver multiple formats and attributes', async () => { const quill = createQuillWithTableModule(`


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

qwf

qwfqwfw
  1. qwgqwgwqg

qwg



qwgwqgwgqwg

qwgwqg

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


${createTaleColHTML(3, { full: false, width: 100 })}

qwf

qwfqwfw
  1. qwgqwg wqg

qwg



qwgwqgwgqwg

qwgwqg


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'data-table-id', 'data-row-id', 'data-col-id', 'data-rowspan', 'data-colspan', 'contenteditable'], }, ); }); it('clipboard convert cell with background on tr', async () => { const quill = createQuillWithTableModule(`


`); // color convert hex in quill internal quill.setContents( quill.clipboard.convert({ html: `
1 2 3
4 5 6
7 8 9
`, }), ); await vi.runAllTimersAsync(); expect(quill.root).toEqualHTML( `


${createTaleColHTML(3, { width: 100, full: false })}

1

2

3

4

5

6

7

8

9


`, { ignoreAttrs: ['data-wrap-tag', 'data-tag', 'class', 'colspan', 'rowspan', 'data-colspan', 'data-rowspan', 'data-table-id', 'data-row-id', 'data-col-id', 'contenteditable'] }, ); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { attributes: { background: '#edeef2' }, insert: '1' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, style: 'background-color: rgb(237, 238, 242);' } }, insert: '\n' }, { attributes: { background: '#edeef2' }, insert: '2' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, style: 'background-color: rgb(237, 238, 242);' } }, insert: '\n' }, { attributes: { background: '#edeef2' }, insert: '3' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, style: 'background-color: rgb(237, 238, 242);' } }, insert: '\n' }, { insert: '4' }, { 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' }, { attributes: { background: '#edeef2' }, insert: '7' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, style: 'background-color: rgb(237, 238, 242);' } }, insert: '\n' }, { attributes: { background: '#edeef2' }, insert: '8' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, style: 'background-color: rgb(237, 238, 242);' } }, insert: '\n' }, { attributes: { background: '#edeef2' }, insert: '9' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1, style: 'background-color: rgb(237, 238, 242);' } }, insert: '\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); }); describe('clipboard cell in cell', () => { it('paste simple text into table', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents(createTableDeltaOps(1, 1, { full: false, width: 100 }, {}, { isEmpty: true })); await vi.runAllTimersAsync(); await simulatePasteHTML( quill, { index: 2, length: 0 }, '

text

123

', ); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: 'text' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, { insert: '123' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); it('paste format text into table', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents(createTableDeltaOps(1, 1, { full: false, width: 100 }, {}, { isEmpty: true })); await vi.runAllTimersAsync(); await simulatePasteHTML( quill, { index: 2, length: 0 }, '\r\n\r\n\u003C!--StartFragment-->

123

123qwe

\u003C!--EndFragment-->\r\n\r\n', ); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: '123' }, { attributes: { 'header': 1, 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, { attributes: { underline: true, strike: true, italic: true, background: '#000000', color: '#e60000', bold: true }, insert: '123' }, { attributes: { underline: true, strike: true, italic: true, bold: true, background: '#000000', color: '#e60000', script: 'sub' }, insert: 'qwe' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); it('paste cell text into table', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents(createTableDeltaOps(1, 1, { full: false, width: 100 }, {}, { isEmpty: true })); await vi.runAllTimersAsync(); const range = { index: 2, length: 0 }; quill.setSelection(range); quill.clipboard.onPaste( range, { html: '\r\n\r\n\u003C!--StartFragment-->

5

q

\u003C!--EndFragment-->\r\n\r\n' }, ); await vi.runAllTimersAsync(); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: '5' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n\n' }, { insert: 'q' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); it('paste cell with format text into table', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents(createTableDeltaOps(1, 1, { full: false, width: 100 }, {}, { isEmpty: true })); await vi.runAllTimersAsync(); const range = { index: 2, length: 0 }; quill.setSelection(range); quill.clipboard.onPaste( range, { html: '\r\n\r\n\u003C!--StartFragment-->

123

123qweqwe

\u003C!--EndFragment-->\r\n\r\n' }, ); await vi.runAllTimersAsync(); expectDelta( new Delta([ { insert: '\n' }, { insert: { 'table-up-col': { full: false, width: 100 } } }, { insert: '123' }, { attributes: { 'header': 1, 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n' }, { attributes: { underline: true, strike: true, italic: true, bold: true }, insert: '123' }, { attributes: { underline: true, strike: true, italic: true, bold: true, script: 'sub' }, insert: 'qwe' }, { attributes: { underline: true, strike: true, italic: true, bold: true, script: 'super' }, insert: 'qwe' }, { attributes: { 'table-up-cell-inner': { rowspan: 1, colspan: 1 } }, insert: '\n\n' }, { insert: '\n' }, ]), quill.getContents(), ); }); }); describe('test TableUp `getHTMLByCell`', () => { it('getHTMLByCell return cell html', async () => { const quill = createQuillWithTableModule(`


`); quill.setContents(createTableDeltaOps(4, 4, { full: true }, {}, { isEmpty: false })); const tableModule = quill.getModule(TableUp.moduleName) as TableUp; const tds = quill.scroll.descendants(TableCellInnerFormat, 0); tableModule.mergeCells([tds[0], tds[1], tds[4], tds[5]]); await vi.runAllTimersAsync(); const html = tableModule.getHTMLByCell([tds[0], tds[2], tds[6]]); const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const htmlCols = Array.from(doc.querySelectorAll('col')); const htmlTds = Array.from(doc.querySelectorAll('td')); expect(htmlCols.length).toBe(3); expect(htmlTds.length).toBe(3); for (const col of htmlCols) { expect(col.getAttribute('width')).toBe('33%'); } }); });