Open neove opened 7 years ago
thank u , maybe I didn't make myself clear. the link example here need to have the select range , but in my case , i just want to insert a link at the cursor position rather than operate the select range, i am really confused about this , thank u @mzbac
@neove in this case, I would just insert a new custom content block and make that custom block to display as inline block..
@neove I'm doing something very similar to you and I was wondering if you got this to work?
Hey @neove I had this exactly same question starting out with draft js last week :) I searched and searched and couldn't find an example of this thing that I thought might be a basic and common use case for draft js. I came up with a solution after scouring the issues and docs ;) So I'm posting it here as a contained example of clicking a button that creates an Entity at the cursor position. (And hopefully creating some SEO juice) The magic happens in the insertPlaceholder
function. Since you want to insert the Entity at the cursor position the selection
is collapsed. You want to use Modifier.insertText
(see the docs for details). In my case I want an IMMUTABLE Entity that I can style however I want. The CompositeDecorator is needed to provide a function to find PLACEHOLDER Entities and render a Placeholder component.
const React = require('react');
const {Editor, EditorState, convertToRaw, convertFromRaw, Entity, Modifier, CompositeDecorator} = require('draft-js');
const rawContent = {
blocks: [
{
text: 'Hey First name',
type: 'unstyled',
entityRanges: [{key: 'first', length: 10, offset: 4}]
},
{
text: '',
type: 'unstyled',
},
{
text: 'Placeholders can be inserted at the cursor position by clicking that button up there.',
type: 'unstyled',
},
],
entityMap: {
first: {
type: 'PLACEHOLDER',
mutability: 'IMMUTABLE',
data: {
content: 'firstName', // can be whatever
},
},
},
};
const styles = {
editor: {
border: '1px solid gray',
minHeight: 300,
cursor: 'text',
},
placeholder: {
display: 'inline-block',
background: 'lightBlue',
padding: '0 10px',
borderRadius: 99
},
};
const Placeholder = props => (
<span {...props} style={styles.placeholder}>
{props.children}
</span>
);
const decorator = new CompositeDecorator([{
strategy: findPlaceholders,
component: Placeholder,
}]);
function findPlaceholders(contentBlock, callback) {
contentBlock.findEntityRanges((character) => {
const entityKey = character.getEntity();
return (
entityKey !== null &&
Entity.get(entityKey).getType() === 'PLACEHOLDER'
);
}, callback);
}
module.exports = React.createClass({
getInitialState() {
return {
editorState: EditorState.createWithContent(convertFromRaw(rawContent), decorator)
}
},
onChange(editorState) {
this.setState({editorState})
},
logState() {
const content = this.state.editorState.getCurrentContent();
console.log(convertToRaw(content));
},
insertPlaceholder(label, meta) {
const editorState = this.state.editorState;
const currentContent = editorState.getCurrentContent();
const selection = editorState.getSelection();
const entityKey = Entity.create('PLACEHOLDER', 'IMMUTABLE', {meta});
const textWithEntity = Modifier.insertText(currentContent, selection, label, null, entityKey);
this.setState({
editorState: EditorState.push(editorState, textWithEntity, 'insert-characters')
}, () => {
this.focus();
});
},
focus() {
this.refs.editor.focus();
},
render() {
return (
<div>
<button type="button" onClick={this.insertPlaceholder.bind(null, 'Some thing', 'Some thing about some thing')}>
Some thing
</button>
<div style={styles.editor} onClick={this.focus}>
<Editor editorState={this.state.editorState}
ref="editor"
onChange={this.onChange} />
</div>
<button type="button" onClick={this.logState}>Log</button>
</div>
);
}
});
I left some basic functionality I've seen in draft js editor examples like handling focus and logging state and initializing editorState with converted raw content and a decorator. I hope this helps you or someone else out 👍 I'd appreciate suggestions and feedback anyone has for better ways of working with entities and decorators in this way.
Does anybody make it works?
There are two ways in my mind:
This will insert mention to current editor, very similar with the answer @rblakejohnson
const currentContent = editorState.getCurrentContent(); const selection = editorState.getSelection(); const entityKey = Entity.create('MENTION', 'IMMUTABLE', {"text":'apple',"value":'apple',"url":'apple'}); const textWithEntity = Modifier.insertText(currentContent, selection, '@APPLE', null, entityKey); this.setState({ editorState: EditorState.push(editorState, textWithEntity, 'insert-characters') });
There is one function called addEntityToContentState. But I have not tried it yet https://github.com/facebook/draft-js/blob/master/src/model/transaction/addEntityToContentState.js
@openzig THANK YOUU, I searched the whole web for your answer!!!!
@openzig This works great however it does not work when there is a range selection, instead of just a cursor. Using replaceText instead of insertText fixes the problem
const editorState = this.state.editorState;
const currentContent = editorState.getCurrentContent();
const selection = editorState.getSelection();
const entityKey = Entity.create('PLACEHOLDER', 'IMMUTABLE', {meta});
const textWithEntity = Modifier.replaceText(currentContent, selection, label, null, entityKey);
@openzig Hi, I've come into that the previously applied styles to the text will be cleared with such solution (such as, bold / italic / font-size / etc.). Is there any way to keep it?
When i use Draf.js , I want to create a new Entity and insert it at the cursor pointer , for example : just create a link entity and inset it . I try to use the Modify. applyEntity , but in my case, there is no selectee range , i wanner which API I should user here , thank you for example: when i click the submit button, i will insert some text 'click me for infomation' and it's url is 'www.google.com'