Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

Commit

Permalink
draft-js: clean up useless divs from HTML when pasting content
Browse files Browse the repository at this point in the history
Summary:
When pasting rich (HTML) content into a Draft editor, the generated blocks
are flattened such that they can be represented in the internal state model.
Until a change to the tree-based model is fully implemented, that may cause
formatting to be lost if the content is wrapped in multiple levels of divs,
as the parsing does not traverse them deeply.

Improve the amount of formatting that can be preserved in the current model
by stripping out divs considered 'useless' (with no text or styling), such
that more important elements can be 'brought to the surface' and parsed
in a more pleasant manner.

Reviewed By: claudiopro

Differential Revision: D15923965

fbshipit-source-id: 72824ddba69b5d08374f505187ed4a6ea7c4d573
  • Loading branch information
Daniel Quadros de Miranda authored and facebook-github-bot committed Jun 24, 2019
1 parent ceaeebf commit 0f5427a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2967,6 +2967,71 @@ lorem ipsum
]
`;

exports[`eliminates useless blocks when experimentalTreeDataSupport is disabled 1`] = `false`;

exports[`eliminates useless blocks when experimentalTreeDataSupport is disabled 2`] = `
Array [
Object {
"characterList": Array [
Object {
"entity": null,
"style": Array [],
},
Object {
"entity": null,
"style": Array [],
},
Object {
"entity": null,
"style": Array [],
},
Object {
"entity": null,
"style": Array [],
},
Object {
"entity": null,
"style": Array [],
},
],
"data": Object {},
"depth": 0,
"key": "key2",
"text": "Hello",
"type": "unstyled",
},
Object {
"characterList": Array [
Object {
"entity": null,
"style": Array [],
},
Object {
"entity": null,
"style": Array [],
},
Object {
"entity": null,
"style": Array [],
},
Object {
"entity": null,
"style": Array [],
},
Object {
"entity": null,
"style": Array [],
},
],
"data": Object {},
"depth": 0,
"key": "key3",
"text": "World",
"type": "unstyled",
},
]
`;

exports[`highlighted text should be recognized and considered styled characters 1`] = `
Array [
Immutable.Record {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,22 @@ test('does not convert deeply nested html blocks when experimentalTreeDataSuppor
});
});

test('eliminates useless blocks when experimentalTreeDataSupport is disabled', () => {
const html_string = `
<div>
<div>
<div>Hello</div>
</div>
<div>World</div>
</div>
`;

expect(AreTreeBlockNodesEquivalent(html_string)).toMatchSnapshot();
assertConvertFromHTMLToContentBlocks(html_string, {
experimentalTreeDataSupport: false,
});
});

SUPPORTED_TAGS.forEach(tag =>
testConvertingAdjacentHtmlElementsToContentBlocks(tag, true),
);
Expand Down
27 changes: 23 additions & 4 deletions src/model/encoding/convertFromHTMLToContentBlocks2.js
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,26 @@ class ContentBlocksBuilder {
}
}

/**
* Remove 'useless' container nodes from the block config hierarchy, by
* replacing them with their children.
*/

_hoistContainersInBlockConfigs(
blockConfigs: Array<ContentBlockConfig>,
): List<ContentBlockConfig> {
const hoisted = List(blockConfigs).flatMap(blockConfig => {
// Don't mess with useful blocks
if (blockConfig.type !== 'unstyled' || blockConfig.text !== '') {
return [blockConfig];
}

return this._hoistContainersInBlockConfigs(blockConfig.childConfigs);
});

return hoisted;
}

// ***********************************************************************
// The two methods below are used for backward compatibility when
// experimentalTreeDataSupport is disabled.
Expand All @@ -667,9 +687,8 @@ class ContentBlocksBuilder {
* text content.
*/
_toFlatContentBlocks(blockConfigs: Array<ContentBlockConfig>) {
const l = blockConfigs.length - 1;
for (let i = 0; i <= l; i++) {
const config = blockConfigs[i];
const cleanConfigs = this._hoistContainersInBlockConfigs(blockConfigs);
cleanConfigs.forEach(config => {
const {text, characterList} = this._extractTextFromBlockConfigs(
config.childConfigs,
);
Expand All @@ -680,7 +699,7 @@ class ContentBlocksBuilder {
characterList: config.characterList.concat(characterList),
}),
);
}
});
}

/**
Expand Down

0 comments on commit 0f5427a

Please sign in to comment.