Skip to content

Commit

Permalink
fix: Fix issue #6 Images within headings are dropped.
Browse files Browse the repository at this point in the history
  • Loading branch information
ericof committed Feb 22, 2022
1 parent 2f0e0ac commit fa5394d
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 43 deletions.
75 changes: 35 additions & 40 deletions src/converters/fromHtml.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,61 +9,56 @@ const parser = new DOMParser();

global.document = new JSDOM('...').window.document;

const convertFromHTML = (input, defaultTextBlock) => {
const document = parser.parseFromString(input, 'text/html');
const blockElements = ['DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P'];

const elementsWithConverters = ['IMG', 'VIDEO', 'TABLE', 'IFRAME'];

const blockFromElement = (el, defaultTextBlock) => {
let textBlock = slateTextBlock;
let tableBlock = slateTableBlock;
if (defaultTextBlock === 'draftjs') {
tableBlock = draftTableBlock;
textBlock = draftTextBlock;
}
let raw = {};
switch (el.tagName) {
case 'IMG':
raw = imageBlock(el);
break;
case 'VIDEO':
raw = videoBlock(el);
break;
case 'TABLE':
raw = tableBlock(el);
break;
case 'IFRAME':
raw = iframeBlock(el);
break;
default:
raw = textBlock(el);
break;
}
return raw;
};

const convertFromHTML = (input, defaultTextBlock) => {
const document = parser.parseFromString(input, 'text/html');
const result = [];
let elements = document.body.children;
const firstChild = document.body.firstElementChild;

let elements = document.body.children;
if (elements.length === 1 && firstChild.tagName === 'DIV') {
elements = document.body.firstElementChild.children;
}

for (const el of elements) {
let raw = {};
const child = el.firstElementChild;
if (el.nodeName === 'P') {
if (child != null) {
switch (child.tagName) {
case 'IMG':
raw = imageBlock(child);
break;
case 'VIDEO':
raw = videoBlock(child);
break;
case 'TABLE':
raw = tableBlock(child);
break;
case 'IFRAME':
raw = iframeBlock(child);
break;
default:
raw = textBlock(el);
break;
}
} else {
raw = textBlock(el);
}
} else {
switch (el.tagName) {
case 'TABLE':
raw = tableBlock(el);
break;
case 'IFRAME':
raw = iframeBlock(el);
break;
default:
raw = textBlock(el);
break;
const children = el.childNodes;
for (const child of children) {
if (elementsWithConverters.includes(child.tagName)) {
el.removeChild(child);
result.push(blockFromElement(child, defaultTextBlock));
}
}
result.push(raw);
result.push(blockFromElement(el, defaultTextBlock));
}
return result;
};
Expand Down
77 changes: 77 additions & 0 deletions src/converters/fromHtml.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,80 @@ describe('convertFromHTML parsing html', () => {
});
});
});

