Skip to content

Instantly share code, notes, and snippets.

@MattSegal
Created May 11, 2018 00:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MattSegal/b7e736981bf306517c3d94b39b96a025 to your computer and use it in GitHub Desktop.
Save MattSegal/b7e736981bf306517c3d94b39b96a025 to your computer and use it in GitHub Desktop.
Draftail atomic block state change
import { Component } from 'react';
const { AtomicBlockUtils, EditorState, SelectionState, Modifier } = window.DraftJS
// The source gathers data for new entities that are being added in the Draftail editor
// It is invoked only when an new embed is inserted by the user
export class TextSource extends Component {
componentDidMount() {
const { editorState, entityType, onComplete } = this.props;
const content = editorState.getCurrentContent();
const contentWithEntity = content.createEntity(entityType.type, 'MUTABLE', {
text: '',
});
const entityKey = contentWithEntity.getLastCreatedEntityKey();
const nextState = AtomicBlockUtils.insertAtomicBlock(editorState, entityKey, ' ');
onComplete(nextState);
}
render() {
return null;
}
}
// The block is used to render the entity in the editor
// It may receive props:
// * from the source component when first created
// * from the server side when reloaded from the database
export class TextBlock extends Component {
constructor(props) {
super(props)
const data = props.blockProps.entity.getData()
this.state = {
text: data.text,
}
}
handleTextChange = e => {
const { text } = this.state
this.setState({
text: e.target.value
})
}
saveText = e => {
// Update editor ContentState
const { block, blockProps } = this.props
const { editorState, onChange } = blockProps
onChange(updateBlockEntity(editorState, block, {
text: this.state.text,
}))
}
render() {
const data = this.props.blockProps.entity.getData()
const { text } = this.state
return (
<div>
<p>Saved text is "{ data.text }"</p>
<input
name="title"
type="text"
onChange={this.handleTextChange}
value={text}
/>
<button onClick={this.saveText}>Submit</button>
</div>
)
}
}
// Update a block's data in the WYSIWYG editor, nicked from DraftUtils source code
const updateBlockEntity = (editorState, block, data) => {
const content = editorState.getCurrentContent();
let nextContent = content.mergeEntityData(block.getEntityAt(0), data);
nextContent = Modifier.mergeBlockData(
nextContent,
new SelectionState({
anchorKey: block.getKey(),
anchorOffset: 0,
focusKey: block.getKey(),
focusOffset: block.getLength(),
}),
{},
);
return EditorState.push(editorState, nextContent, 'apply-entity');
}
@thibaudcolas
Copy link

import { Component } from 'react';

This likely means you're loading React from your own build instead of from the version loaded with Wagtail – this could cause issues.


For updateBlockEntity, if I were you I'd copy the full source with the relevant comment:

        // To remove in Draft.js 0.11.
        // This is necessary because entity data is still using a mutable, global store.
        nextContent = Modifier.mergeBlockData(
            nextContent,
            new SelectionState({
                anchorKey: block.getKey(),
                anchorOffset: 0,
                focusKey: block.getKey(),
                focusOffset: block.getLength(),
            }),
            {},
        );

All of this code will be completely useless in the next version of Draft.js.

Also – in Wagtail 2.1 you'll be able to get this directly (wagtail/wagtail#4467) as window.Draftail.DraftUtils.updateBlockEntity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment