Skip to content

Instantly share code, notes, and snippets.

@AhmedKorim
Created September 17, 2019 01:05
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 AhmedKorim/d96cba5b87d3264c6645717b9a6c3ca2 to your computer and use it in GitHub Desktop.
Save AhmedKorim/d96cba5b87d3264c6645717b9a6c3ca2 to your computer and use it in GitHub Desktop.
Entity Editor - Draft.js example
<!--
Source of the code: https://github.com/facebook/draft-js/blob/master/examples/draft-0-10-0/entity/
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Draft • Entity Editor</title>
</head>
<body>
<div id="target"></div>
</body>
</html>
'use strict';
const {
convertFromRaw,
convertToRaw,
CompositeDecorator,
ContentState,
Editor,
EditorState,
} = Draft;
const rawContent = {
blocks: [
{
text: (
'This is an "immutable" entity: Superman. Deleting any ' +
'characters will delete the entire entity. Adding characters ' +
'will remove the entity from the range.'
),
type: 'unstyled',
entityRanges: [{offset: 31, length: 8, key: 'first'}],
},
{
text: '',
type: 'unstyled',
},
{
text: (
'This is a "mutable" entity: Batman. Characters may be added ' +
'and removed.'
),
type: 'unstyled',
entityRanges: [{offset: 28, length: 6, key: 'second'}],
},
{
text: '',
type: 'unstyled',
},
{
text: (
'This is a "segmented" entity: Green Lantern. Deleting any ' +
'characters will delete the current "segment" from the range. ' +
'Adding characters will remove the entire entity from the range.'
),
type: 'unstyled',
entityRanges: [{offset: 30, length: 13, key: 'third'}],
},
],
entityMap: {
first: {
type: 'TOKEN',
mutability: 'IMMUTABLE',
},
second: {
type: 'TOKEN',
mutability: 'MUTABLE',
},
third: {
type: 'TOKEN',
mutability: 'SEGMENTED',
},
},
};
class EntityEditorExample extends React.Component {
constructor(props) {
super(props);
const decorator = new CompositeDecorator([
{
strategy: getEntityStrategy('IMMUTABLE'),
component: TokenSpan,
},
{
strategy: getEntityStrategy('MUTABLE'),
component: TokenSpan,
},
{
strategy: getEntityStrategy('SEGMENTED'),
component: TokenSpan,
},
]);
const blocks = convertFromRaw(rawContent);
this.state = {
editorState: EditorState.createWithContent(blocks, decorator),
};
this.focus = () => this.refs.editor.focus();
this.onChange = (editorState) => this.setState({editorState});
this.logState = () => {
const content = this.state.editorState.getCurrentContent();
console.log(convertToRaw(content));
};
}
render() {
return (
<div style={styles.root}>
<div style={styles.editor} onClick={this.focus}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
placeholder="Enter some text..."
ref="editor"
/>
</div>
<input
onClick={this.logState}
style={styles.button}
type="button"
value="Log State"
/>
</div>
);
}
}
function getEntityStrategy(mutability) {
return function(contentBlock, callback, contentState) {
contentBlock.findEntityRanges(
(character) => {
const entityKey = character.getEntity();
if (entityKey === null) {
return false;
}
return contentState.getEntity(entityKey).getMutability() === mutability;
},
callback
);
};
}
function getDecoratedStyle(mutability) {
switch (mutability) {
case 'IMMUTABLE': return styles.immutable;
case 'MUTABLE': return styles.mutable;
case 'SEGMENTED': return styles.segmented;
default: return null;
}
}
const TokenSpan = (props) => {
const style = getDecoratedStyle(
props.contentState.getEntity(props.entityKey).getMutability()
);
return (
<span data-offset-key={props.offsetkey} style={style}>
{props.children}
</span>
);
};
const styles = {
root: {
fontFamily: '\'Helvetica\', sans-serif',
padding: 20,
width: 600,
},
editor: {
border: '1px solid #ccc',
cursor: 'text',
minHeight: 80,
padding: 10,
},
button: {
marginTop: 10,
textAlign: 'center',
},
immutable: {
backgroundColor: 'rgba(0, 0, 0, 0.2)',
padding: '2px 0',
},
mutable: {
backgroundColor: 'rgba(204, 204, 255, 1.0)',
padding: '2px 0',
},
segmented: {
backgroundColor: 'rgba(248, 222, 126, 1.0)',
padding: '2px 0',
},
};
ReactDOM.render(
<EntityEditorExample />,
document.getElementById('target')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.3/es6-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/draft-js/0.10.0/Draft.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/draft-js/0.10.0/Draft.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment