diff --git a/app/assets/javascripts/discourse/controllers/merge_topic_controller.js b/app/assets/javascripts/discourse/controllers/merge_topic_controller.js index 9d79f00c3..672654877 100644 --- a/app/assets/javascripts/discourse/controllers/merge_topic_controller.js +++ b/app/assets/javascripts/discourse/controllers/merge_topic_controller.js @@ -12,6 +12,7 @@ Discourse.MergeTopicController = Discourse.ObjectController.extend(Discourse.Sel topicController: Em.computed.alias('controllers.topic'), selectedPosts: Em.computed.alias('topicController.selectedPosts'), + selectedReplies: Em.computed.alias('topicController.selectedReplies'), allPostsSelected: Em.computed.alias('topicController.allPostsSelected'), buttonDisabled: function() { @@ -31,10 +32,13 @@ Discourse.MergeTopicController = Discourse.ObjectController.extend(Discourse.Sel if (this.get('allPostsSelected')) { promise = Discourse.Topic.mergeTopic(this.get('id'), this.get('selectedTopicId')); } else { - var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }); + var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }), + replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }); + promise = Discourse.Topic.movePosts(this.get('id'), { destination_topic_id: this.get('selectedTopicId'), - post_ids: postIds + post_ids: postIds, + reply_post_ids: replyPostIds }); } diff --git a/app/assets/javascripts/discourse/controllers/split_topic_controller.js b/app/assets/javascripts/discourse/controllers/split_topic_controller.js index b07b007b0..7d2dd5993 100644 --- a/app/assets/javascripts/discourse/controllers/split_topic_controller.js +++ b/app/assets/javascripts/discourse/controllers/split_topic_controller.js @@ -12,6 +12,7 @@ Discourse.SplitTopicController = Discourse.ObjectController.extend(Discourse.Sel topicController: Em.computed.alias('controllers.topic'), selectedPosts: Em.computed.alias('topicController.selectedPosts'), + selectedReplies: Em.computed.alias('topicController.selectedReplies'), buttonDisabled: function() { if (this.get('saving')) return true; @@ -30,21 +31,23 @@ Discourse.SplitTopicController = Discourse.ObjectController.extend(Discourse.Sel movePostsToNewTopic: function() { this.set('saving', true); - var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }); - var splitTopicController = this; + var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }), + replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }), + self = this; Discourse.Topic.movePosts(this.get('id'), { title: this.get('topicName'), - post_ids: postIds + post_ids: postIds, + reply_post_ids: replyPostIds }).then(function(result) { // Posts moved - splitTopicController.send('closeModal'); - splitTopicController.get('topicController').toggleMultiSelect(); + self.send('closeModal'); + self.get('topicController').toggleMultiSelect(); Em.run.next(function() { Discourse.URL.routeTo(result.url); }); }, function() { // Error moving posts - splitTopicController.flash(I18n.t('topic.split_topic.error')); - splitTopicController.set('saving', false); + self.flash(I18n.t('topic.split_topic.error')); + self.set('saving', false); }); return false; } diff --git a/app/assets/javascripts/discourse/controllers/topic_controller.js b/app/assets/javascripts/discourse/controllers/topic_controller.js index 6dc6c23c6..a1c969011 100644 --- a/app/assets/javascripts/discourse/controllers/topic_controller.js +++ b/app/assets/javascripts/discourse/controllers/topic_controller.js @@ -11,8 +11,15 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected summaryCollapsed: true, needs: ['header', 'modal', 'composer', 'quoteButton'], allPostsSelected: false, - selectedPosts: new Em.Set(), editingTopic: false, + selectedPosts: null, + selectedReplies: null, + + init: function() { + this._super(); + this.set('selectedPosts', new Em.Set()); + this.set('selectedReplies', new Em.Set()); + }, jumpTopDisabled: function() { return (this.get('progressPosition') === 1); @@ -82,18 +89,49 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected return false; }.property('postStream.loaded', 'currentPost', 'postStream.filteredPostsCount'), - selectPost: function(post) { + deselectPost: function(post) { + this.get('selectedPosts').removeObject(post); + + var selectedReplies = this.get('selectedReplies'); + selectedReplies.removeObject(post); + + var selectedReply = selectedReplies.findProperty('post_number', post.get('reply_to_post_number')); + if (selectedReply) { selectedReplies.removeObject(selectedReply); } + + this.set('allPostsSelected', false); + }, + + postSelected: function(post) { + if (this.get('allPostsSelected')) { return true; } + if (this.get('selectedPosts').contains(post)) { return true; } + + if (this.get('selectedReplies').findProperty('post_number', post.get('reply_to_post_number'))) { return true; } + + return false; + }, + + toggledSelectedPost: function(post) { var selectedPosts = this.get('selectedPosts'); - if (selectedPosts.contains(post)) { - selectedPosts.removeObject(post); - this.set('allPostsSelected', false); + if (this.postSelected(post)) { + this.deselectPost(post); + return false; } else { selectedPosts.addObject(post); // If the user manually selects all posts, all posts are selected if (selectedPosts.length === this.get('posts_count')) { - this.set('allPostsSelected'); + this.set('allPostsSelected', true); } + return true; + } + }, + + toggledSelectedPostReplies: function(post) { + var selectedReplies = this.get('selectedReplies'); + if (this.toggledSelectedPost(post)) { + selectedReplies.addObject(post); + } else { + selectedReplies.removeObject(post); } }, @@ -108,6 +146,7 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected deselectAll: function() { this.get('selectedPosts').clear(); + this.get('selectedReplies').clear(); this.set('allPostsSelected', false); }, @@ -177,19 +216,28 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected }, deleteSelected: function() { - var topicController = this; + var self = this; bootbox.confirm(I18n.t("post.delete.confirm", { count: this.get('selectedPostsCount')}), function(result) { if (result) { // If all posts are selected, it's the same thing as deleting the topic - if (topicController.get('allPostsSelected')) { - return topicController.deleteTopic(); + if (self.get('allPostsSelected')) { + return self.deleteTopic(); } - var selectedPosts = topicController.get('selectedPosts'); - Discourse.Post.deleteMany(selectedPosts); - topicController.get('model.postStream').removePosts(selectedPosts); - topicController.toggleMultiSelect(); + var selectedPosts = self.get('selectedPosts'), + selectedReplies = self.get('selectedReplies'), + postStream = self.get('postStream'), + toRemove = new Ember.Set(); + + + Discourse.Post.deleteMany(selectedPosts, selectedReplies); + postStream.get('posts').forEach(function (p) { + if (self.postSelected(p)) { toRemove.addObject(p); } + }); + + postStream.removePosts(toRemove); + self.toggleMultiSelect(); } }); }, diff --git a/app/assets/javascripts/discourse/mixins/selected_posts_count.js b/app/assets/javascripts/discourse/mixins/selected_posts_count.js index e9e6b5496..e30cfdf40 100644 --- a/app/assets/javascripts/discourse/mixins/selected_posts_count.js +++ b/app/assets/javascripts/discourse/mixins/selected_posts_count.js @@ -11,10 +11,15 @@ Discourse.SelectedPostsCount = Em.Mixin.create({ selectedPostsCount: function() { if (this.get('allPostsSelected')) return this.get('posts_count') || this.get('topic.posts_count'); - if (!this.get('selectedPosts')) return 0; + var sum = this.get('selectedPosts.length') || 0; + if (this.get('selectedReplies')) { + this.get('selectedReplies').forEach(function (p) { + sum += p.get('reply_count') || 0; + }); + } - return this.get('selectedPosts.length'); - }.property('selectedPosts.length', 'allPostsSelected') + return sum; + }.property('selectedPosts.length', 'allPostsSelected', 'selectedReplies.length') }); diff --git a/app/assets/javascripts/discourse/models/post.js b/app/assets/javascripts/discourse/models/post.js index ab1e088d2..7e6f56560 100644 --- a/app/assets/javascripts/discourse/models/post.js +++ b/app/assets/javascripts/discourse/models/post.js @@ -328,8 +328,7 @@ Discourse.Post = Discourse.Model.extend({ // Whether to show replies directly below showRepliesBelow: function() { - var reply_count, topic; - reply_count = this.get('reply_count'); + var reply_count = this.get('reply_count'); // We don't show replies if there aren't any if (reply_count === 0) return false; @@ -341,7 +340,7 @@ Discourse.Post = Discourse.Model.extend({ if (reply_count > 1) return true; // If we have *exactly* one reply, we have to consider if it's directly below us - topic = this.get('topic'); + var topic = this.get('topic'); return !topic.isReplyDirectlyBelow(this); }.property('reply_count'), @@ -377,11 +376,12 @@ Discourse.Post.reopenClass({ return result; }, - deleteMany: function(posts) { + deleteMany: function(selectedPosts, selectedReplies) { return Discourse.ajax("/posts/destroy_many", { type: 'DELETE', data: { - post_ids: posts.map(function(p) { return p.get('id'); }) + post_ids: selectedPosts.map(function(p) { return p.get('id'); }), + reply_post_ids: selectedReplies.map(function(p) { return p.get('id'); }) } }); }, diff --git a/app/assets/javascripts/discourse/templates/post.js.handlebars b/app/assets/javascripts/discourse/templates/post.js.handlebars index 7817cd39a..7077f869d 100644 --- a/app/assets/javascripts/discourse/templates/post.js.handlebars +++ b/app/assets/javascripts/discourse/templates/post.js.handlebars @@ -32,7 +32,10 @@