From 2c42294bbcab3cd5cfdce9604e5872fe4a12e538 Mon Sep 17 00:00:00 2001 From: David Lu Date: Mon, 6 Jun 2016 10:01:35 -0700 Subject: PLT-3101 Added message history (#3205) * Added message history * Minor logical changes * Fixed indexes resetting * Fixed double messages * Fixed resetting main history when RHS opened --- webapp/components/create_comment.jsx | 42 ++++++++++++++++++++++--------- webapp/components/create_post.jsx | 47 +++++++++++++++++++++++++---------- webapp/components/edit_post_modal.jsx | 3 +++ 3 files changed, 67 insertions(+), 25 deletions(-) (limited to 'webapp/components') diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx index 6cd2054a1..8c80ad993 100644 --- a/webapp/components/create_comment.jsx +++ b/webapp/components/create_comment.jsx @@ -11,6 +11,7 @@ import UserStore from 'stores/user_store.jsx'; import PostDeletedModal from './post_deleted_modal.jsx'; import PostStore from 'stores/post_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; +import MessageHistoryStore from 'stores/message_history_store.jsx'; import Textbox from './textbox.jsx'; import MsgTyping from './msg_typing.jsx'; import FileUpload from './file_upload.jsx'; @@ -68,11 +69,11 @@ class CreateComment extends React.Component { this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this); PostStore.clearCommentDraftUploads(); + MessageHistoryStore.resetHistoryIndex('comment'); const draft = PostStore.getCommentDraft(this.props.rootId); this.state = { messageText: draft.message, - lastMessage: '', uploadsInProgress: draft.uploadsInProgress, previews: draft.previews, submitting: false, @@ -80,18 +81,22 @@ class CreateComment extends React.Component { showPostDeletedModal: false }; } + componentDidMount() { PreferenceStore.addChangeListener(this.onPreferenceChange); this.focusTextbox(); } + componentWillUnmount() { PreferenceStore.removeChangeListener(this.onPreferenceChange); } + onPreferenceChange() { this.setState({ ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter') }); } + componentDidUpdate(prevProps, prevState) { if (prevState.uploadsInProgress < this.state.uploadsInProgress) { $('.post-right__scroll').scrollTop($('.post-right__scroll')[0].scrollHeight); @@ -101,6 +106,7 @@ class CreateComment extends React.Component { this.focusTextbox(); } } + handleSubmit(e) { e.preventDefault(); @@ -125,6 +131,8 @@ class CreateComment extends React.Component { return; } + MessageHistoryStore.storeMessageInHistory(this.state.messageText); + const userId = UserStore.getCurrentId(); post.channel_id = this.props.channelId; @@ -173,13 +181,13 @@ class CreateComment extends React.Component { this.setState({ messageText: '', - lastMessage: this.state.messageText, submitting: false, postError: null, previews: [], serverError: null }); } + commentMsgKeyPress(e) { if (this.state.ctrlSend && e.ctrlKey || !this.state.ctrlSend) { if (e.which === KeyCodes.ENTER && !e.shiftKey && !e.altKey) { @@ -191,6 +199,7 @@ class CreateComment extends React.Component { GlobalActions.emitLocalUserTypingEvent(this.props.channelId, this.props.rootId); } + handleUserInput(messageText) { const draft = PostStore.getCommentDraft(this.props.rootId); draft.message = messageText; @@ -199,6 +208,7 @@ class CreateComment extends React.Component { $('.post-right__scroll').parent().scrollTop($('.post-right__scroll')[0].scrollHeight); this.setState({messageText: messageText}); } + handleKeyDown(e) { if (this.state.ctrlSend && e.keyCode === KeyCodes.ENTER && e.ctrlKey === true) { this.commentMsgKeyPress(e); @@ -224,22 +234,21 @@ class CreateComment extends React.Component { }); } - if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && e.keyCode === KeyCodes.UP) { - const lastPost = PostStore.getCurrentUsersLatestPost(this.props.channelId, this.props.rootId); - if (!lastPost || this.state.messageText !== '') { - return; - } - e.preventDefault(); - let message = lastPost.message; - if (this.state.lastMessage !== '') { - message = this.state.lastMessage; + if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && (e.keyCode === Constants.KeyCodes.UP || e.keyCode === Constants.KeyCodes.DOWN)) { + const lastMessage = MessageHistoryStore.nextMessageInHistory(e.keyCode, this.state.messageText, 'comment'); + if (lastMessage !== null) { + e.preventDefault(); + this.setState({ + messageText: lastMessage + }); } - this.setState({messageText: message}); } } + handleUploadClick() { this.focusTextbox(); } + handleUploadStart(clientIds) { const draft = PostStore.getCommentDraft(this.props.rootId); @@ -252,6 +261,7 @@ class CreateComment extends React.Component { // but this also resets the focus after a drag and drop this.focusTextbox(); } + handleFileUploadComplete(filenames, clientIds) { const draft = PostStore.getCommentDraft(this.props.rootId); @@ -269,6 +279,7 @@ class CreateComment extends React.Component { this.setState({uploadsInProgress: draft.uploadsInProgress, previews: draft.previews}); } + handleUploadError(err, clientId) { if (clientId === -1) { this.setState({serverError: err}); @@ -285,6 +296,7 @@ class CreateComment extends React.Component { this.setState({uploadsInProgress: draft.uploadsInProgress, serverError: err}); } } + removePreview(id) { const previews = this.state.previews; const uploadsInProgress = this.state.uploadsInProgress; @@ -309,30 +321,36 @@ class CreateComment extends React.Component { this.setState({previews: previews, uploadsInProgress: uploadsInProgress}); } + componentWillReceiveProps(newProps) { if (newProps.rootId !== this.props.rootId) { const draft = PostStore.getCommentDraft(newProps.rootId); this.setState({messageText: draft.message, uploadsInProgress: draft.uploadsInProgress, previews: draft.previews}); } } + getFileCount() { return this.state.previews.length + this.state.uploadsInProgress.length; } + focusTextbox() { if (!Utils.isMobile()) { this.refs.textbox.focus(); } } + showPostDeletedModal() { this.setState({ showPostDeletedModal: true }); } + hidePostDeletedModal() { this.setState({ showPostDeletedModal: false }); } + render() { let serverError = null; if (this.state.serverError) { diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx index 4c14b03de..ea4459d7d 100644 --- a/webapp/components/create_post.jsx +++ b/webapp/components/create_post.jsx @@ -17,6 +17,7 @@ import * as ChannelActions from 'actions/channel_actions.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import PostStore from 'stores/post_store.jsx'; +import MessageHistoryStore from 'stores/message_history_store.jsx'; import UserStore from 'stores/user_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; @@ -79,7 +80,6 @@ class CreatePost extends React.Component { this.state = { channelId: ChannelStore.getCurrentId(), messageText: draft.messageText, - lastMessage: '', uploadsInProgress: draft.uploadsInProgress, previews: draft.previews, submitting: false, @@ -90,6 +90,7 @@ class CreatePost extends React.Component { showPostDeletedModal: false }; } + getCurrentDraft() { const draft = PostStore.getCurrentDraft(); const safeDraft = {previews: [], messageText: '', uploadsInProgress: []}; @@ -108,6 +109,7 @@ class CreatePost extends React.Component { return safeDraft; } + handleSubmit(e) { e.preventDefault(); @@ -128,8 +130,10 @@ class CreatePost extends React.Component { return; } + MessageHistoryStore.storeMessageInHistory(this.state.messageText); + this.setState({submitting: true, serverError: null}); - this.setState({lastMessage: this.state.messageText}); + if (post.message.indexOf('/') === 0) { ChannelActions.executeCommand( this.state.channelId, @@ -158,6 +162,7 @@ class CreatePost extends React.Component { this.sendMessage(post); } } + sendMessage(post) { post.channel_id = this.state.channelId; post.filenames = this.state.previews; @@ -193,11 +198,13 @@ class CreatePost extends React.Component { } ); } + focusTextbox() { if (!Utils.isMobile()) { this.refs.textbox.focus(); } } + postMsgKeyPress(e) { if (this.state.ctrlSend && e.ctrlKey || !this.state.ctrlSend) { if (e.which === KeyCodes.ENTER && !e.shiftKey && !e.altKey) { @@ -209,6 +216,7 @@ class CreatePost extends React.Component { GlobalActions.emitLocalUserTypingEvent(this.state.channelId, ''); } + handleUserInput(messageText) { this.setState({messageText}); @@ -216,9 +224,11 @@ class CreatePost extends React.Component { draft.message = messageText; PostStore.storeCurrentDraft(draft); } + handleUploadClick() { this.focusTextbox(); } + handleUploadStart(clientIds, channelId) { const draft = PostStore.getDraft(channelId); @@ -231,6 +241,7 @@ class CreatePost extends React.Component { // but this also resets the focus after a drag and drop this.focusTextbox(); } + handleFileUploadComplete(filenames, clientIds, channelId) { const draft = PostStore.getDraft(channelId); @@ -250,6 +261,7 @@ class CreatePost extends React.Component { this.setState({uploadsInProgress: draft.uploadsInProgress, previews: draft.previews}); } } + handleUploadError(err, clientId, channelId) { let message = err; if (message && typeof message !== 'string') { @@ -274,6 +286,7 @@ class CreatePost extends React.Component { this.setState({serverError: message}); } + removePreview(id) { const previews = Object.assign([], this.state.previews); const uploadsInProgress = this.state.uploadsInProgress; @@ -298,6 +311,7 @@ class CreatePost extends React.Component { this.setState({previews, uploadsInProgress}); } + componentWillMount() { const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999); @@ -308,6 +322,7 @@ class CreatePost extends React.Component { showTutorialTip: tutorialStep === TutorialSteps.POST_POPOVER }); } + componentDidMount() { ChannelStore.addChangeListener(this.onChange); PreferenceStore.addChangeListener(this.onPreferenceChange); @@ -315,11 +330,13 @@ class CreatePost extends React.Component { this.focusTextbox(); document.addEventListener('keydown', this.showShortcuts); } + componentDidUpdate(prevProps, prevState) { if (prevState.channelId !== this.state.channelId) { this.focusTextbox(); } } + componentWillUnmount() { ChannelStore.removeChangeListener(this.onChange); PreferenceStore.removeChangeListener(this.onPreferenceChange); @@ -342,6 +359,7 @@ class CreatePost extends React.Component { ); } } + onChange() { const channelId = ChannelStore.getCurrentId(); if (this.state.channelId !== channelId) { @@ -350,6 +368,7 @@ class CreatePost extends React.Component { this.setState({channelId, messageText: draft.messageText, initialText: draft.messageText, submitting: false, serverError: null, postError: null, previews: draft.previews, uploadsInProgress: draft.uploadsInProgress}); } } + onPreferenceChange() { const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999); this.setState({ @@ -358,6 +377,7 @@ class CreatePost extends React.Component { centerTextbox: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_CENTERED }); } + getFileCount(channelId) { if (channelId === this.state.channelId) { return this.state.previews.length + this.state.uploadsInProgress.length; @@ -366,6 +386,7 @@ class CreatePost extends React.Component { const draft = PostStore.getDraft(channelId); return draft.previews.length + draft.uploadsInProgress.length; } + handleKeyDown(e) { if (this.state.ctrlSend && e.keyCode === KeyCodes.ENTER && e.ctrlKey === true) { this.postMsgKeyPress(e); @@ -394,30 +415,29 @@ class CreatePost extends React.Component { }); } - if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && e.keyCode === KeyCodes.UP) { - const channelId = ChannelStore.getCurrentId(); - const lastPost = PostStore.getCurrentUsersLatestPost(channelId); - if (!lastPost || this.state.messageText !== '') { - return; - } - e.preventDefault(); - let message = lastPost.message; - if (this.state.lastMessage !== '') { - message = this.state.lastMessage; + if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && (e.keyCode === Constants.KeyCodes.UP || e.keyCode === Constants.KeyCodes.DOWN)) { + const lastMessage = MessageHistoryStore.nextMessageInHistory(e.keyCode, this.state.messageText, 'post'); + if (lastMessage !== null) { + e.preventDefault(); + this.setState({ + messageText: lastMessage + }); } - this.setState({messageText: message}); } } + showPostDeletedModal() { this.setState({ showPostDeletedModal: true }); } + hidePostDeletedModal() { this.setState({ showPostDeletedModal: false }); } + createTutorialTip() { const screens = []; @@ -438,6 +458,7 @@ class CreatePost extends React.Component { /> ); } + render() { let serverError = null; if (this.state.serverError) { diff --git a/webapp/components/edit_post_modal.jsx b/webapp/components/edit_post_modal.jsx index ac82cf036..0c7b8d672 100644 --- a/webapp/components/edit_post_modal.jsx +++ b/webapp/components/edit_post_modal.jsx @@ -9,6 +9,7 @@ import * as GlobalActions from 'actions/global_actions.jsx'; import Textbox from './textbox.jsx'; import BrowserStore from 'stores/browser_store.jsx'; import PostStore from 'stores/post_store.jsx'; +import MessageHistoryStore from 'stores/message_history_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; import Constants from 'utils/constants.jsx'; @@ -49,6 +50,8 @@ class EditPostModal extends React.Component { return; } + MessageHistoryStore.storeMessageInHistory(updatedPost.message); + if (updatedPost.message.length === 0) { var tempState = this.state; Reflect.deleteProperty(tempState, 'editText'); -- cgit v1.2.3-1-g7c22