diff --git a/app/assets/javascripts/discourse/controllers/topic_bulk_actions_controller.js b/app/assets/javascripts/discourse/controllers/topic_bulk_actions_controller.js index 7d24571b0bb..37245d25a3e 100644 --- a/app/assets/javascripts/discourse/controllers/topic_bulk_actions_controller.js +++ b/app/assets/javascripts/discourse/controllers/topic_bulk_actions_controller.js @@ -10,5 +10,40 @@ Discourse.TopicBulkActionsController = Ember.ArrayController.extend(Discourse.ModalFunctionality, { onShow: function() { this.set('controllers.modal.modalClass', 'topic-bulk-actions-modal'); + }, + + perform: function(operation) { + this.set('loading', true); + + var self = this, + topics = this.get('model'); + return Discourse.Topic.bulkOperation(this.get('model'), operation).then(function(result) { + self.set('loading', false); + if (result && result.topic_ids) { + return result.topic_ids.map(function (t) { + return topics.findBy('id', t); + }); + } + return result; + }).catch(function() { + self.set('loading', false); + }); + }, + + actions: { + showChangeCategory: function() { + this.send('changeBulkTemplate', 'modal/bulk_change_category'); + }, + + changeCategory: function() { + var category = Discourse.Category.findById(parseInt(this.get('newCategoryId'), 10)), + self = this; + this.perform({type: 'change_category', category_id: this.get('newCategoryId')}).then(function(topics) { + topics.forEach(function(t) { + t.set('category', category); + }); + self.send('closeModal'); + }); + } } }); diff --git a/app/assets/javascripts/discourse/models/topic.js b/app/assets/javascripts/discourse/models/topic.js index 3a0cefa1b5a..5513e4c1a2e 100644 --- a/app/assets/javascripts/discourse/models/topic.js +++ b/app/assets/javascripts/discourse/models/topic.js @@ -382,6 +382,16 @@ Discourse.Topic.reopenClass({ promise.reject(new Error("error moving posts topic")); }); return promise; + }, + + bulkOperation: function(topics, operation) { + return Discourse.ajax("/topics/bulk", { + type: 'PUT', + data: { + topic_ids: topics.map(function(t) { return t.get('id'); }), + operation: operation + } + }); } }); diff --git a/app/assets/javascripts/discourse/routes/discovery_route.js b/app/assets/javascripts/discourse/routes/discovery_route.js index 6fbf9e8d838..d83f0378e18 100644 --- a/app/assets/javascripts/discourse/routes/discovery_route.js +++ b/app/assets/javascripts/discourse/routes/discovery_route.js @@ -37,9 +37,14 @@ Discourse.DiscoveryRoute = Discourse.Route.extend({ }); }, + changeBulkTemplate: function(w) { + this.render(w, {into: 'topicBulkActions', outlet: 'bulkOutlet', controller: 'topicBulkActions'}); + }, + showBulkActions: function() { var selected = this.controllerFor('discoveryTopics').get('selected'); Discourse.Route.showModal(this, 'topicBulkActions', selected); + this.send('changeBulkTemplate', 'modal/bulk_actions_buttons'); } } }); diff --git a/app/assets/javascripts/discourse/templates/discovery/topics.js.handlebars b/app/assets/javascripts/discourse/templates/discovery/topics.js.handlebars index c23fcd04941..87b31ce47ad 100644 --- a/app/assets/javascripts/discourse/templates/discovery/topics.js.handlebars +++ b/app/assets/javascripts/discourse/templates/discovery/topics.js.handlebars @@ -11,7 +11,7 @@ {{#if canBulkSelect}} - + {{/if}} {{#sortable-heading sortBy="default" sortOrder=sortOrder}} diff --git a/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars b/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars index d02d7d23e60..0f5281f80c1 100644 --- a/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars +++ b/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars @@ -37,7 +37,7 @@ {{#unless hideCategory}} -{{categoryLink category}} +{{boundCategoryLink category}} {{/unless}} diff --git a/app/assets/javascripts/discourse/templates/modal/bulk_actions_buttons.js.handlebars b/app/assets/javascripts/discourse/templates/modal/bulk_actions_buttons.js.handlebars new file mode 100644 index 00000000000..88c8763eb0b --- /dev/null +++ b/app/assets/javascripts/discourse/templates/modal/bulk_actions_buttons.js.handlebars @@ -0,0 +1 @@ + diff --git a/app/assets/javascripts/discourse/templates/modal/bulk_change_category.js.handlebars b/app/assets/javascripts/discourse/templates/modal/bulk_change_category.js.handlebars new file mode 100644 index 00000000000..6a5fe566a58 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/modal/bulk_change_category.js.handlebars @@ -0,0 +1,10 @@ +

Choose the new category for the topics:

+ +

{{categoryChooser value=newCategoryId}}

+ +{{#if loading}} +
{{i18n loading}}
+{{else}} + +{{/if}} + diff --git a/app/assets/javascripts/discourse/templates/modal/topic_bulk_actions.js.handlebars b/app/assets/javascripts/discourse/templates/modal/topic_bulk_actions.js.handlebars index e0368634dc3..92d3a03e6a3 100644 --- a/app/assets/javascripts/discourse/templates/modal/topic_bulk_actions.js.handlebars +++ b/app/assets/javascripts/discourse/templates/modal/topic_bulk_actions.js.handlebars @@ -1,7 +1,7 @@ diff --git a/app/assets/javascripts/discourse/views/topic_bulk_actions_view.js b/app/assets/javascripts/discourse/views/topic_bulk_actions_view.js index 53eee4ba5bc..a72348415e3 100644 --- a/app/assets/javascripts/discourse/views/topic_bulk_actions_view.js +++ b/app/assets/javascripts/discourse/views/topic_bulk_actions_view.js @@ -8,5 +8,5 @@ **/ Discourse.TopicBulkActionsView = Discourse.ModalBodyView.extend({ templateName: 'modal/topic_bulk_actions', - title: I18n.t('topics.bulk_actions') + title: I18n.t('topics.bulk.actions') }); diff --git a/app/assets/stylesheets/desktop/modal.scss b/app/assets/stylesheets/desktop/modal.scss index 4c7ec965ca3..8445d42a43a 100644 --- a/app/assets/stylesheets/desktop/modal.scss +++ b/app/assets/stylesheets/desktop/modal.scss @@ -251,6 +251,10 @@ p { margin-top: 0; } + .modal-body { + height: 420px; + max-height: 420px; + } } .tabbed-modal { .modal-body { diff --git a/app/assets/stylesheets/desktop/topic-list.scss b/app/assets/stylesheets/desktop/topic-list.scss index d8098c18c32..2881416d344 100644 --- a/app/assets/stylesheets/desktop/topic-list.scss +++ b/app/assets/stylesheets/desktop/topic-list.scss @@ -69,9 +69,6 @@ &:nth-child(even) { background-color: #f8f8f8; } - &.checked { - background-color: $highlight; - } &.archived a { opacity: 0.6; } diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index fc8dd43e99e..f2dec37ced3 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -19,7 +19,8 @@ class TopicsController < ApplicationController :move_posts, :merge_topic, :clear_pin, - :autoclose] + :autoclose, + :bulk] before_filter :consider_user_for_promotion, only: :show @@ -266,6 +267,11 @@ class TopicsController < ApplicationController render 'topics/show', formats: [:rss] end + def bulk + topic_ids = params.require(:topic_ids).map {|t| t.to_i} + render_json_dump topic_ids: topic_ids + end + private def toggle_mute diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2c99efe14fb..0d16de9cde4 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -600,11 +600,13 @@ en: unstar: 'remove this topic from your starred list' topics: - toggle_bulk_select: "toggle bulk selection of topics" - bulk_actions: "Bulk Actions" - selected: - one: "You have selected 1 topic." - other: "You have selected {{count}} topics." + bulk: + toggle: "toggle bulk selection of topics" + actions: "Bulk Actions" + change_category: "Change Category" + selected: + one: "You have selected 1 topic." + other: "You have selected {{count}} topics." none: starred: "You haven't starred any topics yet. To star a topic, click or tap the star next to the title." diff --git a/config/routes.rb b/config/routes.rb index 4b232420f28..f782d0b74e6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -242,6 +242,7 @@ Discourse::Application.routes.draw do post "t" => "topics#create" put "t/:id" => "topics#update" delete "t/:id" => "topics#destroy" + put "topics/bulk" post "topics/timings" get "topics/similar_to" get "topics/created-by/:username" => "list#topics_by", as: "topics_by", constraints: {username: USERNAME_ROUTE_FORMAT}