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

convertFromHTML returns 0 contentBlocks for an empty string or an empty tag #2226

Closed
mstoltenburg opened this issue Oct 24, 2019 · 2 comments

Comments

@mstoltenburg
Copy link

Do you want to request a feature or report a bug?
Report a 🐛

What is the current behavior?
convertFromHTML returns zero contentBlocks for an empty string or an empty tag like <p></p> or <em></em>. When I use that result to create a ContentState with ContentState.createFromBlockArray(), the ContentState can't be used in e.g.EditorState.createWithContent() or ContentState.hasText().

Please provide the steps to reproduce and if possible a minimal demo of the problem.

  1. convert empty tag like e.g. convertFromHTML('<p></p>')
  2. use the result in ContentState.createFromBlockArray()
  3. Try to use that content state in e.g. EditorState.createWithContent(content) or content.hasText()
import { ContentState, convertFromHTML } from 'draft-js';

const { contentBlocks, entityMap } = convertFromHTML('<p></p>');
const content = ContentState.createFromBlockArray(contentBlocks, entityMap);
const hasText = content.hasText();

// throws TypeError: blockMap.first(...) is undefined

https://jsfiddle.net/xygf095s/

What is the expected behavior?
Return a usable ContentState for empty strings or empty tags converted with convertFromHTML or maybe that the blockMap size is equal for ContentState.createFromText and ContentState.createFromBlockArray if I converted an empty string or tag with convertFromHTML.

const emptyString = '':
const { contentBlocks, entityMap } = convertFromHTML(emptyString);
ContentState.createFromText(emptyString).blockMap.size === 1
ContentState.createFromBlockArray(contentBlocks, entityMap).blockMap.size === 0

Which versions of Draft.js, and which browser / OS are affected by this issue? Did this work in previous versions of Draft.js?
draft-js 0.11.1
Chrome 78

@davoscript
Copy link

