diff --git a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6
index ca6d0386a..19103360d 100644
--- a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6
+++ b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6
@@ -1,8 +1,19 @@
export default Ember.Component.extend({
classNameBindings: ['containerClass'],
- layoutName: 'components/conditional-loading-spinner',
containerClass: function() {
return (this.get('size') === 'small') ? 'inline-spinner' : undefined;
- }.property('size')
+ }.property('size'),
+
+ render: function(buffer) {
+ if (this.get('condition')) {
+ buffer.push('
');
+ } else {
+ return this._super();
+ }
+ },
+
+ _conditionChanged: function() {
+ this.rerender();
+ }.observes('condition')
});
diff --git a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 b/app/assets/javascripts/discourse/controllers/edit-category.js.es6
index 7f0f66549..443d3bcb7 100644
--- a/app/assets/javascripts/discourse/controllers/edit-category.js.es6
+++ b/app/assets/javascripts/discourse/controllers/edit-category.js.es6
@@ -146,9 +146,9 @@ export default ObjectController.extend(ModalFunctionality, {
}).catch(function(error) {
if (error && error.responseText) {
- self.flash($.parseJSON(error.responseText).errors[0]);
+ self.flash($.parseJSON(error.responseText).errors[0], 'error');
} else {
- self.flash(I18n.t('generic_error'));
+ self.flash(I18n.t('generic_error'), 'error');
}
self.set('saving', false);
});
diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6
index 92e06d8f8..db94ea85b 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,24 @@ 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() {
+ // Note we roll back on success here because `update` saves
+ // the properties to the topic.
+ self.rollbackBuffer();
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'));
+ }
+ });
},
toggledSelectedPost: function(post) {
diff --git a/app/assets/javascripts/discourse/helpers/link-domain.js.es6 b/app/assets/javascripts/discourse/helpers/link-domain.js.es6
index b16255d94..ba59b7f50 100644
--- a/app/assets/javascripts/discourse/helpers/link-domain.js.es6
+++ b/app/assets/javascripts/discourse/helpers/link-domain.js.es6
@@ -1,5 +1,6 @@
-Handlebars.registerHelper('link-domain', function(property, options) {
- var link = Em.get(this, property, options);
+import registerUnbound from 'discourse/helpers/register-unbound';
+
+registerUnbound('link-domain', function(link) {
if (link) {
var internal = Em.get(link, 'internal'),
hasTitle = (!Em.isEmpty(Em.get(link, 'title')));
diff --git a/app/assets/javascripts/discourse/lib/emoji/emoji-autocomplete.js b/app/assets/javascripts/discourse/lib/emoji/emoji-autocomplete.js
deleted file mode 100644
index 48abf219f..000000000
--- a/app/assets/javascripts/discourse/lib/emoji/emoji-autocomplete.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// TODO: Make this a proper ES6 import
-var ComposerView = require('discourse/views/composer').default;
-
-ComposerView.on("initWmdEditor", function(){
- if (!Discourse.SiteSettings.enable_emoji) { return; }
-
- var template = Handlebars.compile(
- "" +
- "
" +
- "{{#each options}}" +
- "- " +
- "
{{code}}" +
- " " +
- "{{/each}}" +
- "
" +
- "
"
- );
-
- $('#wmd-input').autocomplete({
- template: template,
- key: ":",
- transformComplete: function(v){ return v.code + ":"; },
- dataSource: function(term){
- return new Ember.RSVP.Promise(function(resolve) {
- var full = ":" + term;
- term = term.toLowerCase();
-
- if (term === "") {
- return resolve(["smile", "smiley", "wink", "sunny", "blush"]);
- }
-
- if (Discourse.Emoji.translations[full]) {
- return resolve([Discourse.Emoji.translations[full]]);
- }
-
- var options = Discourse.Emoji.search(term, {maxResults: 5});
-
- return resolve(options);
- }).then(function(list) {
- return list.map(function(i) {
- return {code: i, src: Discourse.Emoji.urlFor(i)};
- });
- });
- }
- });
-});
diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js
index 3f0732328..3f8bb6edb 100644
--- a/app/assets/javascripts/discourse/models/category.js
+++ b/app/assets/javascripts/discourse/models/category.js
@@ -58,6 +58,7 @@ Discourse.Category = Discourse.Model.extend({
return Discourse.ajax(url, {
data: {
name: this.get('name'),
+ slug: this.get('slug'),
color: this.get('color'),
text_color: this.get('text_color'),
secure: this.get('secure'),
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/export_csv.js b/app/assets/javascripts/discourse/models/export_csv.js
index be678c392..9d5c00d89 100644
--- a/app/assets/javascripts/discourse/models/export_csv.js
+++ b/app/assets/javascripts/discourse/models/export_csv.js
@@ -30,7 +30,7 @@ Discourse.ExportCsv.reopenClass({
@method export_user_list
**/
exportUserList: function() {
- return Discourse.ajax("/export_csv/export_entity.json", {data: {entity_type: 'admin', entity: 'user'}});
+ return Discourse.ajax("/export_csv/export_entity.json", {data: {entity_type: 'admin', entity: 'user_list'}});
},
/**
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..6df0bbff5 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,29 @@ Discourse.Topic.reopenClass({
}
},
+ update: function(topic, props) {
+ props = JSON.parse(JSON.stringify(props)) || {};
+
+ // Annoyingly, empty arrays are not sent across the wire. This
+ // allows us to make a distinction between arrays that were not
+ // sent and arrays that we specifically want to be empty.
+ Object.keys(props).forEach(function(k) {
+ var v = props[k];
+ if (v instanceof Array && v.length === 0) {
+ props[k + '_empty_array'] = true;
+ }
+ });
+
+ 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/components/conditional-loading-spinner.hbs b/app/assets/javascripts/discourse/templates/components/conditional-loading-spinner.hbs
deleted file mode 100644
index d1d27ae58..000000000
--- a/app/assets/javascripts/discourse/templates/components/conditional-loading-spinner.hbs
+++ /dev/null
@@ -1,5 +0,0 @@
-{{#if condition}}
-
-{{else}}
- {{yield}}
-{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/topic-map.hbs b/app/assets/javascripts/discourse/templates/components/topic-map.hbs
index 3e3a73c26..bf572caa3 100644
--- a/app/assets/javascripts/discourse/templates/components/topic-map.hbs
+++ b/app/assets/javascripts/discourse/templates/components/topic-map.hbs
@@ -82,7 +82,7 @@
{{#if showAllLinksControls}}
{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/emoji-selector-autocomplete.raw.hbs b/app/assets/javascripts/discourse/templates/emoji-selector-autocomplete.raw.hbs
new file mode 100644
index 000000000..ed2e39c7a
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/emoji-selector-autocomplete.raw.hbs
@@ -0,0 +1,9 @@
+
+
+ {{#each options}}
+ -
+
{{code}}
+
+ {{/each}}
+
+
diff --git a/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs b/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs
index 096441c01..7931c5ef5 100644
--- a/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs
+++ b/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs
@@ -1,7 +1,13 @@