Open N1kto opened 8 years ago
is there any reason why should we copy meta data to split block?
Not to split, but upon split. Yes, I find it needed. Similarly to Entity
data which is kept upon split in both blocks the meta data should be also kept.
In my use case block meta data influences the presence of particular block in editor. So, once I split the block the part of text gets lost since new block created upon split doesn't hold needed meta data. It can be any other appearance-related issues. For example, block text alignment (left | center | right) data can be kept in its meta data, so once you split the text - you expect a new line to be aligned similarly to original block, but it won't.
I have found a workaround to tackle this issue, but it would be great if block data would be kept by default.
this could be related to #718 ?
I have a similar problem where a user can add a tag to a line of text in a list, this tag is stored in block meta-data, but if I move that line to a new line all of that meta-data stays at the first line... example:
- First line text [mock_ui_tag]
now I move my cursor to the first 0 position of that line and press enter to create a new block... now I see:
- [mock_ui_tag]
- First line text
Ideally I want the tag to follow the text. Here's a gif example as well:
Hi @N1kto. I need this for textAlignment functionality. Can you please provide your workaround solution for this issue. I'm thinking of using handleReturn api for this.
@sudkumar please see below. It's in CoffeScript, but I don't think is it a problem. Please note that I wrote it a good while ago, DraftJS APIs it uses might have changed since then.
splitBlock: (editorState) ->
newContent = Modifier.splitBlock editorState.getCurrentContent(), editorState.getSelection()
originalBlockData = newContent.blockMap.get(newContent.selectionBefore.getStartKey()).getData()
newBlockKey = newContent.selectionAfter.getStartKey()
newBlockMap = newContent.blockMap.update newBlockKey, (contentBlock) ->
contentBlock.set 'data', originalBlockData
EditorState.push editorState, newContent.set('blockMap', newBlockMap), 'split-block'
Thanks @N1kto! I was able to modify your response to suit my problem demonstrated in the gif a couple replies up ^
I REALLY wish this was supported out of the box with a param in draft preserveBlockDataOnSplit
or something, but for now this workaround should keep me moving. It's a bit verbose, but if anyone has similar block "tagging" functionality in your UI this should work as well
handleReturn() {
const { editorState } = this.state;
const contentState = editorState.getCurrentContent();
const selectionState = editorState.getSelection();
let newContent = Modifier.splitBlock(contentState, selectionState);
const originalBlock = contentState.blockMap.get(newContent.selectionBefore.getStartKey());
const originalBlockData = originalBlock.getData();
const preserveDataOnSplit = originalBlockData.size
&& selectionState.getFocusOffset() === 0;
/**
/* If the user is trying to bump a block down a row that _has_ data (like
/* attributions) we need to manually transfer that data along with the
/* block split. This code can maybe be eventually deleted if draft decides to
/* support this use case out of the box.
*/
if (preserveDataOnSplit) {
const newBlockKey = newContent.selectionAfter.getStartKey();
// clear data out of the current block we're moving down
newContent = Modifier.setBlockData(newContent, selectionState, {});
// create the new block and transfer data from the current block
const newBlockMap = newContent.blockMap.update(newBlockKey, contentBlock =>
contentBlock.set('data', originalBlockData));
newContent = newContent.set('blockMap', newBlockMap);
// note: handleChange and getNewEditorState are just my helper methods
this.handleChange(getNewEditorState({
editorState,
contentState: newContent,
}));
/**
/* now that the block is split and the data has been transfered
/* we need to force the cursor one block down. Unfortunately it looks
/* as though there is a limitation in editorState where we have to do
/* this as a subsequent change
*/
const newSelection = new SelectionState({
anchorKey: newBlockKey,
anchorOffset: 0,
focusKey: newBlockKey,
focusOffset: 0,
});
setTimeout(() => {
this.setState({
editorState: EditorState.forceSelection(this.state.editorState, newSelection),
});
}, 1);
return 'handled';
}
return 'not-handled';
}
Thanks you @N1kto . That helped. I only wanted to pass-on the styles which I stored in blockData.style
.
I did following.
handleReturn = (e, editorState) => {
const selection = editorState.getSelection()
if (selection.isCollapsed()) {
const contentState = editorState.getCurrentContent()
const startKey = selection.getStartKey()
const currentBlock = contentState.getBlockForKey(startKey)
if (currentBlock) {
const blockData = currentBlock.getData()
const blockStyles = blockData.get("style")
if (blockStyles) {
// Original split logic
const newContentState = Modifier.splitBlock(
editorState.getCurrentContent(),
editorState.getSelection()
)
let splitState = EditorState.push(editorState, newContentState, "split-block")
const target = splitState.getSelection()
const afterMergeStylesContentState = Modifier.mergeBlockData(
splitState.getCurrentContent(),
target,
{
style: blockStyles
}
)
splitState = EditorState.push(editorState, afterMergeStylesContentState, "split-block")
this.updateState(splitState)
return "handled"
}
}
}
return "not-handled"
}
I had to do something similar, but in my case, instead of copying over the data from the previous block, I had to assign new metadata to the newly split block.
const { editorState } = this.state;
const selection = editorState.getSelection();
let contentState = editorState.getCurrentContent();
contentState = Modifier.splitBlock(contentState, selection);
const nextBlockKey = contentState.selectionAfter.getStartKey();
const nextBlockEmptySelection = new SelectionState({
anchorKey: nextBlockKey,
anchorOffset: 0,
focusKey: nextBlockKey,
focusOffset: 0
});
contentState = Modifier.setBlockData(
contentState,
nextBlockEmptySelection,
Map()
.set("createdTime", Date.now())
.set("creator", "Punit Jajodia")
);
const newEditorState = EditorState.set(editorState, {
currentContent: contentState
});
Do you want to request a feature or report a bug? Bug What is the current behavior? When splitting a
ContentBlock
itsdata
prop is not copied to a newContentBlock
. If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. You can use this jsfiddle to get started: https://jsfiddle.net/stopachka/m6z0xn4r/. Create a custom block with some block data. Then split it withenter
key. Inspect the new block - itsdata
prop is empty. What is the expected behavior? Data content from original block should be copied to new block. Same is done withEntity
data. Which versions of Draft.js, and which browser / OS are affected by this issue? Did this work in previous versions of Draft.js? Draft version 0.9.1. It doesn't depend on browser / OS. I think it has always been so, especially taking into account that blockdata
prop is relatively a new feature.