问题
The problem:
I'm trying to create an edit interface for contents created with draft-js
+ draft-js-mention-plugin
. However, editorState
wasn't persisted, only plain text. Mentions were saved as an array of objects. Now I need to recreate the editorState with that data.
Example:
I have a plain text like this:
const content = '@marcello we need to add spell check'
And a mentions
array with objects like this:
const mentions = [{
length: 8,
offset: 0,
user: 'user:59441f5c37b1e209c300547d',
}]
To create the editorState with the plain text I'm using these lines:
const contentState = ContentState.createFromText(content)
EditorState.createWithContent(contentState)
That works well. The plain text is set as initial state, but without mentions.
Now I need a way to add mentions based on mentions
objects.
I'm trying to read the library code to figure it out, but without success so far.
回答1:
How i "hacked" my solution for it:
// Imports
import { EditorState,convertToRaw, ContentState, convertFromRaw, genKey, ContentBlock } from 'draft-js';
// Init some kind of block with a mention
let exampleState = {
blocks: [
{
key: genKey(), //Use the genKey function from draft
text: 'Some text with mention',
type: 'unstyled',
inlineStyleRanges: [],
data: {},
depth: 0,
entityRanges: [
{ offset: 15, length: 7, key: 0 }
]
}
],
entityMap: [
"0": {
"type": "mention",
"mutability": "SEGMENTED",
"data": {
"mention": {
"name": "<name>",
"link": "<link>",
"avatar": "<avatar-url>"
}
}
}
]
};
this.state.editorState = EditorState.createWithContent(convertFromRaw(exampleState));
Here you can can create some function to input your text and output a entityRange return a offset/length of the mention and replace the "entityRanges" array with your highlighted stuff!
In this example the word "mention" would get highlighted with whatever styling your using with the mention plugin
Sidenote:
You could use the ContentBlock class from draft or create your own implementation to make this more pretty
回答2:
This is the solution I managed to put up for adding a mention (#) (with entityMap, to a new block at the end of state). It can be retreived as a mention and so on... Of course that can be simplified, but it works as expected for me.
// import {....} from 'draft-js';
import Immutable, {List, Repeat} from 'immutable' ;
const addMentionLast = (editorState, mentionData) => {
if(!mentionData.id) return;
// debugger;
const contentState = editorState.getCurrentContent();
const oldBlockMap = contentState.getBlockMap();
const lastKey = lastNonEmptyKey(contentState);
const charData = CharacterMetadata.create();
//new state with mention
const selection = editorState.getSelection();
const entityKey = Entity.create('#mention', 'SEGMENTED', {"mention":{...mentionData }} );
//add text
const textWithEntity = Modifier.insertText(contentState, selection , `#${mentionData.name}` , null, entityKey);
const _editorState = EditorState.push(editorState, textWithEntity , 'insert-characters');
//create new block
const _newBlock = new ContentBlock({
key: genKey(),
type: 'unstyled',
depth: 0,
text: mentionData.name,
characterList: List(Repeat(charData, mentionData.name.length)),
});
//set the entity
const __newBlock = applyEntityToContentBlock(_newBlock,0, mentionData.name.length, entityKey)
//set new block in order..
const blocksMap =
Immutable.OrderedMap().withMutations(map => {
if (lastKey) {
//after the last non empty:
for (let [k, v] of oldBlockMap.entries()) {
map.set(k, v);
if (lastKey === k) {
map.set(k, v);
map.set(__newBlock.key, __newBlock);
}
}
}
else {
// first line:
map.set(__newBlock.key, __newBlock);
}
});
return EditorState.push(
_editorState,
ContentState
.createFromBlockArray(Array.from(blocksMap.values()))
.set('selectionBefore', contentState.getSelectionBefore())
.set('selectionAfter', contentState.getSelectionAfter())
)
}
function lastNonEmptyKey (content){
const lastNonEmpty = content.getBlockMap().reverse().skipUntil((block, _) => block.getLength()).first();
if (lastNonEmpty) return lastNonEmpty.getKey();
}
Thanks to all for sharing!
来源:https://stackoverflow.com/questions/47316926/how-to-programatically-add-mentions-using-draft-js-mention-plugin