diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index d38a6798f9..681ca252ff 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -68,6 +68,9 @@ module.exports = React.createClass({ post.channel_id = this.state.channel_id; post.filenames = this.state.previews; + post.root_id = this.state.rootId; + post.parent_id = this.state.parentId; + client.createPost(post, ChannelStore.getCurrent(), function(data) { PostStore.storeDraft(data.channel_id, data.user_id, null); @@ -92,6 +95,17 @@ module.exports = React.createClass({ } $(".post-list-holder-by-time").perfectScrollbar('update'); + + if (this.state.rootId || this.state.parentId) { + this.setState({rootId: "", parentId: ""}); + + // clear the active thread since we've now sent our message + AppDispatcher.handleViewAction({ + type: ActionTypes.RECEIVED_ACTIVE_THREAD_CHANGED, + root_id: "", + parent_id: "" + }); + } }, componentDidUpdate: function() { this.resizePostHolder(); @@ -112,6 +126,60 @@ module.exports = React.createClass({ handleUserInput: function(messageText) { this.resizePostHolder(); this.setState({messageText: messageText}); + + // look to see if the message begins with any carets to indicate that it's a reply + var replyMatch = messageText.match(/^\^+/g); + if (replyMatch) { + // the number of carets indicates how many message threads back we're replying to + var caretCount = replyMatch[0].length; + + var posts = PostStore.getCurrentPosts(); + + var rootId = ""; + + // find the nth most recent post that isn't a comment on another (ie it has no parent) where n is caretCount + for (var i = 0; i < posts.order.length; i++) { + var postId = posts.order[i]; + + if (posts.posts[postId].parent_id === "") { + if (caretCount == 1) { + rootId = postId; + break; + } else { + caretCount -= 1; + } + } + } + + if (rootId) { + // set the parent id to match the root id so that we're replying to the first post in the thread + var parentId = rootId; + + // alert the post list so that it can display the active thread + AppDispatcher.handleViewAction({ + type: ActionTypes.RECEIVED_ACTIVE_THREAD_CHANGED, + root_id: rootId, + parent_id: parentId + }); + + // save these so that we don't need to recalculate them when we send this post + this.setState({rootId: rootId, parentId: parentId}); + } else { + // we couldn't find a post to respond to + this.setState({rootId: "", parentId: ""}); + } + } else { + if (this.state.rootId || this.state.parentId) { + this.setState({rootId: "", parentId: ""}); + + AppDispatcher.handleViewAction({ + type: ActionTypes.RECEIVED_ACTIVE_THREAD_CHANGED, + root_id: "", + parent_id: "" + }); + } + } + var draft = PostStore.getCurrentDraft(); if (!draft) { draft = {} diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx index e72a2d001c..e3586ecded 100644 --- a/web/react/components/post.jsx +++ b/web/react/components/post.jsx @@ -83,7 +83,7 @@ module.exports = React.createClass({ : null } -
+
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx index c058455bae..0fe668aeff 100644 --- a/web/react/components/post_list.jsx +++ b/web/react/components/post_list.jsx @@ -22,7 +22,8 @@ function getStateFromStores() { return { post_list: PostStore.getCurrentPosts(), - channel: channel + channel: channel, + activeThreadRootId: "" }; } @@ -51,6 +52,7 @@ module.exports = React.createClass({ ChannelStore.addChangeListener(this._onChange); UserStore.addStatusesChangeListener(this._onTimeChange); SocketStore.addChangeListener(this._onSocketChange); + PostStore.addActiveThreadChangedListener(this._onActiveThreadChanged); $(".post-list-holder-by-time").perfectScrollbar(); @@ -131,6 +133,7 @@ module.exports = React.createClass({ ChannelStore.removeChangeListener(this._onChange); UserStore.removeStatusesChangeListener(this._onTimeChange); SocketStore.removeChangeListener(this._onSocketChange); + PostStore.removeActiveThreadChangedListener(this._onActiveThreadChanged); $('body').off('click.userpopover'); }, resize: function() { @@ -228,6 +231,9 @@ module.exports = React.createClass({ this.refs[id].forceUpdateInfo(); } }, + _onActiveThreadChanged: function(rootId, parentId) { + this.setState({"activeThreadRootId": rootId}); + }, getMorePosts: function(e) { e.preventDefault(); @@ -419,7 +425,14 @@ module.exports = React.createClass({ // it is the last comment if it is last post in the channel or the next post has a different root post var isLastComment = utils.isComment(post) && (i === 0 || posts[order[i-1]].root_id != post.root_id); - var postCtl = ; + // check if this is part of the thread that we're currently replying to + var isActiveThread = this.state.activeThreadRootId && (post.id === this.state.activeThreadRootId || post.root_id === this.state.activeThreadRootId); + + var postCtl = ( + + ); currentPostDay = utils.getDateForUnixTicks(post.create_at); if (currentPostDay.toDateString() != previousPostDay.toDateString()) { diff --git a/web/sass-files/sass/partials/_post.scss b/web/sass-files/sass/partials/_post.scss index 481ed63a52..87c7a427c2 100644 --- a/web/sass-files/sass/partials/_post.scss +++ b/web/sass-files/sass/partials/_post.scss @@ -322,6 +322,10 @@ body.ios { max-width: 100%; @include legacy-pie-clearfix; } + &.active-thread__content { + // HARRISON remove me + color: blue; + } } .post-image__columns { @include legacy-pie-clearfix; @@ -437,4 +441,4 @@ body.ios { width: 40px; } } -} \ No newline at end of file +}