From dbdd719c51d061dfc327644d4b2ca89a0595b4f1 Mon Sep 17 00:00:00 2001 From: Mike Piccolo Date: Fri, 4 Nov 2016 06:14:19 -0700 Subject: [PATCH] PLT-4376 iOS and Android: Keep the keyboard open after sending a message (#4377) * Force keyboard to retain focus on submitting post on mobile * Fix lint error * Allow keyboard to stay closed if the keyboard was closed earlier before submitting * Increase delay time and add to comment * Remove pass through props on suggestion box --- webapp/components/create_comment.jsx | 17 ++++++++++++++--- webapp/components/create_post.jsx | 19 +++++++++++++++---- .../components/suggestion/suggestion_box.jsx | 1 + webapp/components/textbox.jsx | 9 +++++++++ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx index a34ce0b8a8..2aa85265a8 100644 --- a/webapp/components/create_comment.jsx +++ b/webapp/components/create_comment.jsx @@ -37,6 +37,7 @@ export default class CreateComment extends React.Component { this.commentMsgKeyPress = this.commentMsgKeyPress.bind(this); this.handleChange = this.handleChange.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); + this.handleBlur = this.handleBlur.bind(this); this.handleUploadClick = this.handleUploadClick.bind(this); this.handleUploadStart = this.handleUploadStart.bind(this); this.handleFileUploadComplete = this.handleFileUploadComplete.bind(this); @@ -58,7 +59,8 @@ export default class CreateComment extends React.Component { fileInfos: draft.fileInfos, submitting: false, ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'), - showPostDeletedModal: false + showPostDeletedModal: false, + lastBlurAt: 0 }; } @@ -166,6 +168,10 @@ export default class CreateComment extends React.Component { fileInfos: [], serverError: null }); + + const fasterThanHumanWillClick = 150; + const forceFocus = (Date.now() - this.state.lastBlurAt < fasterThanHumanWillClick); + this.focusTextbox(forceFocus); } commentMsgKeyPress(e) { @@ -316,8 +322,8 @@ export default class CreateComment extends React.Component { return this.state.fileInfos.length + this.state.uploadsInProgress.length; } - focusTextbox() { - if (!Utils.isMobile()) { + focusTextbox(keepFocus = false) { + if (keepFocus || !Utils.isMobile()) { this.refs.textbox.focus(); } } @@ -334,6 +340,10 @@ export default class CreateComment extends React.Component { }); } + handleBlur() { + this.setState({lastBlurAt: Date.now()}); + } + render() { let serverError = null; if (this.state.serverError) { @@ -397,6 +407,7 @@ export default class CreateComment extends React.Component { onKeyPress={this.commentMsgKeyPress} onKeyDown={this.handleKeyDown} value={this.state.message} + onBlur={this.handleBlur} createMessage={Utils.localizeMessage('create_comment.addComment', 'Add a comment...')} initialText='' supportsCommands={false} diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx index 7cbe481144..db61aca41f 100644 --- a/webapp/components/create_post.jsx +++ b/webapp/components/create_post.jsx @@ -52,6 +52,7 @@ export default class CreatePost extends React.Component { this.onPreferenceChange = this.onPreferenceChange.bind(this); this.getFileCount = this.getFileCount.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); + this.handleBlur = this.handleBlur.bind(this); this.sendMessage = this.sendMessage.bind(this); this.focusTextbox = this.focusTextbox.bind(this); this.showPostDeletedModal = this.showPostDeletedModal.bind(this); @@ -71,7 +72,8 @@ export default class CreatePost extends React.Component { ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'), fullWidthTextBox: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN, showTutorialTip: false, - showPostDeletedModal: false + showPostDeletedModal: false, + lastBlurAt: 0 }; } @@ -128,6 +130,10 @@ export default class CreatePost extends React.Component { } else { this.sendMessage(post); } + + const fasterThanHumanWillClick = 150; + const forceFocus = (Date.now() - this.state.lastBlurAt < fasterThanHumanWillClick); + this.focusTextbox(forceFocus); } sendMessage(post) { @@ -171,8 +177,8 @@ export default class CreatePost extends React.Component { ); } - focusTextbox() { - if (!Utils.isMobile()) { + focusTextbox(keepFocus = false) { + if (keepFocus || !Utils.isMobile()) { this.refs.textbox.focus(); } } @@ -405,6 +411,10 @@ export default class CreatePost extends React.Component { } } + handleBlur() { + this.setState({lastBlurAt: Date.now()}); + } + showPostDeletedModal() { this.setState({ showPostDeletedModal: true @@ -495,6 +505,7 @@ export default class CreatePost extends React.Component { onKeyPress={this.postMsgKeyPress} onKeyDown={this.handleKeyDown} value={this.state.message} + onBlur={this.handleBlur} createMessage={Utils.localizeMessage('create_post.write', 'Write a message...')} channelId={this.state.channelId} id='post_textbox' @@ -536,4 +547,4 @@ export default class CreatePost extends React.Component { ); } -} \ No newline at end of file +} diff --git a/webapp/components/suggestion/suggestion_box.jsx b/webapp/components/suggestion/suggestion_box.jsx index 62148c454a..590fdae046 100644 --- a/webapp/components/suggestion/suggestion_box.jsx +++ b/webapp/components/suggestion/suggestion_box.jsx @@ -227,5 +227,6 @@ SuggestionBox.propTypes = { // explicitly name any input event handlers we override and need to manually call onChange: React.PropTypes.func, + onBlur: React.PropTypes.func, onKeyDown: React.PropTypes.func }; diff --git a/webapp/components/textbox.jsx b/webapp/components/textbox.jsx index 4a4a854f3c..f11ef20adb 100644 --- a/webapp/components/textbox.jsx +++ b/webapp/components/textbox.jsx @@ -29,6 +29,7 @@ export default class Textbox extends React.Component { this.onRecievedError = this.onRecievedError.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); + this.handleBlur = this.handleBlur.bind(this); this.handleHeightChange = this.handleHeightChange.bind(this); this.showPreview = this.showPreview.bind(this); @@ -84,6 +85,12 @@ export default class Textbox extends React.Component { } } + handleBlur(e) { + if (this.props.onBlur) { + this.props.onBlur(e); + } + } + handleHeightChange(height) { const textbox = $(this.refs.message.getTextbox()); const wrapper = $(this.refs.wrapper); @@ -209,6 +216,7 @@ export default class Textbox extends React.Component { onChange={this.props.onChange} onKeyPress={this.handleKeyPress} onKeyDown={this.handleKeyDown} + onBlur={this.handleBlur} onHeightChange={this.handleHeightChange} style={{visibility: this.state.preview ? 'hidden' : 'visible'}} listComponent={SuggestionList} @@ -255,5 +263,6 @@ Textbox.propTypes = { onKeyPress: React.PropTypes.func.isRequired, createMessage: React.PropTypes.string.isRequired, onKeyDown: React.PropTypes.func, + onBlur: React.PropTypes.func, supportsCommands: React.PropTypes.bool.isRequired };