Skip to content

Commit

Permalink
Part two deprecate but dont delete old entity api (facebookarchive#814)
Browse files Browse the repository at this point in the history
* Add warnings and comments about deprecating old Entity API

We are deprecating the old DraftEntity API.

Why? Because
 - currently changing or adding entities won't trigger a re-render
 - the use of a non-Immutable storage for entities doesn't fit well with
   the rest of the Draft architecture
 - moves Entity storage out of global module; this just makes more sense
   as an API, rather than having it globally available.

This moves the logic for the old API into private methods, and adds
warnings and comments around the public-but-deprecated API methods.

We then use the private methods internally while we still support both
APIs.

A future version of Draft will actually remove the old API completely,
and these warnings and comments will help folks make updates to their
code to prepare.

We will release more documentation about this soon.

* Update syntax of tex example

This example was still using the old syntax, and the new warnings we
added alerted us to this fact when doing manual testing.
  • Loading branch information
flarnie authored and ouchxp committed Apr 7, 2017
1 parent f9521a7 commit fd48def
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 38 deletions.
15 changes: 10 additions & 5 deletions examples/draft-0-10-0/tex/js/modifiers/insertTeXBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import {
AtomicBlockUtils,
Entity,
EditorState,
} from 'draft-js';

let count = 0;
Expand All @@ -36,12 +36,17 @@ const examples = [
];

export function insertTeXBlock(editorState) {
const contentState = editorState.getCurrentContent();
const nextFormula = count++ % examples.length;
const entityKey = Entity.create(
const contentStateWithEntity = contentState.createEntity(
'TOKEN',
'IMMUTABLE',
{content: examples[nextFormula]}
{content: examples[nextFormula]},
);

return AtomicBlockUtils.insertAtomicBlock(editorState, entityKey, ' ');
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(
editorState,
{currentContent: contentStateWithEntity}
);
return AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' ');
}
4 changes: 2 additions & 2 deletions src/model/encoding/convertFromHTMLToContentBlocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ function genFragment(
node.textContent = imageURI; // Output src if no decorator

// TODO: update this when we remove DraftEntity entirely
inEntity = DraftEntity.create(
inEntity = DraftEntity._create(
'IMAGE',
'MUTABLE',
entityConfig || {},
Expand Down Expand Up @@ -475,7 +475,7 @@ function genFragment(

entityConfig.url = new URI(anchor.href).toString();
// TODO: update this when we remove DraftEntity completely
entityId = DraftEntity.create(
entityId = DraftEntity._create(
'LINK',
'MUTABLE',
entityConfig || {},
Expand Down
2 changes: 1 addition & 1 deletion src/model/encoding/convertFromRawToDraftState.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function convertFromRawToDraftState(
storageKey => {
var encodedEntity = entityMap[storageKey];
var {type, mutability, data} = encodedEntity;
var newKey = DraftEntity.create(type, mutability, data || {});
var newKey = DraftEntity._create(type, mutability, data || {});
fromStorageToLocal[storageKey] = newKey;
}
);
Expand Down
136 changes: 128 additions & 8 deletions src/model/entity/DraftEntity.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ var {Map} = Immutable;
var instances: Map<string, DraftEntityInstance> = Map();
var instanceKey = 0;

/**
* Temporary utility for generating the warnings
*/
function logWarning(oldMethodCall, newMethodCall) {
console.warn(
'WARNING: '
+ oldMethodCall
+ ' will be deprecated soon!\nPlease use "'
+ newMethodCall
+ '" instead.'
);
}

/**
* A "document entity" is an object containing metadata associated with a
* piece of text in a ContentBlock.
Expand All @@ -39,15 +52,25 @@ var instanceKey = 0;
*/
var DraftEntity = {
/**
* WARNING: This method will be deprecated soon!
* Please use 'contentState.getLastCreatedEntityKey' instead.
* ---
* Get the random key string from whatever entity was last created.
* We need this to support the new API, as part of transitioning to put Entity
* storage in contentState.
*/
getLastCreatedEntityKey: function(): string {
return '' + instanceKey;
logWarning(
'DraftEntity.getLastCreatedEntityKey',
'contentState.getLastCreatedEntityKey',
);
return DraftEntity._getLastCreatedEntityKey();
},

/**
* WARNING: This method will be deprecated soon!
* Please use 'contentState.createEntity' instead.
* ---
* Create a DraftEntityInstance and store it for later retrieval.
*
* A random key string will be generated and returned. This key may
Expand All @@ -59,16 +82,113 @@ var DraftEntity = {
mutability: DraftEntityMutability,
data?: Object,
): string {
return DraftEntity.add(
new DraftEntityInstance({type, mutability, data: data || {}})
logWarning(
'DraftEntity.create',
'contentState.createEntity',
);
return DraftEntity._create(type, mutability, data);
},

/**
* WARNING: This method will be deprecated soon!
* Please use 'contentState.addEntity' instead.
* ---
* Add an existing DraftEntityInstance to the DraftEntity map. This is
* useful when restoring instances from the server.
*/
add: function(instance: DraftEntityInstance): string {
logWarning(
'DraftEntity.add',
'contentState.addEntity',
);
return DraftEntity._add(instance);
},

/**
* WARNING: This method will be deprecated soon!
* Please use 'contentState.getEntity' instead.
* ---
* Retrieve the entity corresponding to the supplied key string.
*/
get: function(key: string): DraftEntityInstance {
logWarning(
'DraftEntity.get',
'contentState.getEntity',
);
return DraftEntity._get(key);
},

/**
* WARNING: This method will be deprecated soon!
* Please use 'contentState.mergeEntityData' instead.
* ---
* Entity instances are immutable. If you need to update the data for an
* instance, this method will merge your data updates and return a new
* instance.
*/
mergeData: function(
key: string,
toMerge: {[key: string]: any}
): DraftEntityInstance {
logWarning(
'DraftEntity.mergeData',
'contentState.mergeEntityData',
);
return DraftEntity._mergeData(key, toMerge);
},

/**
* WARNING: This method will be deprecated soon!
* Please use 'contentState.replaceEntityData' instead.
* ---
* Completely replace the data for a given instance.
*/
replaceData: function(
key: string,
newData: {[key: string]: any}
): DraftEntityInstance {
logWarning(
'DraftEntity.replaceData',
'contentState.replaceEntityData',
);
return DraftEntity._replaceData(key, newData);
},

// ***********************************WARNING******************************
// --- the above public API will be deprecated in the next version of Draft!
// The methods below this line are private - don't call them directly.

/**
* Get the random key string from whatever entity was last created.
* We need this to support the new API, as part of transitioning to put Entity
* storage in contentState.
*/
_getLastCreatedEntityKey: function(): string {
return '' + instanceKey;
},

/**
* Create a DraftEntityInstance and store it for later retrieval.
*
* A random key string will be generated and returned. This key may
* be used to track the entity's usage in a ContentBlock, and for
* retrieving data about the entity at render time.
*/
_create: function(
type: DraftEntityType,
mutability: DraftEntityMutability,
data?: Object,
): string {
return DraftEntity._add(
new DraftEntityInstance({type, mutability, data: data || {}})
);
},

/**
* Add an existing DraftEntityInstance to the DraftEntity map. This is
* useful when restoring instances from the server.
*/
_add: function(instance: DraftEntityInstance): string {
var key = '' + (++instanceKey);
instances = instances.set(key, instance);
return key;
Expand All @@ -77,7 +197,7 @@ var DraftEntity = {
/**
* Retrieve the entity corresponding to the supplied key string.
*/
get: function(key: string): DraftEntityInstance {
_get: function(key: string): DraftEntityInstance {
var instance = instances.get(key);
invariant(!!instance, 'Unknown DraftEntity key.');
return instance;
Expand All @@ -88,11 +208,11 @@ var DraftEntity = {
* instance, this method will merge your data updates and return a new
* instance.
*/
mergeData: function(
_mergeData: function(
key: string,
toMerge: {[key: string]: any}
): DraftEntityInstance {
var instance = DraftEntity.get(key);
var instance = DraftEntity._get(key);
var newData = {...instance.getData(), ...toMerge};
var newInstance = instance.set('data', newData);
instances = instances.set(key, newInstance);
Expand All @@ -102,11 +222,11 @@ var DraftEntity = {
/**
* Completely replace the data for a given instance.
*/
replaceData: function(
_replaceData: function(
key: string,
newData: {[key: string]: any}
): DraftEntityInstance {
const instance = DraftEntity.get(key);
const instance = DraftEntity._get(key);
const newInstance = instance.set('data', newData);
instances = instances.set(key, newInstance);
return newInstance;
Expand Down
16 changes: 8 additions & 8 deletions src/model/entity/__tests__/DraftEntity-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('DraftEntity', () => {
});

function createLink() {
return DraftEntity.create('LINK', 'MUTABLE', {uri: 'zombo.com'});
return DraftEntity._create('LINK', 'MUTABLE', {uri: 'zombo.com'});
}

it('must create instances', () => {
Expand All @@ -31,34 +31,34 @@ describe('DraftEntity', () => {

it('must retrieve an instance given a key', () => {
var key = createLink();
var retrieved = DraftEntity.get(key);
var retrieved = DraftEntity._get(key);
expect(retrieved.getType()).toBe('LINK');
expect(retrieved.getMutability()).toBe('MUTABLE');
expect(retrieved.getData()).toEqual({uri: 'zombo.com'});
});

it('must throw when retrieving for an invalid key', () => {
createLink();
expect(() => DraftEntity.get('asdfzxcvqweriuop')).toThrow();
expect(() => DraftEntity.get(null)).toThrow();
expect(() => DraftEntity._get('asdfzxcvqweriuop')).toThrow();
expect(() => DraftEntity._get(null)).toThrow();
});

it('must merge data', () => {
var key = createLink();

// Merge new property.
var newData = {foo: 'bar'};
DraftEntity.mergeData(key, newData);
var newEntity = DraftEntity.get(key);
DraftEntity._mergeData(key, newData);
var newEntity = DraftEntity._get(key);
expect(newEntity.getData()).toEqual({
uri: 'zombo.com',
foo: 'bar',
});

// Replace existing property.
var withNewURI = {uri: 'homestarrunner.com'};
DraftEntity.mergeData(key, withNewURI);
var entityWithNewURI = DraftEntity.get(key);
DraftEntity._mergeData(key, withNewURI);
var entityWithNewURI = DraftEntity._get(key);
expect(entityWithNewURI.getData()).toEqual({
uri: 'homestarrunner.com',
foo: 'bar',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ selectionState = selectionState.merge({
});

function setEntityMutability(mutability) {
contentState.getEntityMap().get = () => ({
contentState.getEntityMap()._get = () => ({
getMutability: () => mutability,
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/model/entity/getEntityKeyForSelection.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function filterKey(
entityKey: ?string
): ?string {
if (entityKey) {
var entity = entityMap.get(entityKey);
var entity = entityMap._get(entityKey);
return entity.getMutability() === 'MUTABLE' ? entityKey : null;
}
return null;
Expand Down
12 changes: 6 additions & 6 deletions src/model/immutable/ContentState.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class ContentState extends ContentStateRecord {

getLastCreatedEntityKey() {
// TODO: update this when we fully remove DraftEntity
return DraftEntity.getLastCreatedEntityKey();
return DraftEntity._getLastCreatedEntityKey();
}

hasText(): boolean {
Expand All @@ -139,7 +139,7 @@ class ContentState extends ContentStateRecord {
data?: Object
): ContentState {
// TODO: update this when we fully remove DraftEntity
DraftEntity.create(
DraftEntity._create(
type,
mutability,
data,
Expand All @@ -152,7 +152,7 @@ class ContentState extends ContentStateRecord {
toMerge: {[key: string]: any}
): ContentState {
// TODO: update this when we fully remove DraftEntity
DraftEntity.mergeData(key, toMerge);
DraftEntity._mergeData(key, toMerge);
return this;
}

Expand All @@ -161,19 +161,19 @@ class ContentState extends ContentStateRecord {
newData: {[key: string]: any}
): ContentState {
// TODO: update this when we fully remove DraftEntity
DraftEntity.replaceData(key, newData);
DraftEntity._replaceData(key, newData);
return this;
}

addEntity(instance: DraftEntityInstance): ContentState {
// TODO: update this when we fully remove DraftEntity
DraftEntity.add(instance);
DraftEntity._add(instance);
return this;
}

getEntity(key: string): DraftEntityInstance {
// TODO: update this when we fully remove DraftEntity
return DraftEntity.get(key);
return DraftEntity._get(key);
}

static createFromBlockArray(
Expand Down
2 changes: 1 addition & 1 deletion src/model/modifier/RichTextEditorUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const RichTextEditorUtil = {
.slice(selection.getStartOffset(), selection.getEndOffset())
.some(v => {
var entity = v.getEntity();
return !!entity && entityMap.get(entity).getType() === 'LINK';
return !!entity && entityMap._get(entity).getType() === 'LINK';
});
},

Expand Down
2 changes: 1 addition & 1 deletion src/model/modifier/getCharacterRemovalRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function getCharacterRemovalRange(
return selectionState;
}

var entity = entityMap.get(entityKey);
var entity = entityMap._get(entityKey);
var mutability = entity.getMutability();

// `MUTABLE` entities can just have the specified range of text removed
Expand Down
Loading

0 comments on commit fd48def

Please sign in to comment.