From 6cb8b12cdae7b5119dfe86a5463a84d3afff2058 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 27 Jul 2017 18:07:41 +0100 Subject: [PATCH 1/2] Instead of inserting MD for completion, convert the Entity later This makes sure that the length of the range for a completed Entity = the length of the text in the decoration, which apparently draftjs assumes when calculating selection state offsets. Fixes https://github.com/vector-im/riot-web/issues/4666 --- .../views/rooms/MessageComposerInput.js | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index ba1673a9df..50486047a5 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -718,9 +718,31 @@ export default class MessageComposerInput extends React.Component { ); } } else { - // Use the original plaintext because `contextText` has had mentions stripped - // and these need to end up in contentHTML - const md = new Markdown(contentState.getPlainText()); + // Use the original contentState because `contentText` has had mentions + // stripped and these need to end up in contentHTML. + + // Replace all Entities of type `LINK` with markdown link equivalents. + // TODO: move this into `Markdown` and do the same conversion in the other + // two places (toggling from MD->RT mode and loading MD history into RT mode) + // but this can only be done when history includes Entities. + 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)); + if (entity.getType() !== 'LINK') { + return; + } + const text = blockText.slice(offset + start, offset + end); + const url = entity.getData().url; + const mdLink = `[${text}](${url})`; + blockText = blockText.slice(0, offset + start) + mdLink + blockText.slice(offset + end); + offset += mdLink.length - text.length; + }); + return blockText; + }).join('\n'); + + const md = new Markdown(pt); if (md.isPlainText()) { contentText = md.toPlaintext(); } else { @@ -916,9 +938,6 @@ export default class MessageComposerInput extends React.Component { url: href, isCompletion: true, }); - if (!this.state.isRichtextEnabled) { - mdCompletion = `[${completion}](${href})`; - } } let selection; From 8a5f2bf2ca2f3a30963b8c329575fdfdace8ec0f Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 28 Jul 2017 14:46:57 +0100 Subject: [PATCH 2/2] Interpret a `split-block` as format toggle for an empty block (`split-block` is emitted when "return" is pressed) part of fixing https://github.com/vector-im/riot-web/issues/4580 --- src/components/views/rooms/MessageComposerInput.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 50486047a5..6963e718b0 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -502,12 +502,18 @@ export default class MessageComposerInput extends React.Component { // These are block types, not handled by RichUtils by default. const blockCommands = ['code-block', 'blockquote', 'unordered-list-item', 'ordered-list-item']; const currentBlockType = RichUtils.getCurrentBlockType(this.state.editorState); + + const shouldToggleBlockFormat = ( + command === 'backspace' || + command === 'split-block' + ) && currentBlockType !== 'unstyled'; + if (blockCommands.includes(command)) { newState = RichUtils.toggleBlockType(this.state.editorState, command); } else if (command === 'strike') { // this is the only inline style not handled by Draft by default newState = RichUtils.toggleInlineStyle(this.state.editorState, 'STRIKETHROUGH'); - } else if (command === 'backspace' && currentBlockType !== 'unstyled') { + } else if (shouldToggleBlockFormat) { const currentStartOffset = this.state.editorState.getSelection().getStartOffset(); if (currentStartOffset === 0) { // Toggle current block type (setting it to 'unstyled')