From 68cf666d0e2593a2828b25de1ef78d4cf1393cea Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Sat, 8 Jun 2019 00:31:33 +0300 Subject: [PATCH 1/3] Fixed markdown editor bugs --- .../view/formats/applyListFormat.js | 38 ++++++++----- .../view/formats/applyWebLinkFormat.js | 10 ++-- .../view/formats/applyWrapFormat.js | 11 +--- .../view/formats/applyWrapFormatNewLines.js | 16 ++---- .../markdownEditor/view/formats/formats.js | 1 - .../markdownEditor/view/markdownEditorView.js | 55 ++++++++++--------- .../textInput/view/textInputView.js | 6 +- 7 files changed, 68 insertions(+), 69 deletions(-) diff --git a/src/components/markdownEditor/view/formats/applyListFormat.js b/src/components/markdownEditor/view/formats/applyListFormat.js index c39861060..640048213 100644 --- a/src/components/markdownEditor/view/formats/applyListFormat.js +++ b/src/components/markdownEditor/view/formats/applyListFormat.js @@ -1,32 +1,40 @@ import { replaceBetween } from './utils'; -export default ({ getState, item, setState }) => { - let { text } = getState(); - const { selection } = getState(); - text = text || ''; +export default async ({ getState, item, setState }) => { + const states = getState(); + let { text } = states; + const { selection } = states; let newText; let newSelection; - if (selection.start !== selection.end) { + + text = text || ''; + + const isSelected = selection.start === selection.end; + const hasLineBreakOnStart = text.substring(selection.start - 1, selection.start) === '\n'; + const hasLineBreakOnEnd = text.substring(selection.end - 1, selection.end) === '\n'; + + if (!isSelected && hasLineBreakOnStart) { newText = replaceBetween( text, selection, `${item.prefix} ${text.substring(selection.start, selection.end)}\n`, ); newSelection = { start: selection.end + 3, end: selection.end + 3 }; - } else if ( - selection.start === selection.end && - text.substring(selection.end - 1, selection.end) === '\n' - ) { + } else if (!isSelected && !hasLineBreakOnStart) { + newText = replaceBetween( + text, + selection, + `\n${item.prefix} ${text.substring(selection.start, selection.end)}\n`, + ); + newSelection = { start: selection.end + 3, end: selection.end + 3 }; + } else if (isSelected && hasLineBreakOnEnd) { newText = replaceBetween(text, selection, `${item.prefix} `); newSelection = { start: selection.start + 2, end: selection.start + 2 }; - } else { + } else if (isSelected && !hasLineBreakOnEnd) { newText = replaceBetween(text, selection, `\n${item.prefix} `); newSelection = { start: selection.start + 3, end: selection.start + 3 }; } - setState({ text: newText }, () => { - setTimeout(() => { - setState({ newSelection }); - }, 300); - }); + await setState({ text: newText, textUpdated: true }); + await setState({ newSelection }); }; diff --git a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js index 563a2297b..f33c3cead 100644 --- a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js +++ b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js @@ -3,15 +3,15 @@ import { isStringWebLink, replaceBetween } from './utils'; export const writeUrlTextHere = 'https://example.com'; export const writeTextHereString = 'Text here'; -export default ({ getState, item, setState, isImage = null }) => { +export default async ({ getState, item, setState, isImage = null }) => { const { selection, text } = getState(); const imagePrefix = isImage ? '!' : ''; const itemText = item ? item.text : writeTextHereString; const itemUrl = item ? item.url : writeUrlTextHere; - let newText; let newSelection; const selectedText = text.substring(selection.start, selection.end); + if (selection.start !== selection.end) { if (isStringWebLink(selectedText)) { newText = replaceBetween(text, selection, `${imagePrefix}[${itemText}](${selectedText})`); @@ -40,7 +40,7 @@ export default ({ getState, item, setState, isImage = null }) => { }; } } - setState({ text: newText }, () => { - setState({ newSelection }); - }); + + await setState({ text: newText, textUpdated: true }); + await setState({ newSelection }); }; diff --git a/src/components/markdownEditor/view/formats/applyWrapFormat.js b/src/components/markdownEditor/view/formats/applyWrapFormat.js index 11ad6b4e3..d15d99c8e 100644 --- a/src/components/markdownEditor/view/formats/applyWrapFormat.js +++ b/src/components/markdownEditor/view/formats/applyWrapFormat.js @@ -8,19 +8,14 @@ export default ({ getState, item, setState }) => { item.wrapper.concat(text.substring(selection.start, selection.end), item.wrapper), ); let newPosition; + if (selection.start === selection.end) { newPosition = selection.end + item.wrapper.length; } else { newPosition = selection.end + item.wrapper.length * 2; } - const extra = { - newSelection: { - start: newPosition, - end: newPosition, - }, - }; - setState({ text: newText }, () => { - setState({ ...extra }); + setState({ text: newText, textUpdated: true }, () => { + setState({ newSelection: { start: newPosition, end: newPosition } }); }); }; diff --git a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js index 6bc3657ea..f2744a793 100644 --- a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js +++ b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js @@ -1,6 +1,6 @@ import { replaceBetween } from './utils'; -export default ({ getState, item, setState }) => { +export default async ({ getState, item, setState }) => { const { text, selection } = getState(); let newText = replaceBetween( text, @@ -41,15 +41,7 @@ export default ({ getState, item, setState }) => { )}`, ); } - const extra = { - newSelection: { - start: newPosition, - end: newPosition, - }, - }; - setState({ text: newText }, () => { - setTimeout(() => { - setState({ ...extra }); - }, 25); - }); + + await setState({ text: newText, textUpdated: true }); + await setState({ newSelection: { start: newPosition, end: newPosition } }); }; diff --git a/src/components/markdownEditor/view/formats/formats.js b/src/components/markdownEditor/view/formats/formats.js index 0d5ee0d2d..ced587e87 100644 --- a/src/components/markdownEditor/view/formats/formats.js +++ b/src/components/markdownEditor/view/formats/formats.js @@ -11,7 +11,6 @@ export default [ iconType: 'FontAwesome', wrapper: '**', onPress: applyWrapFormat, - // style: { fontWeight: 'bold' }, }, { key: 'I', diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index 68ae18a67..bb6a97507 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -22,8 +22,13 @@ export default class MarkdownEditorView extends Component { this.state = { text: props.draftBody || '', selection: { start: 0, end: 0 }, + textUpdated: false, newSelection: null, }; + + this.inputRef = React.createRef(); + this.galleryRef = React.createRef(); + this.clearRef = React.createRef(); } // Lifecycle functions @@ -47,8 +52,8 @@ export default class MarkdownEditorView extends Component { ) { applyImageLink({ getState: this._getState, - setState: (state, callback) => { - this.setState(state, callback); + setState: async (state, callback) => { + await this.setState(state, callback); }, item: { url: nextProps.uploadedImage.url, text: nextProps.uploadedImage.hash }, isImage: !!nextProps.uploadedImage, @@ -76,6 +81,14 @@ export default class MarkdownEditorView extends Component { // Component functions _changeText = input => { const { onChange, handleOnTextChange, handleIsValid, componentID } = this.props; + const { textUpdated } = this.state; + + if (textUpdated) { + this.setState({ + textUpdated: false, + }); + return; + } this.setState({ text: input }); @@ -100,14 +113,16 @@ export default class MarkdownEditorView extends Component { selection: newSelection, newSelection: null, }); - } else { - this.setState({ - selection: event.nativeEvent.selection, - }); + return; } + this.setState({ + selection: event.nativeEvent.selection, + }); }; - _getState = () => this.state; + _getState = () => { + return this.state; + }; _renderPreview = () => { const { text } = this.state; @@ -154,7 +169,7 @@ export default class MarkdownEditorView extends Component { onPress={() => Formats[9].onPress({ getState, setState })} /> this.ActionSheet.show()} + onPress={() => this.galleryRef.current.show()} style={styles.rightIcons} size={20} iconStyle={styles.icon} @@ -163,21 +178,13 @@ export default class MarkdownEditorView extends Component { /> this.ClearActionSheet.show()} + onPress={() => this.clearRef.current.show()} size={20} iconStyle={styles.clearIcon} iconType="FontAwesome" name="trash" /> - {/* TODO: After alpha */} - {/* */} ); @@ -203,7 +210,7 @@ export default class MarkdownEditorView extends Component { {!isPreviewActive ? ( this._changeText(e)} + onChangeText={this._changeText} onSelectionChange={this._handleOnSelectionChange} placeholder={intl.formatMessage({ id: isReply ? 'editor.reply_placeholder' : 'editor.default_placeholder', @@ -214,6 +221,7 @@ export default class MarkdownEditorView extends Component { style={styles.textWrapper} underlineColorAndroid="transparent" value={text} + innerRef={this.inputRef} /> ) : ( this._renderPreview() @@ -222,13 +230,12 @@ export default class MarkdownEditorView extends Component { this._renderEditorButtons({ getState: this._getState, setState: (state, callback) => { + this.inputRef.current.focus(); this.setState(state, callback); }, })} - - {/* TODO: This is a problem re-factor */} (this.ActionSheet = o)} + ref={this.galleryRef} options={[ intl.formatMessage({ id: 'editor.open_gallery', @@ -246,7 +253,7 @@ export default class MarkdownEditorView extends Component { }} /> (this.ClearActionSheet = o)} + ref={this.clearRef} title={intl.formatMessage({ id: 'alert.clear_alert', })} @@ -259,9 +266,7 @@ export default class MarkdownEditorView extends Component { }), ]} cancelButtonIndex={1} - onPress={index => { - index === 0 && this._handleClear(); - }} + onPress={index => index === 0 && this._handleClear()} /> ); diff --git a/src/components/textInput/view/textInputView.js b/src/components/textInput/view/textInputView.js index ce23aaaad..6b9411cb2 100644 --- a/src/components/textInput/view/textInputView.js +++ b/src/components/textInput/view/textInputView.js @@ -1,9 +1,9 @@ import React from 'react'; -import { connect } from 'react-redux'; import { TextInput } from 'react-native'; +import { connect } from 'react-redux'; -const TextInputView = props => ( - +const TextInputView = ({ isDarkTheme, innerRef, ...props }) => ( + ); const mapStateToProps = state => ({ From fc9982da144c4b54875c492fc01a668da48c24e3 Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Sat, 8 Jun 2019 00:48:03 +0300 Subject: [PATCH 2/3] Fixed clear editor button design issue --- src/components/markdownEditor/view/markdownEditorView.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index bb6a97507..6a65dc4ae 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -183,6 +183,7 @@ export default class MarkdownEditorView extends Component { iconStyle={styles.clearIcon} iconType="FontAwesome" name="trash" + backgroundColor={styles.clearButtonWrapper.backgroundColor} /> From 515fb57aaa2b0959af704eadd7e790f0d5ca1cdf Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Tue, 11 Jun 2019 11:08:34 +0300 Subject: [PATCH 3/3] Comment changes --- .../markdownEditor/view/formats/applyWebLinkFormat.js | 5 +++-- .../markdownEditor/view/formats/applyWrapFormatNewLines.js | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js index f33c3cead..2cf5ff0a7 100644 --- a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js +++ b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js @@ -41,6 +41,7 @@ export default async ({ getState, item, setState, isImage = null }) => { } } - await setState({ text: newText, textUpdated: true }); - await setState({ newSelection }); + await setState({ text: newText, textUpdated: true }, async () => { + await setState({ newSelection }); + }); }; diff --git a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js index f2744a793..96b188b95 100644 --- a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js +++ b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js @@ -42,6 +42,7 @@ export default async ({ getState, item, setState }) => { ); } - await setState({ text: newText, textUpdated: true }); - await setState({ newSelection: { start: newPosition, end: newPosition } }); + await setState({ text: newText, textUpdated: true }, async () => { + await setState({ newSelection: { start: newPosition, end: newPosition } }); + }); };