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");