0

I have a Draft.js editor with some HTML in it. How can I insert a new piece of HTML at a current selection position, preserving both stylings and entity/block mappings? I know how to insert raw text via Modifier.insertText:

const contentState = Modifier.insertText(
  editorState.getCurrentContent(),
  editorState.getSelection(),
  insertionText,
  editorState.getCurrentInlineStyle(),
);

but it will strip all the HTML which is not ok.

// Original HTML piece
const { contentBlocks, entityMap } = htmlToDraft(originalHTML);
const contentState = ContentState.createFromBlockArray(
  contentBlocks,
  entityMap,
);
const editorState = EditorState.createWithContent(contentState);

// Additional HTML piece, which I want to insert at the selection (cursor) position of
// previous editor state
const { contentBlocks, entityMap } = htmlToDraft(newHTML);
const newContentState = ContentState.createFromBlockArray(
  contentBlocks,
  entityMap,
);

2 Answers2

0

You should probably use Modifier.replaceWithFragment for this:

A "fragment" is a section of a block map, effectively just an OrderedMap much the same as the full block map of a ContentState object. This method will replace the "target" range with the fragment.

This will work identically to insertText, except that you need to give it a block map as a parameter. It’s not entirely clear from your example what the return value of htmlToDraft is but it should be possible for you to either:

  • Use contentBlocks directly from the return value
  • Or create a contentState as in your example, then use its .getBlockMap() method to get the block map to insert into the editor’s content.
const newContentState = ContentState.createFromBlockArray(
  contentBlocks,
  entityMap,
);
// Use newContentState.getBlockMap()
Thibaud Colas
  • 1,248
  • 1
  • 16
  • 24
0

I could not post it in the comment section (too long of a snippet) but as mentioned earlier Modifier.replaceWithFragment is the way to go, so I made it work like in the snippet below.

*** Make sure you have all other infrastructure in place like blockRendererFn, blockRenderMap, compositeDecorator, etc to actually render all those blocks, inline styles for links, images, etc

import {
    Modifier,
    ContentState,
    convertFromHTML,
} from 'draft-js'

onPaste = (text, html, state) => {
    if (html) {
        const blocks = convertFromHTML(html)
        Modifier.replaceWithFragment(
            this.state.editorState.getCurrentContent(),
            this.state.editorState.getSelection(),
            ContentState.createFromBlockArray(blocks, blocks.entityMap).getBlockMap(),
        )
    }
    return false
}
dehumanizer
  • 1,250
  • 12
  • 15