diff options
author | Max <max@nextcloud.com> | 2022-03-14 15:57:34 +0300 |
---|---|---|
committer | Max <max@nextcloud.com> | 2022-03-31 15:29:20 +0300 |
commit | 759f8cbc0cc4ad9c28382f384b7c84963aa9d89a (patch) | |
tree | ea3ec3af29f0dcae10d91e8e9eccca78cf8b2c2e | |
parent | a62606ce6af09fb88fc18866864dc73035f108f3 (diff) |
fix: handling of various table formats
Signed-off-by: Max <max@nextcloud.com>
-rw-r--r-- | src/nodes/Table.js | 37 | ||||
-rw-r--r-- | src/nodes/TableBody.js | 8 | ||||
-rw-r--r-- | src/nodes/TableCell.js | 8 | ||||
-rw-r--r-- | src/nodes/TableHead.js | 6 | ||||
-rw-r--r-- | src/nodes/TableHeader.js | 12 | ||||
-rw-r--r-- | src/nodes/TableRow.js | 5 | ||||
-rw-r--r-- | src/tests/fixtures/tables/handbook-caption-tbody.html | 34 | ||||
-rw-r--r-- | src/tests/fixtures/tables/handbook-empty-thead-tbody.html | 34 | ||||
-rw-r--r-- | src/tests/fixtures/tables/handbook-multiple-tbody.html | 36 | ||||
-rw-r--r-- | src/tests/fixtures/tables/handbook-thead-tbody.html | 34 | ||||
-rw-r--r-- | src/tests/fixtures/tables/handbook-with-caption.html | 33 | ||||
-rw-r--r-- | src/tests/fixtures/tables/handbook.html | 32 | ||||
-rw-r--r-- | src/tests/fixtures/tables/handbook.out.html | 34 | ||||
-rw-r--r-- | src/tests/tables.spec.js | 16 |
14 files changed, 313 insertions, 16 deletions
diff --git a/src/nodes/Table.js b/src/nodes/Table.js index 02441aacf..a4d93ed85 100644 --- a/src/nodes/Table.js +++ b/src/nodes/Table.js @@ -1,8 +1,41 @@ import { Table } from '@tiptap/extension-table' -import { mergeAttributes } from '@tiptap/core' +import { Node, mergeAttributes } from '@tiptap/core' + +/* + * Markdown tables do not include captions. + * We still need to parse them though + * because otherwise tiptap will try to insert their text content + * and put it in the top row of the table. + */ +const tableCaption = Node.create({ + name: 'tableCaption', + content: 'inline*', + addAttributes() { + return {} + }, + + renderHTML() { + return ['caption'] + }, + + toMarkdown(state, node) { + }, + + parseHTML() { + return [ + { tag: 'table caption', priority: 90 }, + ] + }, +}) export default Table.extend({ - content: 'tableHead tableBody', + content: 'tableCaption? tableHead tableBody', + + addExtensions() { + return [ + tableCaption, + ] + }, renderHTML({ HTMLAttributes }) { return ['table', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0] diff --git a/src/nodes/TableBody.js b/src/nodes/TableBody.js index bf0e9b616..5a2673424 100644 --- a/src/nodes/TableBody.js +++ b/src/nodes/TableBody.js @@ -2,7 +2,7 @@ import { Node, mergeAttributes } from '@tiptap/core' export default Node.create({ name: 'tableBody', - content: 'tableRow', + content: 'tableRow*', addOptions() { return { @@ -10,12 +10,6 @@ export default Node.create({ } }, - parseHTML() { - return [ - { tag: 'tbody' }, - ] - }, - renderHTML({ HTMLAttributes }) { return ['tbody', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0] }, diff --git a/src/nodes/TableCell.js b/src/nodes/TableCell.js index b3829640f..82fa666b3 100644 --- a/src/nodes/TableCell.js +++ b/src/nodes/TableCell.js @@ -13,4 +13,12 @@ export default TableCell.extend({ state.write(' |') }, + parseHTML() { + return [ + { tag: 'td' }, + { tag: 'th' }, + { tag: 'table thead ~ tbody th', priority: 70 }, + { tag: 'table thead ~ tbody td', priority: 70 }, + ] + }, }) diff --git a/src/nodes/TableHead.js b/src/nodes/TableHead.js index 9fe6c94da..0cd7af788 100644 --- a/src/nodes/TableHead.js +++ b/src/nodes/TableHead.js @@ -39,12 +39,8 @@ export default Node.create({ }, addExtensions() { - return [tableHeadRow] - }, - - parseHTML() { return [ - { tag: 'thead' }, + tableHeadRow, ] }, diff --git a/src/nodes/TableHeader.js b/src/nodes/TableHeader.js index 936ab26f2..b08f5c609 100644 --- a/src/nodes/TableHeader.js +++ b/src/nodes/TableHeader.js @@ -13,4 +13,16 @@ export default TableHeader.extend({ state.write(' |') }, + parseHTML() { + return [ + { tag: 'table thead:empty ~ tbody :first-child th', priority: 80 }, + { tag: 'table thead:empty ~ tbody :first-child td', priority: 80 }, + { tag: 'table thead :first-child th', priority: 60 }, + { tag: 'table thead :first-child td', priority: 60 }, + { tag: 'table tbody :first-child th', priority: 60 }, + { tag: 'table tbody :first-child td', priority: 60 }, + { tag: 'table > :first-child > th', priority: 60 }, + { tag: 'table > :first-child > td', priority: 60 }, + ] + }, }) diff --git a/src/nodes/TableRow.js b/src/nodes/TableRow.js index 915cae27b..3beb7cf06 100644 --- a/src/nodes/TableRow.js +++ b/src/nodes/TableRow.js @@ -11,4 +11,9 @@ export default TableRow.extend({ state.renderInline(node) }, + parseHTML() { + return [ + { tag: 'tr', priority: 80 }, + ] + }, }) diff --git a/src/tests/fixtures/tables/handbook-caption-tbody.html b/src/tests/fixtures/tables/handbook-caption-tbody.html new file mode 100644 index 000000000..7dc9d82ea --- /dev/null +++ b/src/tests/fixtures/tables/handbook-caption-tbody.html @@ -0,0 +1,34 @@ +<table id="bkmrk-section-name" style="border-collapse: collapse; width: 100%; height: 150px;" border="1"> +<caption>Testing tables +</caption> +<tbody> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Heading 0</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 1</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 2</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 3</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 4</strong></td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Letter</strong></td> +<td style="width: 20%; height: 29px;">a</td> +<td style="width: 20%; height: 29px;">b</td> +<td style="width: 20%; height: 29px;">c</td> +<td style="width: 20%; height: 29px;">d</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Number</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">2</td> +<td style="width: 20%; height: 29px;">3</td> +<td style="width: 20%; height: 29px;">4</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Square</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">4</td> +<td style="width: 20%; height: 29px;">9</td> +<td style="width: 20%; height: 29px;">16</td> +</tr> +</tbody> +</table> diff --git a/src/tests/fixtures/tables/handbook-empty-thead-tbody.html b/src/tests/fixtures/tables/handbook-empty-thead-tbody.html new file mode 100644 index 000000000..9ea8376c7 --- /dev/null +++ b/src/tests/fixtures/tables/handbook-empty-thead-tbody.html @@ -0,0 +1,34 @@ +<table id="bkmrk-section-name" style="border-collapse: collapse; width: 100%; height: 150px;" border="1"> +<thead> +</thead> +<tbody> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Heading 0</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 1</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 2</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 3</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 4</strong></td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Letter</strong></td> +<td style="width: 20%; height: 29px;">a</td> +<td style="width: 20%; height: 29px;">b</td> +<td style="width: 20%; height: 29px;">c</td> +<td style="width: 20%; height: 29px;">d</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Number</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">2</td> +<td style="width: 20%; height: 29px;">3</td> +<td style="width: 20%; height: 29px;">4</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Square</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">4</td> +<td style="width: 20%; height: 29px;">9</td> +<td style="width: 20%; height: 29px;">16</td> +</tr> +</tbody> +</table> diff --git a/src/tests/fixtures/tables/handbook-multiple-tbody.html b/src/tests/fixtures/tables/handbook-multiple-tbody.html new file mode 100644 index 000000000..02eb3ed07 --- /dev/null +++ b/src/tests/fixtures/tables/handbook-multiple-tbody.html @@ -0,0 +1,36 @@ +<table id="bkmrk-section-name" style="border-collapse: collapse; width: 100%; height: 150px;" border="1"> +<tbody> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Heading 0</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 1</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 2</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 3</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 4</strong></td> +</tr> +</tbody> +<tbody> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Letter</strong></td> +<td style="width: 20%; height: 29px;">a</td> +<td style="width: 20%; height: 29px;">b</td> +<td style="width: 20%; height: 29px;">c</td> +<td style="width: 20%; height: 29px;">d</td> +</tr> +</tbody> +<tbody> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Number</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">2</td> +<td style="width: 20%; height: 29px;">3</td> +<td style="width: 20%; height: 29px;">4</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Square</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">4</td> +<td style="width: 20%; height: 29px;">9</td> +<td style="width: 20%; height: 29px;">16</td> +</tr> +</tbody> +</table> diff --git a/src/tests/fixtures/tables/handbook-thead-tbody.html b/src/tests/fixtures/tables/handbook-thead-tbody.html new file mode 100644 index 000000000..63b4f3157 --- /dev/null +++ b/src/tests/fixtures/tables/handbook-thead-tbody.html @@ -0,0 +1,34 @@ +<table id="bkmrk-section-name" style="border-collapse: collapse; width: 100%; height: 150px;" border="1"> +<thead> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Heading 0</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 1</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 2</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 3</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 4</strong></td> +</tr> +</thead> +<tbody> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Letter</strong></td> +<td style="width: 20%; height: 29px;">a</td> +<td style="width: 20%; height: 29px;">b</td> +<td style="width: 20%; height: 29px;">c</td> +<td style="width: 20%; height: 29px;">d</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Number</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">2</td> +<td style="width: 20%; height: 29px;">3</td> +<td style="width: 20%; height: 29px;">4</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Square</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">4</td> +<td style="width: 20%; height: 29px;">9</td> +<td style="width: 20%; height: 29px;">16</td> +</tr> +</tbody> +</table> diff --git a/src/tests/fixtures/tables/handbook-with-caption.html b/src/tests/fixtures/tables/handbook-with-caption.html new file mode 100644 index 000000000..f288b4b19 --- /dev/null +++ b/src/tests/fixtures/tables/handbook-with-caption.html @@ -0,0 +1,33 @@ +<table id="bkmrk-section-name" style="border-collapse: collapse; width: 100%; height: 150px;" border="1"> +<caption>test</caption> +<tbody> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Heading 0</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 1</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 2</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 3</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 4</strong></td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Letter</strong></td> +<td style="width: 20%; height: 29px;">a</td> +<td style="width: 20%; height: 29px;">b</td> +<td style="width: 20%; height: 29px;">c</td> +<td style="width: 20%; height: 29px;">d</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Number</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">2</td> +<td style="width: 20%; height: 29px;">3</td> +<td style="width: 20%; height: 29px;">4</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Square</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">4</td> +<td style="width: 20%; height: 29px;">9</td> +<td style="width: 20%; height: 29px;">16</td> +</tr> +</tbody> +</table> diff --git a/src/tests/fixtures/tables/handbook.html b/src/tests/fixtures/tables/handbook.html new file mode 100644 index 000000000..f0be817ae --- /dev/null +++ b/src/tests/fixtures/tables/handbook.html @@ -0,0 +1,32 @@ +<table id="bkmrk-section-name" style="border-collapse: collapse; width: 100%; height: 150px;" border="1"> +<tbody> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Heading 0</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 1</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 2</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 3</strong></td> +<td style="width: 20%; height: 29px;"><strong>Heading 4</strong></td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Letter</strong></td> +<td style="width: 20%; height: 29px;">a</td> +<td style="width: 20%; height: 29px;">b</td> +<td style="width: 20%; height: 29px;">c</td> +<td style="width: 20%; height: 29px;">d</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Number</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">2</td> +<td style="width: 20%; height: 29px;">3</td> +<td style="width: 20%; height: 29px;">4</td> +</tr> +<tr style="height: 29px;"> +<td style="width: 20%; height: 29px;"><strong>Square</strong></td> +<td style="width: 20%; height: 29px;">1</td> +<td style="width: 20%; height: 29px;">4</td> +<td style="width: 20%; height: 29px;">9</td> +<td style="width: 20%; height: 29px;">16</td> +</tr> +</tbody> +</table> diff --git a/src/tests/fixtures/tables/handbook.out.html b/src/tests/fixtures/tables/handbook.out.html new file mode 100644 index 000000000..ad2d26a4a --- /dev/null +++ b/src/tests/fixtures/tables/handbook.out.html @@ -0,0 +1,34 @@ +<table> +<thead> +<tr> +<th><strong>Heading 0</strong></th> +<th><strong>Heading 1</strong></th> +<th><strong>Heading 2</strong></th> +<th><strong>Heading 3</strong></th> +<th><strong>Heading 4</strong></th> +</tr> +</thead> +<tbody> +<tr> +<td><strong>Letter</strong></td> +<td>a</td> +<td>b</td> +<td>c</td> +<td>d</td> +</tr> +<tr> +<td><strong>Number</strong></td> +<td>1</td> +<td>2</td> +<td>3</td> +<td>4</td> +</tr> +<tr> +<td><strong>Square</strong></td> +<td>1</td> +<td>4</td> +<td>9</td> +<td>16</td> +</tr> +</tbody> +</table> diff --git a/src/tests/tables.spec.js b/src/tests/tables.spec.js index 7a347eb9e..7e0bdce33 100644 --- a/src/tests/tables.spec.js +++ b/src/tests/tables.spec.js @@ -4,12 +4,14 @@ import markdownit from './../markdownit' import input from './fixtures/table.md' import output from './fixtures/table.html' import otherStructure from './fixtures/tableWithOtherStructure.html' +import handbook from './fixtures/tables/handbook.html' +import handbookOut from './fixtures/tables/handbook.out.html' describe('Table', () => { test('load into editor', () => { const tiptap = editorWithContent(markdownit.render(input)) - expect(tiptap.getHTML().replaceAll('><', ">\n<")).toBe(output.replace(/\n$/, '')) + expect(formatHTML(tiptap.getHTML())).toBe(formatHTML(output)) }) test('serialize from editor', () => { @@ -22,7 +24,14 @@ describe('Table', () => { const tiptap = editorWithContent( otherStructure.replace(/\n\s*/g,'') ) - expect(tiptap.getHTML().replaceAll('><', ">\n<")).toBe(output.replace(/\n$/, '')) + expect(formatHTML(tiptap.getHTML())).toBe(formatHTML(output)) + }) + + test('handle html table from handbook', () => { + const tiptap = editorWithContent( + handbook.replace(/\n\s*/g,'') + ) + expect(formatHTML(tiptap.getHTML())).toBe(formatHTML(handbookOut)) }) }) @@ -34,3 +43,6 @@ function editorWithContent(content) { }) } +function formatHTML(html) { + return html.replaceAll('><', ">\n<").replace(/\n$/, '') +} |