Hi @mstoltenburg, I was having the same issue, I sent this pull request (#2240) yesterday which fixes the problem in case you want to take a look at it.

@mstoltenburg
Copy link
Author

Very nice. My fix at the moment is quite similar to yours 😃

export function createEditorStateWithContent(html) {
    const content = createContentStateFromHtml(html);

    return content.getBlockMap().size
        ? EditorState.createWithContent(content)
        : EditorState.createEmpty();
}

export function createContentStateFromHtml(html) {
    const { contentBlocks, entityMap } = convertFromHTML(html);

    return ContentState.createFromBlockArray(contentBlocks, entityMap);
}

I'm still not sure if this should be expected behaviour, that using convertFromHTML on e.g. the HTML string <p></p> creates zero blocks at all.

facebook-github-bot pushed a commit that referenced this issue Nov 5, 2019
…(Fixes issue #2226) (#2240)

Summary:
**Summary**

When passing `createWithContent` a `state` parameter created using `convertFromHTML` from an empty string and `createFromBlockArray`, as shown in the example:

```
const sampleMarkup =
  '<b>Bold text</b>, <i>Italic text</i><br/ ><br />' +
  '<a href="http://www.facebook.com">Example link</a><br /><br/ >' +
  '<img src="image.png" height="112" width="200" />';

const blocksFromHTML = convertFromHTML(sampleMarkup);
const state = ContentState.createFromBlockArray(
  blocksFromHTML.contentBlocks,
  blocksFromHTML.entityMap,
);

this.state = {
  editorState: EditorState.createWithContent(
    state,
    decorator,
  ),
};
```

The following error is thrown:

```
TypeError: Cannot read property 'getKey' of undefined

  84 | EditorState.createWithContent = function createWithContent(contentState, decorator) {
> 85 |   var firstKey = contentState.getBlockMap().first().getKey();
     | ^  86 |   return EditorState.create({
  87 |     currentContent: contentState,
  88 |     undoStack: Stack(),
```
The previous error is generated because `createWithContent` asumes that `contentState.getBlockMap().first()` will return an element, which is wrong for scenarios where the block map is empty. As a consecuence the `getKey();` function in `contentState.getBlockMap().first().getKey();` is executed on `undefined`, thus throwing the error.

The previous scenario is very common if you are planning to use the editor to allow a user to write HTML content which could also be blank, especially as a default value.

**Solution**

In order to make the less amount of modifications to the code, I've added a validation that will run `createEmpty` in case the block map is empty.

**Test Plan**

Open `/draft-js/examples/draft-0-10-0/convertFromHTML/convert.html` and change line #61 from:

`const blocksFromHTML = convertFromHTML(sampleMarkup);`

to:

`const blocksFromHTML = convertFromHTML('');`

No error will be shown.
Pull Request resolved: #2240

Differential Revision: D18247644

Pulled By: mrkev

fbshipit-source-id: 3eb90fd5379e8a2d85efbb2b7b9587ca87701d12
@mrkev
Copy link
Contributor

mrkev commented Nov 5, 2019

Merged #2240. Not quite sure when the next release to NPM will be, but it should be soon. The fix will be included there. Thanks to both!

@mrkev mrkev closed this as completed Nov 5, 2019
@mrkev
Copy link
Contributor

mrkev commented Nov 5, 2019

Merged #2240. Not quite sure when the next release to NPM will be, but it should be soon. The fix will be included there. Ty 👍

mmissey pushed a commit to mmissey/draft-js that referenced this issue Mar 24, 2020
…(Fixes issue facebookarchive#2226) (facebookarchive#2240)

Summary:
**Summary**

When passing `createWithContent` a `state` parameter created using `convertFromHTML` from an empty string and `createFromBlockArray`, as shown in the example:

```
const sampleMarkup =
  '<b>Bold text</b>, <i>Italic text</i><br/ ><br />' +
  '<a href="http://www.facebook.com">Example link</a><br /><br/ >' +
  '<img src="image.png" height="112" width="200" />';

const blocksFromHTML = convertFromHTML(sampleMarkup);
const state = ContentState.createFromBlockArray(
  blocksFromHTML.contentBlocks,
  blocksFromHTML.entityMap,
);

this.state = {
  editorState: EditorState.createWithContent(
    state,
    decorator,
  ),
};
```

The following error is thrown:

```
TypeError: Cannot read property 'getKey' of undefined

  84 | EditorState.createWithContent = function createWithContent(contentState, decorator) {
> 85 |   var firstKey = contentState.getBlockMap().first().getKey();
     | ^  86 |   return EditorState.create({
  87 |     currentContent: contentState,
  88 |     undoStack: Stack(),
```
The previous error is generated because `createWithContent` asumes that `contentState.getBlockMap().first()` will return an element, which is wrong for scenarios where the block map is empty. As a consecuence the `getKey();` function in `contentState.getBlockMap().first().getKey();` is executed on `undefined`, thus throwing the error.

The previous scenario is very common if you are planning to use the editor to allow a user to write HTML content which could also be blank, especially as a default value.

**Solution**

In order to make the less amount of modifications to the code, I've added a validation that will run `createEmpty` in case the block map is empty.

**Test Plan**

Open `/draft-js/examples/draft-0-10-0/convertFromHTML/convert.html` and change line facebookarchive#61 from:

`const blocksFromHTML = convertFromHTML(sampleMarkup);`

to:

`const blocksFromHTML = convertFromHTML('');`

No error will be shown.
Pull Request resolved: facebookarchive#2240

Differential Revision: D18247644

Pulled By: mrkev

fbshipit-source-id: 3eb90fd5379e8a2d85efbb2b7b9587ca87701d12
vilemj-Viclick pushed a commit to kontent-ai/draft-js that referenced this issue Jul 16, 2020
…(Fixes issue facebookarchive#2226) (facebookarchive#2240)

Summary:
**Summary**

When passing `createWithContent` a `state` parameter created using `convertFromHTML` from an empty string and `createFromBlockArray`, as shown in the example:

```
const sampleMarkup =
  '<b>Bold text</b>, <i>Italic text</i><br/ ><br />' +
  '<a href="http://www.facebook.com">Example link</a><br /><br/ >' +
  '<img src="image.png" height="112" width="200" />';

const blocksFromHTML = convertFromHTML(sampleMarkup);
const state = ContentState.createFromBlockArray(
  blocksFromHTML.contentBlocks,
  blocksFromHTML.entityMap,
);

this.state = {
  editorState: EditorState.createWithContent(
    state,
    decorator,
  ),
};
```

The following error is thrown:

```
TypeError: Cannot read property 'getKey' of undefined

  84 | EditorState.createWithContent = function createWithContent(contentState, decorator) {
> 85 |   var firstKey = contentState.getBlockMap().first().getKey();
     | ^  86 |   return EditorState.create({
  87 |     currentContent: contentState,
  88 |     undoStack: Stack(),
```
The previous error is generated because `createWithContent` asumes that `contentState.getBlockMap().first()` will return an element, which is wrong for scenarios where the block map is empty. As a consecuence the `getKey();` function in `contentState.getBlockMap().first().getKey();` is executed on `undefined`, thus throwing the error.

The previous scenario is very common if you are planning to use the editor to allow a user to write HTML content which could also be blank, especially as a default value.

**Solution**

In order to make the less amount of modifications to the code, I've added a validation that will run `createEmpty` in case the block map is empty.

**Test Plan**

Open `/draft-js/examples/draft-0-10-0/convertFromHTML/convert.html` and change line facebookarchive#61 from:

`const blocksFromHTML = convertFromHTML(sampleMarkup);`

to:

`const blocksFromHTML = convertFromHTML('');`

No error will be shown.
Pull Request resolved: facebookarchive#2240

Differential Revision: D18247644

Pulled By: mrkev

fbshipit-source-id: 3eb90fd5379e8a2d85efbb2b7b9587ca87701d12
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants