diff --git a/src/converters/fromHtml.js b/src/converters/fromHtml.js index e8e2d91..c3696dc 100644 --- a/src/converters/fromHtml.js +++ b/src/converters/fromHtml.js @@ -4,6 +4,7 @@ import { draftTableBlock, draftTextBlock } from './draftjs.js'; import { slateTableBlock, slateTextBlock } from './slate.js'; import { groupInlineNodes, + isInline, isWhitespace, isGlobalInline, } from '../helpers/dom.js'; @@ -89,9 +90,6 @@ const skipCommentsAndWhitespace = (elements) => { ); }; -const isInline = (n) => - n.nodeType === TEXT_NODE || isGlobalInline(n.tagName.toLowerCase()); - const extractElementsWithConverters = (el, defaultTextBlock, href) => { const result = []; if (el.tagName === 'A') { diff --git a/src/converters/slate.js b/src/converters/slate.js index 3b42017..eb9e47b 100644 --- a/src/converters/slate.js +++ b/src/converters/slate.js @@ -290,7 +290,12 @@ const slateTableBlock = (elem) => { for (const cell of tchild.children) { const cellType = cell.tagName === 'TD' ? 'data' : 'header'; const cellValue = deserializeChildren(cell); - cells.push(createCell(cellType, cellValue)); + const elements = cellValue.map((element) => + isInline(element) + ? jsx('element', { type: 'span' }, [element]) + : element, + ); + cells.push(createCell(cellType, elements)); } rows.push({ key: getId(), cells }); } diff --git a/src/converters/slate.test.js b/src/converters/slate.test.js index fc9cdd6..b71af2a 100644 --- a/src/converters/slate.test.js +++ b/src/converters/slate.test.js @@ -640,7 +640,9 @@ describe('slateTableBlock processing a simple table', () => { expect(rows[0].cells[0].key).toBeDefined(); expect(rows[0].cells[0].type).toBe('data'); expect(rows[0].cells[0].value).toHaveLength(1); - const value = rows[0].cells[0].value[0]; + const parentValue = rows[0].cells[0].value[0]; + expect(parentValue['type']).toBe('span'); + const value = parentValue['children'][0]; expect(value['text']).toBe('A value'); }); }); @@ -657,7 +659,10 @@ describe('slateTableBlock processing a table with whitespace', () => { const cells = rows[0].cells; expect(cells).toHaveLength(1); const cell = cells[0]; - expect(cell.value).toEqual([{ text: 'A value\n\xa0' }]); + const parentValue = cell.value[0]; + expect(parentValue['type']).toBe('span'); + const value = parentValue['children'][0]; + expect(value).toEqual({ text: 'A value' }); }); }); @@ -678,7 +683,9 @@ describe('slateTableBlock processing a table with a link', () => { expect(rows[0].cells).toHaveLength(1); expect(rows[0].cells[0].type).toBe('data'); expect(rows[0].cells[0].value).toHaveLength(1); - const value = rows[0].cells[0].value[0]; + const parentValue = rows[0].cells[0].value[0]; + expect(parentValue['type']).toBe('span'); + const value = parentValue['children'][0]; expect(value['type']).toBe('link'); expect(value['data']['url']).toBe('https://plone.org'); expect(value['children'][0]['text']).toBe('Plone'); @@ -707,14 +714,18 @@ describe('slateTableBlock processing a table with a link', () => { test('first value is a text', () => { const result = slateTableBlock(elem); const rows = result.table.rows; - let value = rows[0].cells[0].value[0]; + const parentValue = rows[0].cells[0].value[0]; + expect(parentValue['type']).toBe('span'); + const value = parentValue['children'][0]; expect(value['text']).toBe('Plone '); }); - test('second value is the link', () => { + test('second value is the span with the link', () => { const result = slateTableBlock(elem); const rows = result.table.rows; - let value = rows[0].cells[0].value[1]; + const parentValue = rows[0].cells[0].value[1]; + expect(parentValue['type']).toBe('span'); + const value = parentValue['children'][0]; expect(value['type']).toBe('link'); expect(value['data']['url']).toBe('https://plone.org'); expect(value['children'][0]['text']).toBe('site'); @@ -729,13 +740,20 @@ describe('slateTableBlock processing a table with text + sup', () => { test('will keep sup inline', () => { const result = slateTableBlock(elem); const cell = result.table.rows[0].cells[0]; - expect(cell.value).toEqual([ - { text: '10' }, - { - type: 'sup', - children: [{ text: '2' }], - }, - ]); + expect(cell.value).toHaveLength(2); + expect(cell.value[0]).toEqual({ + type: 'span', + children: [{ text: '10' }], + }); + expect(cell.value[1]).toEqual({ + type: 'span', + children: [ + { + type: 'sup', + children: [{ text: '2' }], + }, + ], + }); }); }); @@ -744,11 +762,48 @@ describe('slateTableBlock processing a table with a div', () => { '
text
', ); - test('will remove the div', () => { + test('will replace the div with a paragraph', () => { const result = slateTableBlock(elem); const cell = result.table.rows[0].cells[0]; expect(cell.value).toEqual([ - { type: 'strong', children: [{ text: 'text' }] }, + { + type: 'span', + children: [{ type: 'strong', children: [{ text: 'text' }] }], + }, ]); }); }); + +describe('slateTableBlock parsing table with bold text', () => { + const elem = elementFromString( + '\n\n\n\n
Text1
', + ); + test('returns valid result with the correct children', () => { + const block = slateTableBlock(elem); + expect(block['@type']).toEqual('slateTable'); + const rows = block['table']['rows']; + expect(rows).toHaveLength(1); + const cells = rows[0]['cells']; + expect(cells).toHaveLength(1); + const value = cells[0]['value'][0]; + expect(value['type']).toEqual('span'); + expect(value['children'][0]['type']).toEqual('strong'); + }); +}); + +describe('slateTableBlock parsing table with line break', () => { + const elem = elementFromString( + '\n\n\n\n

Text
', + ); + test('returns valid result with the correct children', () => { + const block = slateTableBlock(elem); + expect(block['@type']).toEqual('slateTable'); + const rows = block['table']['rows']; + expect(rows).toHaveLength(1); + const cells = rows[0]['cells']; + expect(cells).toHaveLength(1); + const value = cells[0]['value'][0]; + expect(value['type']).toEqual('span'); + expect(value['children'][0]['text']).toEqual('\n'); + }); +}); diff --git a/src/helpers/dom.js b/src/helpers/dom.js index 4300e0b..bede1c0 100644 --- a/src/helpers/dom.js +++ b/src/helpers/dom.js @@ -3,6 +3,8 @@ const { JSDOM } = jsdom; const DOMParser = new JSDOM().window.DOMParser; const parser = new DOMParser(); +const TEXT_NODE = 3; + const elementFromString = (value) => { const elem = parser.parseFromString(value, 'text/html').body.firstChild; return elem; @@ -51,4 +53,13 @@ const inlineElements = [ const isGlobalInline = (tagName) => inlineElements.includes(tagName); -export { elementFromString, isWhitespace, isGlobalInline, groupInlineNodes }; +const isInline = (n) => + n.nodeType === TEXT_NODE || isGlobalInline(n.tagName.toLowerCase()); + +export { + elementFromString, + isInline, + isWhitespace, + isGlobalInline, + groupInlineNodes, +};