Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

Commit

Permalink
Fixed a bug causing block data being over-written when pasted.
Browse files Browse the repository at this point in the history
Summary:
there is a bug in Draft JS replace fragment logic where it replaces
block data directly with the fragment's block data. That causes things like
notice block loses it's data when pasted from other blocks.

The diff introduces a new parameter to allow the data on the block to be merged
instead of replaced. That way we could preserve the original data as well as
merging from the fragment's data (if available).

Note that in our use case, old data take precedence - for exmaple, if you paste
from a "note" notice to a "warning" notice, the resulting notice should still be
warning instead of "note".

Differential Revision: D16167295

fbshipit-source-id: 6e525d2263014e0666928077a71d9d406bd68143
  • Loading branch information
Tee Xie authored and facebook-github-bot committed Jul 10, 2019
1 parent 0e88544 commit 82e2135
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/model/modifier/DraftModifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {DraftInlineStyle} from 'DraftInlineStyle';
import type {DraftRemovalDirection} from 'DraftRemovalDirection';
import type SelectionState from 'SelectionState';
import type {Map} from 'immutable';
import type {BlockDataMergeBehavior} from 'insertFragmentIntoContentState';

const CharacterMetadata = require('CharacterMetadata');
const ContentStateInlineStyle = require('ContentStateInlineStyle');
Expand Down Expand Up @@ -118,6 +119,7 @@ const DraftModifier = {
contentState: ContentState,
targetRange: SelectionState,
fragment: BlockMap,
mergeBlockData?: BlockDataMergeBehavior = 'REPLACE_WITH_NEW_DATA',
): ContentState {
const withoutEntities = removeEntitiesAtEdges(contentState, targetRange);
const withoutText = removeRangeFromContentState(
Expand All @@ -129,6 +131,7 @@ const DraftModifier = {
withoutText,
withoutText.getSelectionAfter(),
fragment,
mergeBlockData,
);
},

Expand Down
20 changes: 19 additions & 1 deletion src/model/transaction/insertFragmentIntoContentState.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,36 @@ const randomizeBlockMapKeys = require('randomizeBlockMapKeys');

const {List} = Immutable;

export type BlockDataMergeBehavior =
| 'REPLACE_WITH_NEW_DATA'
| 'MERGE_OLD_DATA_TO_NEW_DATA';

const updateExistingBlock = (
contentState: ContentState,
selectionState: SelectionState,
blockMap: BlockMap,
fragmentBlock: BlockNodeRecord,
targetKey: string,
targetOffset: number,
mergeBlockData?: BlockDataMergeBehavior = 'REPLACE_WITH_NEW_DATA',
): ContentState => {
const targetBlock = blockMap.get(targetKey);
const text = targetBlock.getText();
const chars = targetBlock.getCharacterList();
const finalKey = targetKey;
const finalOffset = targetOffset + fragmentBlock.getText().length;

let data = null;

switch (mergeBlockData) {
case 'MERGE_OLD_DATA_TO_NEW_DATA':
data = fragmentBlock.getData().merge(targetBlock.getData());
break;
case 'REPLACE_WITH_NEW_DATA':
data = fragmentBlock.getData();
break;
}

const newBlock = targetBlock.merge({
text:
text.slice(0, targetOffset) +
Expand All @@ -50,7 +66,7 @@ const updateExistingBlock = (
fragmentBlock.getCharacterList(),
targetOffset,
),
data: fragmentBlock.getData(),
data,
});

return contentState.merge({
Expand Down Expand Up @@ -290,6 +306,7 @@ const insertFragmentIntoContentState = (
contentState: ContentState,
selectionState: SelectionState,
fragmentBlockMap: BlockMap,
mergeBlockData?: BlockDataMergeBehavior = 'REPLACE_WITH_NEW_DATA',
): ContentState => {
invariant(
selectionState.isCollapsed(),
Expand Down Expand Up @@ -320,6 +337,7 @@ const insertFragmentIntoContentState = (
fragment.first(),
targetKey,
targetOffset,
mergeBlockData,
);
}

Expand Down

0 comments on commit 82e2135

Please sign in to comment.