Perhaps I just missed it, but is there any way to truncate the current ContentState while keeping its rich styles ? I'd like to render a preview of the content, say 100 characters but I can't find anywhere how to do so.
Thanks a lot 馃檹
@antoinerey my solution is covert to rawContentState then modify blocks after that covert it back to editorState.. feels that's not ideal.. but it works on my project
That's what I'm doing too at the moment, but I have the impression that I'm fighting against the system.
@antoinerey - I apologize for the late response, could you explain your use case more? Is it that you want to render the entire Editor component, but only show the first 100 characters, but then you could hit like a "See More" button and it would expand to show everything? will you have multiple instances of this on the page?
@davidchang No problem 馃憤 What I'm trying to accomplish is a preview system, pretty much like a "Read more" button.
So, what I'm doing at the moment is :
... at the end of the previewBut I'm pretty much fighting against the system here since I have to add character metadata to be sure ... is displayed, remove the inline styles of unused text...
I could probably go for a max-height container, but how would I display an ellipsis at the end ?
I wrote a simple function to truncate it.
truncate(editorState, charCount) {
const contentState = editorState.getCurrentContent();
const blocks = contentState.getBlockMap();
let count = 0;
let isTruncated = false;
const truncatedBlocks = [];
blocks.forEach((block) => {
if (!isTruncated) {
const length = block.getLength();
if (count + length > charCount) {
isTruncated = true;
const truncatedText = block.getText().slice(0, charCount - count);
const state = ContentState.createFromText(`${truncatedText}...`);
truncatedBlocks.push(state.getFirstBlock());
} else {
truncatedBlocks.push(block);
}
count += length + 1;
}
});
if (isTruncated) {
const state = ContentState.createFromBlockArray(truncatedBlocks);
return EditorState.createWithContent(state);
}
return editorState;
}
TY for that piece of code @JimLiu it was really useful, I iterated over it and decided to use getBlocksAsArray as the solution you posted will iterate over all of the blocks and in my case I will have multiple instances of this "preview" component, maybe this is a premature optimization, but it was cheap so. Here it is in case it is useful for someone else:
truncate = (editorState, charCount = 200) => {
const contentState = editorState.getCurrentContent();
const blocks = contentState.getBlocksAsArray();
let index = 0;
let currentLength = 0;
let isTruncated = false;
const truncatedBlocks = [];
while (!isTruncated && blocks[index]) {
const block = blocks[index];
const length = block.getLength();
if (currentLength + length > charCount) {
isTruncated = true;
const truncatedText = block
.getText()
.slice(0, charCount - currentLength);
const state = ContentState.createFromText(`${truncatedText}...`);
truncatedBlocks.push(state.getFirstBlock());
} else {
truncatedBlocks.push(block);
}
currentLength += length + 1;
index++;
}
if (isTruncated) {
const state = ContentState.createFromBlockArray(truncatedBlocks);
return EditorState.createWithContent(state);
}
return editorState;
};
@JimLiu @irvingv8 if we use ContentState.createFromText(${truncatedText}...);
It won't show entity thing also. If I want to truncate content but the entity should be there or entity should not truncate.
Here is my method of truncating editor text while preserving the formatting and styles after slightly modifying the solutions proposed by @JimLiu and @irvingv8
truncate = (editorState, charCount = 200) => {
// https://github.com/facebook/draft-js/issues/742
// thanks to JimLiu & irvingv8
let newEditorState = null;
if (editorState && editorState.getCurrentContent) {
const contentState = editorState.getCurrentContent();
const blocks = contentState.getBlocksAsArray();
let index = 0;
let currentLength = 0;
let isTruncated = false;
const truncatedBlocks = [];
let inlineStyleChars = 0;
while (!isTruncated && blocks[index]) {
const block = blocks[index];
const length = block.getLength();
if (currentLength + length > charCount) {
isTruncated = true;
inlineStyleChars = charCount - currentLength;
const characterList = block.getCharacterList().slice(0, inlineStyleChars);
const newBlock = block.set('characterList', characterList);
// .push(
// CharacterMetadata.create({'entity': '.'}),
// CharacterMetadata.create({'entity': '.'}),
// CharacterMetadata.create({'entity': '.'})))
// .set('text', `${block.getText()}...`)
truncatedBlocks.push(newBlock);
} else {
truncatedBlocks.push(block);
}
currentLength += length + 1;
index+=1;
}
if (isTruncated) {
const state = ContentState.createFromBlockArray(truncatedBlocks);
newEditorState = EditorState.createWithContent(state)
} else {
newEditorState = editorState;
}
return [newEditorState, isTruncated];
}
return [newEditorState, false];
};
Note that the commented out sections were my attempts to add the ... characters, but was unsuccessful.
Most helpful comment
I wrote a simple function to truncate it.