From 40b54d0a30272d0a7af5f4c8368cf5138c3867f3 Mon Sep 17 00:00:00 2001 From: renrizzolo Date: Tue, 14 Mar 2023 15:14:37 +1100 Subject: [PATCH] fix: rich text truncation --- src/components/RichTextEditor/index.jsx | 57 ++++++++++---------- src/components/RichTextEditor/index.spec.jsx | 6 +++ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/components/RichTextEditor/index.jsx b/src/components/RichTextEditor/index.jsx index ed8005e42..de37f0370 100644 --- a/src/components/RichTextEditor/index.jsx +++ b/src/components/RichTextEditor/index.jsx @@ -16,7 +16,7 @@ import FilePreviewList from './FilePreviewList'; import Popover from '../Popover'; import './styles.css'; -const { Modifier, EditorState, convertToRaw, RichUtils, SelectionState } = draftJs; +const { Modifier, EditorState, ContentState, convertToRaw, RichUtils, SelectionState } = draftJs; const editorStateToHTML = (input) => stateToHTML(input.getCurrentContent()); const editorStateFromHTML = (input, options = {}) => @@ -265,46 +265,43 @@ RichTextEditor.useTruncateState = ({ editorState, briefCharCount, truncateString const contentState = editorState.getCurrentContent(); const blocks = contentState.getBlocksAsArray(); - const lastBlock = contentState.getLastBlock(); - let anchor = lastBlock; - let anchorOffset = 0; let acc = 0; - - // get the anchor offset and start block of the text to be removed - for (let i = 0; i < blocks.length; i++) { - const curr = blocks[i]; - if (curr.getLength() + acc >= briefCharCount) { - anchor = curr; - const offset = curr.getLength() + acc - briefCharCount; - anchorOffset = offset === 0 ? curr.getLength() : -offset; + let anchorOffset = 0; + let truncatedBlockIndex = 0; + + // get the block index and string offset of the text to be truncated + for (const [i, block] of blocks.entries()) { + if (block.getLength() + acc >= briefCharCount) { + truncatedBlockIndex = i; + const offset = block.getLength() + acc - briefCharCount; + anchorOffset = block.getLength() - offset; break; } - acc += curr.getLength(); + acc += block.getLength(); } - // select from anchor offset to end of last block - const targetRange = new SelectionState({ - anchorKey: anchor.getKey(), - anchorOffset, - focusKey: lastBlock.getKey(), - focusOffset: lastBlock.getLength(), - }); + let truncatedBlocks = [...blocks].slice(0, truncatedBlockIndex + 1); - const replaced = Modifier.removeRange(contentState, targetRange, 'forward'); + // replace the block's text with the truncated text + truncatedBlocks[truncatedBlockIndex] = truncatedBlocks[truncatedBlockIndex].set( + 'text', + truncatedBlocks[truncatedBlockIndex].getText().substring(0, anchorOffset) + ); - // insert truncateString at end - if (truncateString) { - const end = replaced.getLastBlock(); - const newSelection = SelectionState.createEmpty(anchor.getKey()) - .set('anchorOffset', end.getLength()) - .set('focusOffset', end.getLength()); + let newState = ContentState.createFromBlockArray(truncatedBlocks); - const withTruncateString = Modifier.insertText(replaced, newSelection, truncateString, null); + if (truncateString) { + // selection at last character + const endSelection = SelectionState.createEmpty(truncatedBlocks[truncatedBlockIndex].getKey()) + .set('anchorOffset', truncatedBlocks[truncatedBlockIndex].getLength()) + .set('focusOffset', truncatedBlocks[truncatedBlockIndex].getLength()); - return EditorState.push(editorState, withTruncateString, 'remove-range'); + // insert truncate string after the last character + newState = Modifier.insertText(newState, endSelection, truncateString); } - return EditorState.push(editorState, replaced, 'remove-range'); + + return EditorState.createWithContent(newState); }, [briefCharCount, editorState, totalCharCount, truncateString]); return { diff --git a/src/components/RichTextEditor/index.spec.jsx b/src/components/RichTextEditor/index.spec.jsx index cc82c2c7f..136d88d62 100644 --- a/src/components/RichTextEditor/index.spec.jsx +++ b/src/components/RichTextEditor/index.spec.jsx @@ -468,5 +468,11 @@ describe('', () => { const { getByTestId } = render(); expect(getByTestId('test').innerHTML).toEqual(`

abcdefghijklmnop...

`); }); + it('should retain inline styles', () => { + const { getByTestId } = render( + + ); + expect(getByTestId('test').innerHTML).toEqual(`

abcdefghijklmnop...

`); + }); }); });