From 4f0cf7d6ecc39799ba8c0f6ea3b1c3bd173c68cb Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 3 Aug 2017 11:16:32 +0100 Subject: [PATCH 1/6] Update npm dep of draft-js to 0.11.0-alpha --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3bab88d45..496d8a7de6 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "classnames": "^2.1.2", "commonmark": "^0.27.0", "counterpart": "^0.18.0", - "draft-js": "^0.10.1", + "draft-js": "^0.11.0-alpha", "draft-js-export-html": "^0.5.0", "draft-js-export-markdown": "^0.2.0", "emojione": "2.2.7", From 124795006ce071e1e3faa6a622c9adfc7ab1f6a2 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 3 Aug 2017 11:18:56 +0100 Subject: [PATCH 2/6] Reflect API change for creating an Entity --- src/RichText.js | 5 ++++- .../views/rooms/MessageComposerInput.js | 15 +++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/RichText.js b/src/RichText.js index 225a1c212a..6f7d143e04 100644 --- a/src/RichText.js +++ b/src/RichText.js @@ -248,7 +248,10 @@ export function attachImmutableEntitiesToEmoji(editorState: EditorState): Editor .set('anchorOffset', start) .set('focusOffset', end); const emojiText = plainText.substring(start, end); - const entityKey = Entity.create('emoji', 'IMMUTABLE', { emojiUnicode: emojiText }); + newContentState = newContentState.createEntity( + 'emoji', 'IMMUTABLE', { emojiUnicode: emojiText } + ); + const entityKey = newContentState.getLastCreatedEntityKey(); newContentState = Modifier.replaceText( newContentState, selection, diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 743caf3a76..222a473a23 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -936,32 +936,27 @@ export default class MessageComposerInput extends React.Component { } const {range = null, completion = '', href = null, suffix = ''} = displayedCompletion; + let contentState = activeEditorState.getCurrentContent(); let entityKey; - let mdCompletion; if (href) { - entityKey = Entity.create('LINK', 'IMMUTABLE', { + contentState = contentState.createEntity('LINK', 'IMMUTABLE', { url: href, isCompletion: true, }); + entityKey = contentState.getLastCreatedEntityKey(); } let selection; if (range) { selection = RichText.textOffsetsToSelectionState( - range, activeEditorState.getCurrentContent().getBlocksAsArray(), + range, contentState.getBlocksAsArray(), ); } else { selection = activeEditorState.getSelection(); } - let contentState = Modifier.replaceText( - activeEditorState.getCurrentContent(), - selection, - mdCompletion || completion, - null, - entityKey, - ); + contentState = Modifier.replaceText(contentState, selection, completion, null, entityKey); // Move the selection to the end of the block const afterSelection = contentState.getSelectionAfter(); From fb5dc295aa1dd109c09b119bf2c38ea47e3169d9 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 3 Aug 2017 11:29:26 +0100 Subject: [PATCH 3/6] Reflect API change for getting an Entity --- src/RichText.js | 2 +- .../views/rooms/MessageComposerInput.js | 36 ++++++++++--------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/RichText.js b/src/RichText.js index 6f7d143e04..5f37d89c6f 100644 --- a/src/RichText.js +++ b/src/RichText.js @@ -238,7 +238,7 @@ export function attachImmutableEntitiesToEmoji(editorState: EditorState): Editor const existingEntityKey = block.getEntityAt(start); if (existingEntityKey) { // avoid manipulation in case the emoji already has an entity - const entity = Entity.get(existingEntityKey); + const entity = newContentState.getEntity(existingEntityKey); if (entity && entity.get('type') === 'emoji') { return; } diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 222a473a23..669156ba7a 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -165,17 +165,20 @@ export default class MessageComposerInput extends React.Component { this.client = MatrixClientPeg.get(); } - findLinkEntities(contentBlock, callback) { - contentBlock.findEntityRanges( - (character) => { - const entityKey = character.getEntity(); - return ( - entityKey !== null && - Entity.get(entityKey).getType() === 'LINK' - ); - }, callback, - ); + getLinkFindingStrategy(contentState: ContentState) { + return (contentBlock, callback) => { + contentBlock.findEntityRanges( + (character) => { + const entityKey = character.getEntity(); + return ( + entityKey !== null && + contentState.getEntity(entityKey).getType() === 'LINK' + ); + }, callback, + ); + }; } + /* * "Does the right thing" to create an EditorState, based on: * - whether we've got rich text mode enabled @@ -185,10 +188,10 @@ export default class MessageComposerInput extends React.Component { const decorators = richText ? RichText.getScopedRTDecorators(this.props) : RichText.getScopedMDDecorators(this.props); decorators.push({ - strategy: this.findLinkEntities.bind(this), + strategy: this.getLinkFindingStrategy(contentState), component: (entityProps) => { const Pill = sdk.getComponent('elements.Pill'); - const {url} = Entity.get(entityProps.entityKey).getData(); + const {url} = contentState.getEntity(entityProps.entityKey).getData(); if (Pill.isPillUrl(url)) { return ; } @@ -713,7 +716,7 @@ export default class MessageComposerInput extends React.Component { const hasLink = blocks.some((block) => { return block.getCharacterList().filter((c) => { const entityKey = c.getEntity(); - return entityKey && Entity.get(entityKey).getType() === 'LINK'; + return entityKey && contentState.getEntity(entityKey).getType() === 'LINK'; }).size > 0; }); shouldSendHTML = hasLink; @@ -724,6 +727,7 @@ export default class MessageComposerInput extends React.Component { ); } } else { + const findLinkEntities = this.getLinkFindingStrategy(contentState); // Use the original contentState because `contentText` has had mentions // stripped and these need to end up in contentHTML. @@ -734,8 +738,8 @@ export default class MessageComposerInput extends React.Component { const pt = contentState.getBlocksAsArray().map((block) => { let blockText = block.getText(); let offset = 0; - this.findLinkEntities(block, (start, end) => { - const entity = Entity.get(block.getEntityAt(start)); + findLinkEntities(block, (start, end) => { + const entity = contentState.getEntity(block.getEntityAt(start)); if (entity.getType() !== 'LINK') { return; } @@ -1042,7 +1046,7 @@ export default class MessageComposerInput extends React.Component { offset -= sum; const entityKey = block.getEntityAt(offset); - const entity = entityKey ? Entity.get(entityKey) : null; + const entity = entityKey ? contentState.getEntity(entityKey) : null; if (entity && entity.getData().isCompletion) { // This is a completed mention, so do not insert MD link, just text return text; From 1d1cd5f691f57c388fb2ba2c0c8fc6c317a707e1 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 3 Aug 2017 11:36:07 +0100 Subject: [PATCH 4/6] Reflect API change for decorator strategy --- .../views/rooms/MessageComposerInput.js | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 669156ba7a..18b2424106 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -165,18 +165,16 @@ export default class MessageComposerInput extends React.Component { this.client = MatrixClientPeg.get(); } - getLinkFindingStrategy(contentState: ContentState) { - return (contentBlock, callback) => { - contentBlock.findEntityRanges( - (character) => { - const entityKey = character.getEntity(); - return ( - entityKey !== null && - contentState.getEntity(entityKey).getType() === 'LINK' - ); - }, callback, - ); - }; + findLinkEntities(contentBlock: ContentBlock, callback, contentState: ContentState) { + contentBlock.findEntityRanges( + (character) => { + const entityKey = character.getEntity(); + return ( + entityKey !== null && + contentState.getEntity(entityKey).getType() === 'LINK' + ); + }, callback, + ); } /* @@ -188,7 +186,7 @@ export default class MessageComposerInput extends React.Component { const decorators = richText ? RichText.getScopedRTDecorators(this.props) : RichText.getScopedMDDecorators(this.props); decorators.push({ - strategy: this.getLinkFindingStrategy(contentState), + strategy: this.findLinkEntities.bind(this), component: (entityProps) => { const Pill = sdk.getComponent('elements.Pill'); const {url} = contentState.getEntity(entityProps.entityKey).getData(); @@ -727,7 +725,6 @@ export default class MessageComposerInput extends React.Component { ); } } else { - const findLinkEntities = this.getLinkFindingStrategy(contentState); // Use the original contentState because `contentText` has had mentions // stripped and these need to end up in contentHTML. @@ -738,7 +735,7 @@ export default class MessageComposerInput extends React.Component { const pt = contentState.getBlocksAsArray().map((block) => { let blockText = block.getText(); let offset = 0; - findLinkEntities(block, (start, end) => { + this.findLinkEntities(block, (start, end) => { const entity = contentState.getEntity(block.getEntityAt(start)); if (entity.getType() !== 'LINK') { return; From 901cbf495dfce1edeed791edf1606a374e83ee5b Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 3 Aug 2017 12:02:29 +0100 Subject: [PATCH 5/6] Update decorator strategy API in accordance with recent changes to 0.11.0 See https://github.com/facebook/draft-js/commit/590cdc6c54b409be750f5ad88206873218c6c289, which is a change to the API not mentioned in the migration to v0.10 notes https://draftjs.org/docs/v0-10-api-migration.html --- src/RichText.js | 6 +++--- src/components/views/rooms/MessageComposerInput.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/RichText.js b/src/RichText.js index 5f37d89c6f..6a183b31be 100644 --- a/src/RichText.js +++ b/src/RichText.js @@ -90,7 +90,7 @@ function findWithRegex(regex, contentBlock: ContentBlock, callback: (start: numb // Workaround for https://github.com/facebook/draft-js/issues/414 let emojiDecorator = { - strategy: (contentBlock, callback) => { + strategy: (contentState, contentBlock, callback) => { findWithRegex(EMOJI_REGEX, contentBlock, callback); }, component: (props) => { @@ -119,7 +119,7 @@ export function getScopedRTDecorators(scope: any): CompositeDecorator { export function getScopedMDDecorators(scope: any): CompositeDecorator { let markdownDecorators = ['HR', 'BOLD', 'ITALIC', 'CODE', 'STRIKETHROUGH'].map( (style) => ({ - strategy: (contentBlock, callback) => { + strategy: (contentState, contentBlock, callback) => { return findWithRegex(MARKDOWN_REGEX[style], contentBlock, callback); }, component: (props) => ( @@ -130,7 +130,7 @@ export function getScopedMDDecorators(scope: any): CompositeDecorator { })); markdownDecorators.push({ - strategy: (contentBlock, callback) => { + strategy: (contentState, contentBlock, callback) => { return findWithRegex(MARKDOWN_REGEX.LINK, contentBlock, callback); }, component: (props) => ( diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 18b2424106..938caa0969 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -165,7 +165,7 @@ export default class MessageComposerInput extends React.Component { this.client = MatrixClientPeg.get(); } - findLinkEntities(contentBlock: ContentBlock, callback, contentState: ContentState) { + findLinkEntities(contentState: ContentState, contentBlock: ContentBlock, callback) { contentBlock.findEntityRanges( (character) => { const entityKey = character.getEntity(); @@ -189,7 +189,7 @@ export default class MessageComposerInput extends React.Component { strategy: this.findLinkEntities.bind(this), component: (entityProps) => { const Pill = sdk.getComponent('elements.Pill'); - const {url} = contentState.getEntity(entityProps.entityKey).getData(); + const {url} = entityProps.contentState.getEntity(entityProps.entityKey).getData(); if (Pill.isPillUrl(url)) { return ; } From a27eefd89338cf1546f859bdae434afc4052d30e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 3 Aug 2017 15:20:44 +0100 Subject: [PATCH 6/6] Fix a couple of more errors due to API changes --- src/RichText.js | 3 ++- src/components/views/rooms/MessageComposerInput.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/RichText.js b/src/RichText.js index 6a183b31be..9876fcc93f 100644 --- a/src/RichText.js +++ b/src/RichText.js @@ -51,7 +51,8 @@ export const contentStateToHTML = (contentState: ContentState) => { }; export function htmlToContentState(html: string): ContentState { - return ContentState.createFromBlockArray(convertFromHTML(html)); + const blockArray = convertFromHTML(html).contentBlocks; + return ContentState.createFromBlockArray(blockArray); } function unicodeToEmojiUri(str) { diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 938caa0969..c16348300f 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -735,7 +735,7 @@ export default class MessageComposerInput extends React.Component { const pt = contentState.getBlocksAsArray().map((block) => { let blockText = block.getText(); let offset = 0; - this.findLinkEntities(block, (start, end) => { + this.findLinkEntities(contentState, block, (start, end) => { const entity = contentState.getEntity(block.getEntityAt(start)); if (entity.getType() !== 'LINK') { return;