describe('convertFromHTML parsing html with images nested in h2', () => {
const html = `
<div>
<h2 id="chrissy"><img src="https://plone.org/foundation/meetings/membership/2019-membership-meeting/nominations/img4_08594.jpg/@@images/7a07f0e5-0fd7-4366-a32d-6b033c8dfce7.jpeg" title="Chrissy Wainwright 2019" alt="Chrissy Wainwright 2019" class="image-right">Chrissy Wainwright</h2>
<p><strong>President</strong>, (Springdale, Arkansas, USA)</p>
<p>Chrissy started at Six Feet Up as a front-end developer building Plone themes and has since moved to the back-end doing Python development and Plone migrations. She has given talks and training classes at many Plone Symposia and Conferences. This is her seventh term on the board, second as President.</p>
<hr>
<h2 id="erico"><img src="https://plone.org/foundation/board/github.jpg/@@images/1135c449-bf22-4011-b128-ab50c62e03b1.jpeg" title="ericof" alt="ericof" class="image-right">Érico Andrei</h2>
<p><strong>Vice President</strong>, (Berlin, DE)</p>
<p>Érico Andrei worked for more than 10 years with content management projects using Plone. During that period he co-founded Simples Consultoria, hosted 2 Plone Symposiums, co-organized a Plone Conference and in 2011 he was PythonBrasil (local Pycon) chair. Currently CTO for a German startup. He still uses Plone and Python every day. This is Érico's sixth term on the board.</p>
<hr>
</div>
`;

describe('with draftjs converter', () => {
const result = convertFromHTML(html, 'draftjs');

test('will return an array of blocks', () => {
expect(result).toHaveLength(10);
});

test('will have a first block with an image', () => {
const block = result[0];
expect(block['@type']).toBe('image');
expect(block['align']).toBe('right');
expect(block['alt']).toBe('Chrissy Wainwright 2019');
expect(block['title']).toBe('Chrissy Wainwright 2019');
expect(block['size']).toBe('m');
expect(block['url']).toBe(
'https://plone.org/foundation/meetings/membership/2019-membership-meeting/nominations/img4_08594.jpg',
);
});

test('will have a second block with text content', () => {
const block = result[1];
expect(block['@type']).toBe('text');
const valueElement = block.text;
expect(valueElement.blocks).toHaveLength(1);
const firstBlock = valueElement.blocks[0];
expect(firstBlock['text']).toContain('Chrissy Wainwright');
expect(firstBlock['type']).toBe('header-two');
expect(firstBlock['depth']).toBe(0);
});
});

describe('with slate converter', () => {
const result = convertFromHTML(html, 'slate');

test('will return an array of blocks', () => {
expect(result).toHaveLength(10);
});

test('will have a first block with an image', () => {
const block = result[0];
expect(block['@type']).toBe('image');
expect(block['align']).toBe('right');
expect(block['alt']).toBe('Chrissy Wainwright 2019');
expect(block['title']).toBe('Chrissy Wainwright 2019');
expect(block['size']).toBe('m');
expect(block['url']).toBe(
'https://plone.org/foundation/meetings/membership/2019-membership-meeting/nominations/img4_08594.jpg',
);
});

test('will have a second block with text content', () => {
const block = result[1];
expect(block['@type']).toBe('slate');
expect(block.plaintext).toContain('Chrissy Wainwright');
const valueElement = block.value[0];
expect(valueElement['type']).toBe('h2');
expect(valueElement['children'][0]['text']).toContain(
'Chrissy Wainwright',
);
});
});
});
1 change: 0 additions & 1 deletion src/converters/slate.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ const htmlTagsToSlate = {
};

const deserialize = (el) => {
// console.log('des:', el.nodeType, el);
if (el.nodeType === COMMENT) {
return null;
} else if (el.nodeType === TEXT_NODE) {
Expand Down
13 changes: 11 additions & 2 deletions src/converters/slate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,23 @@ describe('slateTextBlock processing a H1', () => {
});

describe('slateTextBlock processing a h2', () => {
const elem = elementFromString('<h2>Hello world!</h2>');

test('will have a nested structure in the value', () => {
const elem = elementFromString('<h2>Hello world!</h2>');
const result = slateTextBlock(elem);
const valueElement = result.value[0];
expect(valueElement['type']).toBe('h2');
expect(valueElement['children'][0]['text']).toBe('Hello world!');
});

test('will ignore img element in the structure', () => {
const elem = elementFromString(
'<h2 id="chrissy"><img src="https://plone.org/foundation/meetings/membership/2019-membership-meeting/nominations/img4_08594.jpg/@@images/7a07f0e5-0fd7-4366-a32d-6b033c8dfce7.jpeg" title="Chrissy Wainwright 2019" alt="Chrissy Wainwright 2019" class="image-right">Chrissy Wainwright</h2>',
);
const result = slateTextBlock(elem);
const valueElement = result.value[0];
expect(valueElement['type']).toBe('h2');
expect(valueElement['children'][0]['text']).toBe('Chrissy Wainwright');
});
});

describe('slateTextBlock processing a b', () => {
Expand Down

0 comments on commit fa5394d

Please sign in to comment.