diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6
index 92e06d8f8..f94571ce9 100644
--- a/app/assets/javascripts/discourse/controllers/topic.js.es6
+++ b/app/assets/javascripts/discourse/controllers/topic.js.es6
@@ -1,7 +1,8 @@
import ObjectController from 'discourse/controllers/object';
+import BufferedContent from 'discourse/mixins/buffered-content';
import { spinnerHTML } from 'discourse/helpers/loading-spinner';
-export default ObjectController.extend(Discourse.SelectedPostsCount, {
+export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedContent, {
multiSelect: false,
needs: ['header', 'modal', 'composer', 'quote-button', 'search', 'topic-progress', 'application'],
allPostsSelected: false,
@@ -235,11 +236,6 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, {
this.set('allPostsSelected', false);
},
- /**
- Toggle a participant for filtering
-
- @method toggleParticipant
- **/
toggleParticipant: function(user) {
this.get('postStream').toggleParticipant(Em.get(user, 'username'));
},
@@ -247,17 +243,13 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, {
editTopic: function() {
if (!this.get('details.can_edit')) return false;
- this.setProperties({
- editingTopic: true,
- newTitle: this.get('title'),
- newCategoryId: this.get('category_id')
- });
+ this.set('editingTopic', true);
return false;
},
- // close editing mode
cancelEditingTopic: function() {
this.set('editingTopic', false);
+ this.rollbackBuffer();
},
toggleMultiSelect: function() {
@@ -265,39 +257,25 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, {
},
finishedEditingTopic: function() {
- if (this.get('editingTopic')) {
+ if (!this.get('editingTopic')) { return; }
- var topic = this.get('model');
+ // save the modifications
+ var self = this,
+ props = this.get('buffered.buffer');
- // Topic title hasn't been sanitized yet, so the template shouldn't trust it.
- this.set('topicSaving', true);
-
- // manually update the titles & category
- var backup = topic.setPropertiesBackup({
- title: this.get('newTitle'),
- category_id: parseInt(this.get('newCategoryId'), 10),
- fancy_title: this.get('newTitle')
- });
-
- // save the modifications
- var self = this;
- topic.save().then(function(result){
- // update the title if it has been changed (cleaned up) server-side
- topic.setProperties(Em.getProperties(result.basic_topic, 'title', 'fancy_title'));
- self.set('topicSaving', false);
- }, function(error) {
- self.setProperties({ editingTopic: true, topicSaving: false });
- topic.setProperties(backup);
- if (error && error.responseText) {
- bootbox.alert($.parseJSON(error.responseText).errors[0]);
- } else {
- bootbox.alert(I18n.t('generic_error'));
- }
- });
-
- // close editing mode
+ Discourse.Topic.update(this.get('model'), props).then(function() {
self.set('editingTopic', false);
- }
+ }).catch(function(error) {
+ if (error && error.responseText) {
+ bootbox.alert($.parseJSON(error.responseText).errors[0]);
+ } else {
+ bootbox.alert(I18n.t('generic_error'));
+ }
+ }).finally(function() {
+ // Note we even roll back on success here because `update` saves
+ // the properties to the topic.
+ self.rollbackBuffer();
+ });
},
toggledSelectedPost: function(post) {
diff --git a/app/assets/javascripts/discourse/models/composer.js b/app/assets/javascripts/discourse/models/composer.js
index 2d9523cac..6b166a8ab 100644
--- a/app/assets/javascripts/discourse/models/composer.js
+++ b/app/assets/javascripts/discourse/models/composer.js
@@ -463,13 +463,10 @@ Discourse.Composer = Discourse.Model.extend({
// Update the title if we've changed it
if (this.get('title') && post.get('post_number') === 1) {
- var topic = this.get('topic');
- topic.setProperties({
+ Discourse.Topic.update(this.get('topic'), {
title: this.get('title'),
- fancy_title: Handlebars.Utils.escapeExpression(this.get('title')),
- category_id: parseInt(this.get('categoryId'), 10)
+ category_id: this.get('categoryId')
});
- topic.save();
}
post.setProperties({
diff --git a/app/assets/javascripts/discourse/models/model.js b/app/assets/javascripts/discourse/models/model.js
index 084c7c72a..0c2619c7c 100644
--- a/app/assets/javascripts/discourse/models/model.js
+++ b/app/assets/javascripts/discourse/models/model.js
@@ -1,12 +1,4 @@
-Discourse.Model = Ember.Object.extend(Discourse.Presence, {
- // Like `setProperties` but returns the original values in case
- // we want to roll back
- setPropertiesBackup: function(obj) {
- var backup = this.getProperties(Ember.keys(obj));
- this.setProperties(obj);
- return backup;
- }
-});
+Discourse.Model = Ember.Object.extend(Discourse.Presence);
Discourse.Model.reopenClass({
extractByKey: function(collection, klass) {
diff --git a/app/assets/javascripts/discourse/models/topic.js b/app/assets/javascripts/discourse/models/topic.js
index 817376fbf..59cfbf9df 100644
--- a/app/assets/javascripts/discourse/models/topic.js
+++ b/app/assets/javascripts/discourse/models/topic.js
@@ -202,23 +202,6 @@ Discourse.Topic = Discourse.Model.extend({
});
},
- // Save any changes we've made to the model
- save: function() {
- // Don't save unless we can
- if (!this.get('details.can_edit')) return;
-
- var data = { title: this.get('title') };
-
- if(this.get('category')){
- data.category_id = this.get('category.id');
- }
-
- return Discourse.ajax(this.get('url'), {
- type: 'PUT',
- data: data
- });
- },
-
/**
Invite a user to this topic
@@ -373,6 +356,17 @@ Discourse.Topic.reopenClass({
}
},
+ update: function(topic, props) {
+ return Discourse.ajax(topic.get('url'), { type: 'PUT', data: props }).then(function(result) {
+
+ // The title can be cleaned up server side
+ props.title = result.basic_topic.title;
+ props.fancy_title = result.basic_topic.fancy_title;
+
+ topic.setProperties(props);
+ });
+ },
+
create: function() {
var result = this._super.apply(this, arguments);
this.createActionSummary(result);
diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs
index f724e92ff..3deaa666d 100644
--- a/app/assets/javascripts/discourse/templates/topic.hbs
+++ b/app/assets/javascripts/discourse/templates/topic.hbs
@@ -16,11 +16,11 @@
{{#if editingTopic}}
{{#if isPrivateMessage}}
{{fa-icon envelope}}
- {{autofocus-text-field id='edit-title' value=newTitle maxLength=maxTitleLength}}
+ {{autofocus-text-field id='edit-title' value=buffered.title maxLength=maxTitleLength}}
{{else}}
- {{autofocus-text-field id='edit-title' value=newTitle maxLength=maxTitleLength}}
+ {{autofocus-text-field id='edit-title' value=buffered.title maxLength=maxTitleLength}}
- {{category-chooser valueAttribute="id" value=newCategoryId source=category_id}}
+ {{category-chooser valueAttribute="id" value=buffered.category_id source=buffered.category_id}}
{{/if}}
@@ -34,11 +34,7 @@
{{#if details.loaded}}
{{topic-status topic=model}}
- {{#if topicSaving}}
- {{fancy_title}}
- {{else}}
- {{{fancy_title}}}
- {{/if}}
+ {{{fancy_title}}}
{{/if}}
diff --git a/app/assets/javascripts/discourse/views/category-chooser.js.es6 b/app/assets/javascripts/discourse/views/category-chooser.js.es6
index b0bda8b33..46a82d012 100644
--- a/app/assets/javascripts/discourse/views/category-chooser.js.es6
+++ b/app/assets/javascripts/discourse/views/category-chooser.js.es6
@@ -7,6 +7,7 @@ export default ComboboxView.extend({
overrideWidths: true,
dataAttributes: ['id', 'description_text'],
valueBinding: Ember.Binding.oneWay('source'),
+ castInteger: true,
content: function() {
var scopedCategoryId = this.get('scopedCategoryId');
diff --git a/app/assets/javascripts/discourse/views/combo-box.js.es6 b/app/assets/javascripts/discourse/views/combo-box.js.es6
index 24d4b2d28..186683673 100644
--- a/app/assets/javascripts/discourse/views/combo-box.js.es6
+++ b/app/assets/javascripts/discourse/views/combo-box.js.es6
@@ -63,7 +63,7 @@ export default Discourse.View.extend({
this.rerender();
}.observes('content.@each'),
- didInsertElement: function() {
+ _initializeCombo: function() {
var $elem = this.$(),
self = this;
@@ -75,10 +75,15 @@ export default Discourse.View.extend({
$elem.select2({formatResult: this.template, minimumResultsForSearch: 5, width: 'resolve'});
+ var castInteger = this.get('castInteger');
$elem.on("change", function (e) {
- self.set('value', $(e.target).val());
+ var val = $(e.target).val();
+ if (val.length && castInteger) {
+ val = parseInt(val, 10);
+ }
+ self.set('value', val);
});
- },
+ }.on('didInsertElement'),
willClearRender: function() {
var elementId = "s2id_" + this.$().attr('id');
diff --git a/test/javascripts/controllers/topic-test.js.es6 b/test/javascripts/controllers/topic-test.js.es6
index cf853c0d3..5b9bb5135 100644
--- a/test/javascripts/controllers/topic-test.js.es6
+++ b/test/javascripts/controllers/topic-test.js.es6
@@ -28,8 +28,8 @@ test("editingMode", function() {
topicController.set('model.details.can_edit', true);
topicController.send('editTopic');
ok(topicController.get('editingTopic'), "calling editTopic enables editing if the user can edit");
- equal(topicController.get('newTitle'), topic.get('title'));
- equal(topicController.get('newCategoryId'), topic.get('category_id'));
+ equal(topicController.get('buffered.title'), topic.get('title'));
+ equal(topicController.get('buffered.category_id'), topic.get('category_id'));
topicController.send('cancelEditingTopic');
ok(!topicController.get('editingTopic'), "cancelling edit mode reverts the property value");