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

Commit

Permalink
make encodeRawBlocks support non-contiguous entities
Browse files Browse the repository at this point in the history
Summary: `encodeRawBlocks` was improperly incrementing `entityStorageKey` when processing non-contiguous entities. This caused all entities after the non-contiguous one to have incorrect keys.

Reviewed By: sophiebits

Differential Revision: D6667822

fbshipit-source-id: 6222ea844893ab75aad8171224d01ad893ecf44f
  • Loading branch information
Frank Thompson authored and facebook-github-bot committed Jan 9, 2018
1 parent 232791a commit 0059dd4
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,90 @@ Object {
"entityMap": Object {},
}
`;

exports[`must be able to convert from draft state with noncontiguous entities to raw 1`] = `
Object {
"blocks": Array [
Object {
"data": Object {},
"depth": 0,
"entityRanges": Array [
Object {
"key": 0,
"length": 5,
"offset": 0,
},
Object {
"key": 0,
"length": 5,
"offset": 6,
},
Object {
"key": 1,
"length": 5,
"offset": 12,
},
],
"inlineStyleRanges": Array [],
"key": "a",
"text": "link2 link2 link3",
"type": "unstyled",
},
Object {
"data": Object {},
"depth": 0,
"entityRanges": Array [
Object {
"key": 2,
"length": 5,
"offset": 0,
},
Object {
"key": 0,
"length": 5,
"offset": 6,
},
Object {
"key": 3,
"length": 5,
"offset": 12,
},
],
"inlineStyleRanges": Array [],
"key": "b",
"text": "link4 link2 link5",
"type": "unstyled",
},
],
"entityMap": Object {
"0": Object {
"data": Object {
"url": "www.2.com",
},
"mutability": "IMMUTABLE",
"type": "LINK",
},
"1": Object {
"data": Object {
"url": "www.3.com",
},
"mutability": "IMMUTABLE",
"type": "LINK",
},
"2": Object {
"data": Object {
"url": "www.4.com",
},
"mutability": "IMMUTABLE",
"type": "LINK",
},
"3": Object {
"data": Object {
"url": "www.5.com",
},
"mutability": "IMMUTABLE",
"type": "LINK",
},
},
}
`;
51 changes: 51 additions & 0 deletions src/model/encoding/__tests__/convertFromDraftStateToRaw-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
jest.disableAutomock();

const BlockMapBuilder = require('BlockMapBuilder');
const CharacterMetadata = require('CharacterMetadata');
const ContentBlock = require('ContentBlock');
const ContentBlockNode = require('ContentBlockNode');
const ContentState = require('ContentState');
const DraftEntityInstance = require('DraftEntityInstance');
const Immutable = require('immutable');

const convertFromDraftStateToRaw = require('convertFromDraftStateToRaw');
Expand Down Expand Up @@ -59,6 +63,49 @@ const treeContentState = contentState.set(
]),
);

const getMetadata = entityKey =>
Immutable.Repeat(CharacterMetadata.create({entity: entityKey}), 5);
const getLink = entityKey =>
new DraftEntityInstance({
type: 'LINK',
mutabiltity: 'MUTABLE',
data: {
url: `www.${entityKey}.com`,
},
});
// We start numbering our entities with '2' because getSampleStateForTesting
// already created an entity with key '1'.
const contentStateWithNonContiguousEntities = ContentState.createFromBlockArray(
[
new ContentBlock({
key: 'a',
type: 'unstyled',
text: 'link2 link2 link3',
characterList: getMetadata('2')
.toList()
.push(CharacterMetadata.EMPTY)
.concat(getMetadata('2'))
.push(CharacterMetadata.EMPTY)
.concat(getMetadata('3')),
}),
new ContentBlock({
key: 'b',
type: 'unstyled',
text: 'link4 link2 link5',
characterList: getMetadata('4')
.toList()
.push(CharacterMetadata.EMPTY)
.concat(getMetadata('2'))
.push(CharacterMetadata.EMPTY)
.concat(getMetadata('5')),
}),
],
)
.addEntity(getLink('2'))
.addEntity(getLink('3'))
.addEntity(getLink('4'))
.addEntity(getLink('5'));

const assertConvertFromDraftStateToRaw = content => {
expect(convertFromDraftStateToRaw(content)).toMatchSnapshot();
};
Expand All @@ -70,3 +117,7 @@ test('must be able to convert from draft state with ContentBlock to raw', () =>
test('must be able to convert from draft state with ContentBlockNode to raw', () => {
assertConvertFromDraftStateToRaw(treeContentState);
});

test('must be able to convert from draft state with noncontiguous entities to raw', () => {
assertConvertFromDraftStateToRaw(contentStateWithNonContiguousEntities);
});
46 changes: 17 additions & 29 deletions src/model/encoding/convertFromDraftStateToRaw.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,28 +65,6 @@ const insertRawBlock = (
rawBlocks.push(rawBlock);
};

const insertRawEntity = (
entityStorageKey: number,
entityKey: mixed,
entityMap: *,
entityCacheRef: *,
) => {
// Stringify to maintain order of otherwise numeric keys.
const stringifiedEntityKey = DraftStringKey.stringify(entityKey);

if (entityCacheRef[stringifiedEntityKey]) {
return;
}

entityCacheRef[stringifiedEntityKey] = entityKey;

// we need the `any` casting here since this is a temporary state
// where we will later on flip the entity map and populate it with
// real entity, at this stage we just need to map back the entity
// key used by the BlockNode
entityMap[stringifiedEntityKey] = (`${entityStorageKey}`: any);
};

const encodeRawBlocks = (
contentState: ContentState,
rawState: RawDraftContentState,
Expand All @@ -102,13 +80,23 @@ const encodeRawBlocks = (
contentState.getBlockMap().forEach(block => {
block.findEntityRanges(
character => character.getEntity() !== null,
start =>
insertRawEntity(
entityStorageKey++,
block.getEntityAt(start),
entityMap,
entityCacheRef,
),
start => {
const entityKey = block.getEntityAt(start);
// Stringify to maintain order of otherwise numeric keys.
const stringifiedEntityKey = DraftStringKey.stringify(entityKey);
// This makes this function resilient to two entities
// erroneously having the same key
if (entityCacheRef[stringifiedEntityKey]) {
return;
}
entityCacheRef[stringifiedEntityKey] = entityKey;
// we need the `any` casting here since this is a temporary state
// where we will later on flip the entity map and populate it with
// real entity, at this stage we just need to map back the entity
// key used by the BlockNode
entityMap[stringifiedEntityKey] = (`${entityStorageKey}`: any);
entityStorageKey++;
},
);

insertRawBlock(block, entityMap, rawBlocks, blockCacheRef);
Expand Down

0 comments on commit 0059dd4

Please sign in to comment.