diff --git a/.gitignore b/.gitignore index 4268486d7b..25f45fa7f7 100644 --- a/.gitignore +++ b/.gitignore @@ -30,9 +30,9 @@ config/discourse.pill config/discourse.conf # Ignore the default SQLite database and db dumps +*.sql +*.sql.gz /db/*.sqlite3 -/dbs/*.sql -/dbs/*.sql.gz /db/structure.sql # Ignore all logfiles and tempfiles. diff --git a/Gemfile.lock b/Gemfile.lock index 8fd86089c4..48c8b97299 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -147,7 +147,7 @@ GEM librarian (0.1.2) highline thor (~> 0.15) - libv8 (5.0.71.48.3) + libv8 (5.3.332.38.1) listen (0.7.3) logster (1.2.5) loofah (2.0.3) @@ -162,8 +162,8 @@ GEM method_source (0.8.2) mime-types (2.99.2) mini_portile2 (2.1.0) - mini_racer (0.1.3) - libv8 (~> 5.0) + mini_racer (0.1.7) + libv8 (~> 5.3) minitest (5.9.1) mocha (1.1.0) metaclass (~> 0.0.1) @@ -501,4 +501,4 @@ DEPENDENCIES unicorn BUNDLED WITH - 1.13.4 + 1.13.6 diff --git a/app/assets/javascripts/admin/components/ace-editor.js.es6 b/app/assets/javascripts/admin/components/ace-editor.js.es6 index f9be641640..561ebc6d8a 100644 --- a/app/assets/javascripts/admin/components/ace-editor.js.es6 +++ b/app/assets/javascripts/admin/components/ace-editor.js.es6 @@ -1,8 +1,9 @@ /* global ace:true */ import loadScript from 'discourse/lib/load-script'; import { escapeExpression } from 'discourse/lib/utilities'; +import { bufferedRender } from 'discourse-common/lib/buffered-render'; -export default Ember.Component.extend({ +export default Ember.Component.extend(bufferedRender({ mode: 'css', classNames: ['ace-wrapper'], _editor: null, @@ -14,7 +15,7 @@ export default Ember.Component.extend({ } }.observes('content'), - render(buffer) { + buildBuffer(buffer) { buffer.push("
");
@@ -40,14 +50,8 @@ export default Ember.View.extend({
buffer.push("" + I18n.t("admin.backups.logs.none") + "
");
}
// add a loading indicator
- if (this.get("controller.status.model.isOperationRunning")) {
+ if (this.get("status.isOperationRunning")) {
buffer.push(renderSpinner('small'));
}
- },
-
- _forceScrollToBottom: function() {
- const $div = this.$()[0];
- $div.scrollTop = $div.scrollHeight;
- }.on("didInsertElement")
-
-});
+ }
+}));
diff --git a/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6
index c8438a65b7..d176b5a40a 100644
--- a/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6
+++ b/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6
@@ -1,8 +1,8 @@
import computed from 'ember-addons/ember-computed-decorators';
-import StringBuffer from 'discourse/mixins/string-buffer';
import { iconHTML } from 'discourse-common/helpers/fa-icon';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
classes: ["text-muted", "text-danger", "text-successful"],
icons: ["circle-o", "times-circle", "circle"],
@@ -21,8 +21,8 @@ export default Ember.Component.extend(StringBuffer, {
return classes[statusId - 1];
},
- renderString(buffer) {
+ buildBuffer(buffer) {
buffer.push(iconHTML(this.get('icon'), { class: this.get('class') }));
buffer.push(I18n.t(`admin.web_hooks.delivery_status.${this.get('status.name')}`));
}
-});
+}));
diff --git a/app/assets/javascripts/admin/components/resumable-upload.js.es6 b/app/assets/javascripts/admin/components/resumable-upload.js.es6
index ea2f02cfa0..73a46eded3 100644
--- a/app/assets/javascripts/admin/components/resumable-upload.js.es6
+++ b/app/assets/javascripts/admin/components/resumable-upload.js.es6
@@ -1,3 +1,5 @@
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
+
/*global Resumable:true */
/**
@@ -10,7 +12,7 @@
uploadText="UPLOAD"
}}
**/
-const ResumableUploadComponent = Ember.Component.extend(Discourse.StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
tagName: "button",
classNames: ["btn", "ru"],
classNameBindings: ["isUploading"],
@@ -36,9 +38,9 @@ const ResumableUploadComponent = Ember.Component.extend(Discourse.StringBuffer,
}
}.property("isUploading", "progress"),
- renderString: function(buffer) {
- var icon = this.get("isUploading") ? "times" : "upload";
- buffer.push("");
+ buildBuffer(buffer) {
+ const icon = this.get("isUploading") ? "times" : "upload";
+ buffer.push(``);
buffer.push("" + this.get("text") + "");
buffer.push("");
},
@@ -117,6 +119,4 @@ const ResumableUploadComponent = Ember.Component.extend(Discourse.StringBuffer,
}
}.on("willDestroyElement")
-});
-
-export default ResumableUploadComponent;
+}));
diff --git a/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 b/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6
index 82366d3bd7..529538263c 100644
--- a/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6
@@ -1,66 +1,30 @@
import ApiKey from 'admin/models/api-key';
-/**
- This controller supports the interface for dealing with API keys
-
- @class AdminApiController
- @extends Ember.ArrayController
- @namespace Discourse
- @module Discourse
-**/
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
actions: {
- /**
- Generates a master api key
-
- @method generateMasterKey
- **/
- generateMasterKey: function() {
- var self = this;
- ApiKey.generateMasterKey().then(function (key) {
- self.get('model').pushObject(key);
- });
+ generateMasterKey() {
+ ApiKey.generateMasterKey().then(key => this.get('model').pushObject(key));
},
- /**
- Creates an API key instance with internal user object
-
- @method regenerateKey
- @param {ApiKey} key the key to regenerate
- **/
- regenerateKey: function(key) {
- bootbox.confirm(I18n.t("admin.api.confirm_regen"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
+ regenerateKey(key) {
+ bootbox.confirm(I18n.t("admin.api.confirm_regen"), I18n.t("no_value"), I18n.t("yes_value"), result => {
if (result) {
key.regenerate();
}
});
},
- /**
- Revokes an API key
-
- @method revokeKey
- @param {ApiKey} key the key to revoke
- **/
- revokeKey: function(key) {
- var self = this;
- bootbox.confirm(I18n.t("admin.api.confirm_revoke"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
+ revokeKey(key) {
+ bootbox.confirm(I18n.t("admin.api.confirm_revoke"), I18n.t("no_value"), I18n.t("yes_value"), result => {
if (result) {
- key.revoke().then(function() {
- self.get('model').removeObject(key);
- });
+ key.revoke().then(() => this.get('model').removeObject(key));
}
});
}
},
- /**
- Has a master key already been generated?
-
- @property hasMasterKey
- @type {Boolean}
- **/
+ // Has a master key already been generated?
hasMasterKey: function() {
return !!this.get('model').findBy('user', null);
}.property('model.[]')
diff --git a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6
index 98f76405a2..605ebe83af 100644
--- a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6
@@ -1,19 +1,20 @@
import { ajax } from 'discourse/lib/ajax';
-export default Ember.ArrayController.extend({
- needs: ["adminBackups"],
- status: Ember.computed.alias("controllers.adminBackups"),
+
+export default Ember.Controller.extend({
+ adminBackups: Ember.inject.controller(),
+ status: Ember.computed.alias('adminBackups.model'),
uploadLabel: function() { return I18n.t("admin.backups.upload.label"); }.property(),
restoreTitle: function() {
- if (!this.get('status.model.allowRestore')) {
+ if (!this.get('status.allowRestore')) {
return "admin.backups.operations.restore.is_disabled";
- } else if (this.get("status.model.isOperationRunning")) {
+ } else if (this.get("status.isOperationRunning")) {
return "admin.backups.operations.is_running";
} else {
return "admin.backups.operations.restore.title";
}
- }.property("status.model.{allowRestore,isOperationRunning}"),
+ }.property("status.{allowRestore,isOperationRunning}"),
actions: {
diff --git a/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6
index 1b3d90346a..38bdd6f571 100644
--- a/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6
@@ -1,4 +1,5 @@
-export default Ember.ArrayController.extend({
- needs: ["adminBackups"],
- status: Em.computed.alias("controllers.adminBackups")
+export default Ember.Controller.extend({
+ logs: [],
+ adminBackups: Ember.inject.controller(),
+ status: Em.computed.alias("adminBackups.model")
});
diff --git a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6
index 5ec2cb4541..7d11fc8622 100644
--- a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6
@@ -3,14 +3,14 @@ import BufferedContent from 'discourse/mixins/buffered-content';
import { propertyNotEqual } from 'discourse/lib/computed';
export default Ember.Controller.extend(BufferedContent, {
- needs: ['admin-badges'],
+ adminBadges: Ember.inject.controller(),
saving: false,
savingStatus: '',
- badgeTypes: Em.computed.alias('controllers.admin-badges.badgeTypes'),
- badgeGroupings: Em.computed.alias('controllers.admin-badges.badgeGroupings'),
- badgeTriggers: Em.computed.alias('controllers.admin-badges.badgeTriggers'),
- protectedSystemFields: Em.computed.alias('controllers.admin-badges.protectedSystemFields'),
+ badgeTypes: Ember.computed.alias('adminBadges.badgeTypes'),
+ badgeGroupings: Ember.computed.alias('adminBadges.badgeGroupings'),
+ badgeTriggers: Ember.computed.alias('adminBadges.badgeTriggers'),
+ protectedSystemFields: Ember.computed.alias('adminBadges.protectedSystemFields'),
readOnly: Ember.computed.alias('buffered.system'),
showDisplayName: propertyNotEqual('name', 'displayName'),
@@ -30,16 +30,15 @@ export default Ember.Controller.extend(BufferedContent, {
}.observes('model.id'),
actions: {
- save: function() {
+ save() {
if (!this.get('saving')) {
- var fields = ['allow_title', 'multiple_grant',
- 'listable', 'auto_revoke',
- 'enabled', 'show_posts',
- 'target_posts', 'name', 'description',
- 'long_description',
- 'icon', 'image', 'query', 'badge_grouping_id',
- 'trigger', 'badge_type_id'],
- self = this;
+ let fields = ['allow_title', 'multiple_grant',
+ 'listable', 'auto_revoke',
+ 'enabled', 'show_posts',
+ 'target_posts', 'name', 'description',
+ 'long_description',
+ 'icon', 'image', 'query', 'badge_grouping_id',
+ 'trigger', 'badge_type_id'];
if (this.get('buffered.system')){
var protectedFields = this.get('protectedSystemFields');
@@ -51,54 +50,55 @@ export default Ember.Controller.extend(BufferedContent, {
this.set('saving', true);
this.set('savingStatus', I18n.t('saving'));
- var boolFields = ['allow_title', 'multiple_grant',
- 'listable', 'auto_revoke',
- 'enabled', 'show_posts',
- 'target_posts' ];
+ const boolFields = ['allow_title', 'multiple_grant',
+ 'listable', 'auto_revoke',
+ 'enabled', 'show_posts',
+ 'target_posts' ];
- var data = {},
- buffered = this.get('buffered');
+ const data = {};
+ const buffered = this.get('buffered');
fields.forEach(function(field){
var d = buffered.get(field);
if (_.include(boolFields, field)) { d = !!d; }
data[field] = d;
});
- var newBadge = !this.get('id'),
- model = this.get('model');
- this.get('model').save(data).then(function() {
+ const newBadge = !this.get('id');
+ const model = this.get('model');
+ this.get('model').save(data).then(() => {
if (newBadge) {
- var adminBadgesController = self.get('controllers.admin-badges');
- if (!adminBadgesController.contains(model)) adminBadgesController.pushObject(model);
- self.transitionToRoute('adminBadges.show', model.get('id'));
+ const adminBadges = this.get('adminBadges.model');
+ if (!adminBadges.contains(model)) {
+ adminBadges.pushObject(model);
+ }
+ this.transitionToRoute('adminBadges.show', model.get('id'));
} else {
- self.commitBuffer();
- self.set('savingStatus', I18n.t('saved'));
+ this.commitBuffer();
+ this.set('savingStatus', I18n.t('saved'));
}
- }).catch(popupAjaxError).finally(function() {
- self.set('saving', false);
- self.set('savingStatus', '');
+ }).catch(popupAjaxError).finally(() => {
+ this.set('saving', false);
+ this.set('savingStatus', '');
});
}
},
- destroy: function() {
- var self = this,
- adminBadgesController = this.get('controllers.admin-badges'),
- model = this.get('model');
+ destroy() {
+ const adminBadges = this.get('adminBadges.model');
+ const model = this.get('model');
if (!model.get('id')) {
- self.transitionToRoute('adminBadges.index');
+ this.transitionToRoute('adminBadges.index');
return;
}
- return bootbox.confirm(I18n.t("admin.badges.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
+ return bootbox.confirm(I18n.t("admin.badges.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => {
if (result) {
- model.destroy().then(function() {
- adminBadgesController.removeObject(model);
- self.transitionToRoute('adminBadges.index');
- }).catch(function() {
+ model.destroy().then(() => {
+ adminBadges.removeObject(model);
+ this.transitionToRoute('adminBadges.index');
+ }).catch(() => {
bootbox.alert(I18n.t('generic_error'));
});
}
diff --git a/app/assets/javascripts/admin/controllers/admin-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges.js.es6
index 24c4c05139..77c79b724a 100644
--- a/app/assets/javascripts/admin/controllers/admin-badges.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-badges.js.es6
@@ -1 +1 @@
-export default Ember.ArrayController.extend();
+export default Ember.Controller.extend();
diff --git a/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6
index 4a6a58021b..ae253aec84 100644
--- a/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6
@@ -1,4 +1,4 @@
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
onlyOverridden: false,
baseColorScheme: function() {
@@ -13,8 +13,8 @@ export default Ember.ArrayController.extend({
return baseColorsHash;
}.property('baseColorScheme'),
- removeSelected: function() {
- this.removeObject(this.get('selectedItem'));
+ removeSelected() {
+ this.get('model').removeObject(this.get('selectedItem'));
this.set('selectedItem', null);
},
@@ -26,8 +26,7 @@ export default Ember.ArrayController.extend({
return;
}
- var matches = Em.A();
-
+ const matches = [];
_.each(this.get('selectedItem.colors'), function(color){
if (color.get('overridden')) matches.pushObject(color);
});
@@ -58,10 +57,10 @@ export default Ember.ArrayController.extend({
this.filterContent();
},
- newColorScheme: function() {
- var newColorScheme = Em.copy(this.get('baseColorScheme'), true);
+ newColorScheme() {
+ const newColorScheme = Em.copy(this.get('baseColorScheme'), true);
newColorScheme.set('name', I18n.t('admin.customize.colors.new_name'));
- this.pushObject(newColorScheme);
+ this.get('model').pushObject(newColorScheme);
this.send('selectColorScheme', newColorScheme);
this.set('onlyOverridden', false);
},
@@ -86,10 +85,10 @@ export default Ember.ArrayController.extend({
this.updateEnabled();
},
- copy: function(colorScheme) {
+ copy(colorScheme) {
var newColorScheme = Em.copy(colorScheme, true);
newColorScheme.set('name', I18n.t('admin.customize.colors.copy_name_prefix') + ' ' + colorScheme.get('name'));
- this.pushObject(newColorScheme);
+ this.get('model').pushObject(newColorScheme);
this.send('selectColorScheme', newColorScheme);
},
diff --git a/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6
index 03c855a969..47cf280ae6 100644
--- a/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6
@@ -33,7 +33,7 @@ export default Ember.Controller.extend(activeSections, {
return !this.get('model.changed') || this.get('model.isSaving');
}.property('model.changed', 'model.isSaving'),
- needs: ['adminCustomizeCssHtml'],
+ adminCustomizeCssHtml: Ember.inject.controller(),
undoPreviewUrl: url('/?preview-style='),
defaultStyleUrl: url('/?preview-style=default'),
@@ -44,13 +44,12 @@ export default Ember.Controller.extend(activeSections, {
},
destroy() {
- const self = this;
- return bootbox.confirm(I18n.t("admin.customize.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
+ return bootbox.confirm(I18n.t("admin.customize.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => {
if (result) {
- const model = self.get('model');
- model.destroyRecord().then(function() {
- self.get('controllers.adminCustomizeCssHtml').get('model').removeObject(model);
- self.transitionToRoute('adminCustomizeCssHtml');
+ const model = this.get('model');
+ model.destroyRecord().then(() => {
+ this.get('adminCustomizeCssHtml').get('model').removeObject(model);
+ this.transitionToRoute('adminCustomizeCssHtml');
});
}
});
diff --git a/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 b/app/assets/javascripts/admin/controllers/admin-embedding.js.es6
index b73a8c0354..266aa6975e 100644
--- a/app/assets/javascripts/admin/controllers/admin-embedding.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-embedding.js.es6
@@ -9,7 +9,7 @@ export default Ember.Controller.extend({
@computed('embedding.embeddable_hosts.@each.isCreated')
showSecondary() {
const hosts = this.get('embedding.embeddable_hosts');
- return hosts.length && hosts.findProperty('isCreated');
+ return hosts.length && hosts.findBy('isCreated');
},
@computed('embedding.base_url')
diff --git a/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 b/app/assets/javascripts/admin/controllers/admin-emojis.js.es6
index b111a5952b..29aecc4773 100644
--- a/app/assets/javascripts/admin/controllers/admin-emojis.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-emojis.js.es6
@@ -1,23 +1,23 @@
import { ajax } from 'discourse/lib/ajax';
-export default Ember.ArrayController.extend({
- sortProperties: ["name"],
+export default Ember.Controller.extend({
+ sortedEmojis: Ember.computed.sort('model', 'emojiSorting'),
+ emojiSorting: ['name'],
actions: {
emojiUploaded(emoji) {
emoji.url += "?t=" + new Date().getTime();
- this.pushObject(Ember.Object.create(emoji));
+ this.get('model').pushObject(Ember.Object.create(emoji));
},
destroy(emoji) {
- const self = this;
return bootbox.confirm(
I18n.t("admin.emoji.delete_confirm", { name: emoji.get("name") }),
I18n.t("no_value"),
I18n.t("yes_value"),
- function(destroy) {
+ destroy => {
if (destroy) {
- return ajax("/admin/customize/emojis/" + emoji.get("name"), { type: "DELETE" }).then(function() {
- self.removeObject(emoji);
+ return ajax("/admin/customize/emojis/" + emoji.get("name"), { type: "DELETE" }).then(() => {
+ this.get('model').removeObject(emoji);
});
}
}
diff --git a/app/assets/javascripts/admin/controllers/admin-flags-list.js.es6 b/app/assets/javascripts/admin/controllers/admin-flags-list.js.es6
index 0c85749775..e3101e2fa3 100644
--- a/app/assets/javascripts/admin/controllers/admin-flags-list.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-flags-list.js.es6
@@ -1,6 +1,6 @@
import FlaggedPost from 'admin/models/flagged-post';
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
query: null,
adminOldFlagsView: Em.computed.equal("query", "old"),
@@ -8,18 +8,16 @@ export default Ember.ArrayController.extend({
actions: {
disagreeFlags(flaggedPost) {
- var self = this;
- flaggedPost.disagreeFlags().then(function () {
- self.removeObject(flaggedPost);
+ flaggedPost.disagreeFlags().then(() => {
+ this.get('model').removeObject(flaggedPost);
}, function () {
bootbox.alert(I18n.t("admin.flags.error"));
});
},
deferFlags(flaggedPost) {
- var self = this;
- flaggedPost.deferFlags().then(function () {
- self.removeObject(flaggedPost);
+ flaggedPost.deferFlags().then(() => {
+ this.get('model').removeObject(flaggedPost);
}, function () {
bootbox.alert(I18n.t("admin.flags.error"));
});
@@ -29,7 +27,7 @@ export default Ember.ArrayController.extend({
this.send("disagreeFlags", item);
},
- loadMore(){
+ loadMore() {
const flags = this.get('model');
return FlaggedPost.findAll(this.get('query'), flags.length+1).then(data => {
if (data.length===0) {
diff --git a/app/assets/javascripts/admin/controllers/admin-group.js.es6 b/app/assets/javascripts/admin/controllers/admin-group.js.es6
index bf19293117..e7d53800e7 100644
--- a/app/assets/javascripts/admin/controllers/admin-group.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-group.js.es6
@@ -4,7 +4,7 @@ import { escapeExpression } from 'discourse/lib/utilities';
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({
- needs: ['adminGroupsType'],
+ adminGroupsType: Ember.inject.controller(),
disableSave: false,
savingStatus: '',
@@ -131,13 +131,13 @@ export default Ember.Controller.extend({
save() {
const group = this.get('model'),
- groupsController = this.get("controllers.adminGroupsType"),
+ groupsController = this.get("adminGroupsType"),
groupType = groupsController.get("type");
this.set('disableSave', true);
this.set('savingStatus', I18n.t('saving'));
- let promise = group.get("id") ? group.save() : group.create().then(() => groupsController.addObject(group));
+ let promise = group.get("id") ? group.save() : group.create().then(() => groupsController.get('model').addObject(group));
promise.then(() => {
this.transitionToRoute("adminGroup", groupType, group.get('name'));
@@ -148,7 +148,7 @@ export default Ember.Controller.extend({
destroy() {
const group = this.get('model'),
- groupsController = this.get('controllers.adminGroupsType'),
+ groupsController = this.get('adminGroupsType'),
self = this;
if (!group.get('id')) {
diff --git a/app/assets/javascripts/admin/controllers/admin-groups-type.js.es6 b/app/assets/javascripts/admin/controllers/admin-groups-type.js.es6
index 9a5962cccf..10d7ad01cf 100644
--- a/app/assets/javascripts/admin/controllers/admin-groups-type.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-groups-type.js.es6
@@ -1,18 +1,18 @@
import { ajax } from 'discourse/lib/ajax';
-export default Ember.ArrayController.extend({
- sortProperties: ['name'],
+export default Ember.Controller.extend({
+ sortedGroups: Ember.computed.sort('model', 'groupSorting'),
+ groupSorting: ['name'],
+
refreshingAutoGroups: false,
- isAuto: function(){
- return this.get('type') === 'automatic';
- }.property('type'),
+
+ isAuto: Ember.computed.equal('type', 'automatic'),
actions: {
- refreshAutoGroups: function(){
- var self = this;
+ refreshAutoGroups() {
this.set('refreshingAutoGroups', true);
- ajax('/admin/groups/refresh_automatic_groups', {type: 'POST'}).then(function() {
- self.transitionToRoute("adminGroupsType", "automatic").then(function() {
- self.set('refreshingAutoGroups', false);
+ ajax('/admin/groups/refresh_automatic_groups', {type: 'POST'}).then(() => {
+ this.transitionToRoute("adminGroupsType", "automatic").then(() => {
+ this.set('refreshingAutoGroups', false);
});
});
}
diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6
index fe158a33ab..13685f16b9 100644
--- a/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6
@@ -2,12 +2,12 @@ import { exportEntity } from 'discourse/lib/export-csv';
import { outputExportResult } from 'discourse/lib/export-result';
import ScreenedEmail from 'admin/models/screened-email';
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
loading: false,
actions: {
clearBlock(row){
- row.clearBlock().then(function(){
+ row.clearBlock().then(function() {
// feeling lazy
window.location.reload();
});
@@ -19,11 +19,10 @@ export default Ember.ArrayController.extend({
},
show() {
- var self = this;
- self.set('loading', true);
- ScreenedEmail.findAll().then(function(result) {
- self.set('model', result);
- self.set('loading', false);
+ this.set('loading', true);
+ ScreenedEmail.findAll().then(result => {
+ this.set('model', result);
+ this.set('loading', false);
});
}
});
diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6
index 88f46d6ccb..b654e6d65f 100644
--- a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6
@@ -3,7 +3,7 @@ import { outputExportResult } from 'discourse/lib/export-result';
import { exportEntity } from 'discourse/lib/export-csv';
import ScreenedIpAddress from 'admin/models/screened-ip-address';
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
loading: false,
filter: null,
savedIpAddress: null,
@@ -63,16 +63,15 @@ export default Ember.ArrayController.extend({
},
destroy(record) {
- const self = this;
return bootbox.confirm(
I18n.t("admin.logs.screened_ips.delete_confirm", { ip_address: record.get('ip_address') }),
I18n.t("no_value"),
I18n.t("yes_value"),
- function (result) {
+ result => {
if (result) {
record.destroy().then(deleted => {
if (deleted) {
- self.get("content").removeObject(record);
+ this.get("model").removeObject(record);
} else {
bootbox.alert(I18n.t("generic_error"));
}
diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6
index 5f5e333960..d57a151d21 100644
--- a/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6
@@ -2,15 +2,14 @@ import { exportEntity } from 'discourse/lib/export-csv';
import { outputExportResult } from 'discourse/lib/export-result';
import ScreenedUrl from 'admin/models/screened-url';
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
loading: false,
show() {
- const self = this;
- self.set('loading', true);
- ScreenedUrl.findAll().then(function(result) {
- self.set('model', result);
- self.set('loading', false);
+ this.set('loading', true);
+ ScreenedUrl.findAll().then(result => {
+ this.set('model', result);
+ this.set('loading', false);
});
},
diff --git a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6
index 956a737e57..98f135dc57 100644
--- a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6
@@ -2,7 +2,7 @@ import { exportEntity } from 'discourse/lib/export-csv';
import { outputExportResult } from 'discourse/lib/export-result';
import StaffActionLog from 'admin/models/staff-action-log';
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
loading: false,
filters: null,
diff --git a/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 b/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6
index 9c5ab4bb3e..6bfcc66922 100644
--- a/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6
@@ -1,16 +1,14 @@
import debounce from 'discourse/lib/debounce';
import Permalink from 'admin/models/permalink';
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
loading: false,
filter: null,
show: debounce(function() {
- var self = this;
- self.set('loading', true);
- Permalink.findAll(self.get("filter")).then(function(result) {
- self.set('model', result);
- self.set('loading', false);
+ Permalink.findAll(this.get("filter")).then(result => {
+ this.set('model', result);
+ this.set('loading', false);
});
}, 250).observes("filter"),
@@ -20,12 +18,11 @@ export default Ember.ArrayController.extend({
},
destroy: function(record) {
- const self = this;
- return bootbox.confirm(I18n.t("admin.permalink.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
+ return bootbox.confirm(I18n.t("admin.permalink.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => {
if (result) {
- record.destroy().then(function(deleted) {
+ record.destroy().then(deleted => {
if (deleted) {
- self.removeObject(record);
+ this.get('model').removeObject(record);
} else {
bootbox.alert(I18n.t("generic_error"));
}
diff --git a/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 b/app/assets/javascripts/admin/controllers/admin-plugins.js.es6
index b2eb1335ed..5393a27c8f 100644
--- a/app/assets/javascripts/admin/controllers/admin-plugins.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-plugins.js.es6
@@ -1,10 +1,9 @@
-export default Ember.ArrayController.extend({
-
+export default Ember.Controller.extend({
adminRoutes: function() {
- return this.get('model').map(function(p) {
- if (p.get('enabled')) {
- return p.admin_route;
- }
+ return this.get('model').map(p => {
+ if (p.get('enabled')) {
+ return p.admin_route;
+ }
}).compact();
}.property()
});
diff --git a/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6
index b16db34e3e..df0738bed1 100644
--- a/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6
@@ -1,16 +1,16 @@
export default Ember.Controller.extend({
categoryNameKey: null,
- needs: ['adminSiteSettings'],
+ adminSiteSettings: Ember.inject.controller(),
filteredContent: function() {
if (!this.get('categoryNameKey')) { return []; }
- const category = this.get('controllers.adminSiteSettings.content').findProperty('nameKey', this.get('categoryNameKey'));
+ const category = (this.get('adminSiteSettings.model') || []).findBy('nameKey', this.get('categoryNameKey'));
if (category) {
return category.siteSettings;
} else {
return [];
}
- }.property('controllers.adminSiteSettings.content', 'categoryNameKey')
+ }.property('adminSiteSettings.model', 'categoryNameKey')
});
diff --git a/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6
index b7c4302e87..02a907d7af 100644
--- a/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6
@@ -1,6 +1,6 @@
import debounce from 'discourse/lib/debounce';
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
filter: null,
onlyOverridden: false,
filtered: Ember.computed.notEmpty('filter'),
diff --git a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6
index c8c0ba6219..a2b7c94f17 100644
--- a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6
@@ -1,10 +1,11 @@
import UserBadge from 'discourse/models/user-badge';
-export default Ember.ArrayController.extend({
- needs: ["adminUser"],
- user: Em.computed.alias('controllers.adminUser.model'),
- sortProperties: ['granted_at'],
- sortAscending: false,
+export default Ember.Controller.extend({
+ adminUser: Ember.inject.controller(),
+ user: Ember.computed.alias('adminUser.model'),
+
+ sortedBadges: Ember.computed.sort('model', 'badgeSortOrder'),
+ badgeSortOrder: ['granted_at:desc'],
groupedBadges: function(){
const allBadges = this.get('model');
@@ -38,8 +39,6 @@ export default Ember.ArrayController.extend({
});
return _(expanded).sortBy(group => group.granted_at).reverse().value();
-
-
}.property('model', 'model.[]', 'model.expandedBadges.[]'),
/**
@@ -80,22 +79,15 @@ export default Ember.ArrayController.extend({
model.get('expandedBadges').pushObject(userBadge.badge.id);
},
- /**
- Grant the selected badge to the user.
-
- @method grantBadge
- @param {Integer} badgeId id of the badge we want to grant.
- **/
- grantBadge: function(badgeId) {
- var self = this;
- UserBadge.grant(badgeId, this.get('user.username'), this.get('badgeReason')).then(function(userBadge) {
- self.set('badgeReason', '');
- self.pushObject(userBadge);
- Ember.run.next(function() {
+ grantBadge(badgeId) {
+ UserBadge.grant(badgeId, this.get('user.username'), this.get('badgeReason')).then(userBadge => {
+ this.set('badgeReason', '');
+ this.get('model').pushObject(userBadge);
+ Ember.run.next(() => {
// Update the selected badge ID after the combobox has re-rendered.
- var newSelectedBadge = self.get('grantableBadges')[0];
+ const newSelectedBadge = this.get('grantableBadges')[0];
if (newSelectedBadge) {
- self.set('selectedBadgeId', newSelectedBadge.get('id'));
+ this.set('selectedBadgeId', newSelectedBadge.get('id'));
}
});
}, function() {
@@ -104,12 +96,11 @@ export default Ember.ArrayController.extend({
});
},
- revokeBadge: function(userBadge) {
- var self = this;
- return bootbox.confirm(I18n.t("admin.badges.revoke_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
+ revokeBadge(userBadge) {
+ return bootbox.confirm(I18n.t("admin.badges.revoke_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => {
if (result) {
- userBadge.revoke().then(function() {
- self.get('model').removeObject(userBadge);
+ userBadge.revoke().then(() => {
+ this.get('model').removeObject(userBadge);
});
}
});
diff --git a/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6
index af4a0297ef..1d877dadaf 100644
--- a/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6
@@ -2,7 +2,7 @@ import debounce from 'discourse/lib/debounce';
import { i18n } from 'discourse/lib/computed';
import AdminUser from 'admin/models/admin-user';
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
query: null,
showEmails: false,
refreshing: false,
@@ -19,7 +19,7 @@ export default Ember.ArrayController.extend({
selectedCount: function() {
var model = this.get('model');
if (!model || !model.length) return 0;
- return model.filterProperty('selected').length;
+ return model.filterBy('selected').length;
}.property('model.@each.selected'),
selectAllChanged: function() {
@@ -52,14 +52,14 @@ export default Ember.ArrayController.extend({
actions: {
approveUsers: function() {
- AdminUser.bulkApprove(this.get('model').filterProperty('selected'));
+ AdminUser.bulkApprove(this.get('model').filterBy('selected'));
this._refreshUsers();
},
rejectUsers: function() {
var maxPostAge = this.siteSettings.delete_user_max_post_age;
var controller = this;
- AdminUser.bulkReject(this.get('model').filterProperty('selected')).then(function(result){
+ AdminUser.bulkReject(this.get('model').filterBy('selected')).then(function(result){
var message = I18n.t("admin.users.reject_successful", {count: result.success});
if (result.failed > 0) {
message += ' ' + I18n.t("admin.users.reject_failures", {count: result.failed});
diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6
index 7cb76be26c..53d8370403 100644
--- a/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6
@@ -4,10 +4,10 @@ import computed from 'ember-addons/ember-computed-decorators';
import InputValidation from 'discourse/models/input-validation';
export default Ember.Controller.extend({
- needs: ['adminWebHooks'],
- eventTypes: Em.computed.alias('controllers.adminWebHooks.eventTypes'),
- defaultEventTypes: Em.computed.alias('controllers.adminWebHooks.defaultEventTypes'),
- contentTypes: Em.computed.alias('controllers.adminWebHooks.contentTypes'),
+ adminWebHooks: Ember.inject.controller(),
+ eventTypes: Ember.computed.alias('adminWebHooks.eventTypes'),
+ defaultEventTypes: Ember.computed.alias('adminWebHooks.defaultEventTypes'),
+ contentTypes: Ember.computed.alias('adminWebHooks.contentTypes'),
@computed('model.isSaving', 'saved', 'saveButtonDisabled')
savingStatus(isSaving, saved, saveButtonDisabled) {
@@ -68,7 +68,7 @@ export default Ember.Controller.extend({
const saveWebHook = () => {
return model.save().then(() => {
this.set('saved', true);
- this.get('controllers.adminWebHooks').get('model').addObject(model);
+ this.get('adminWebHooks').get('model').addObject(model);
}).catch(popupAjaxError);
};
@@ -88,7 +88,7 @@ export default Ember.Controller.extend({
if (result) {
const model = this.get('model');
model.destroyRecord().then(() => {
- this.get('controllers.adminWebHooks').get('model').removeObject(model);
+ this.get('adminWebHooks').get('model').removeObject(model);
this.transitionToRoute('adminWebHooks');
}).catch(popupAjaxError);
}
diff --git a/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6
index 2924eb6699..7f1f4f2e49 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6
@@ -1,16 +1,15 @@
import ModalFunctionality from 'discourse/mixins/modal-functionality';
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ["admin-flags-list"],
+ adminFlagsList: Ember.inject.controller(),
_agreeFlag: function (actionOnPost) {
- var adminFlagController = this.get("controllers.admin-flags-list");
- var post = this.get("content");
- var self = this;
+ const adminFlagController = this.get("adminFlagsList");
+ const post = this.get("content");
- return post.agreeFlags(actionOnPost).then(function () {
- adminFlagController.removeObject(post);
- self.send("closeModal");
+ return post.agreeFlags(actionOnPost).then(() => {
+ adminFlagController.get('model').removeObject(post);
+ this.send("closeModal");
}, function () {
bootbox.alert(I18n.t("admin.flags.error"));
});
diff --git a/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6
index 8f93884c60..8aaf637552 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6
@@ -1,11 +1,9 @@
import { escapeExpression } from 'discourse/lib/utilities';
export default Ember.Controller.extend({
- needs: ['modal'],
-
- sample: Em.computed.alias('model.sample'),
- errors: Em.computed.alias('model.errors'),
- count: Em.computed.alias('model.grant_count'),
+ sample: Ember.computed.alias('model.sample'),
+ errors: Ember.computed.alias('model.errors'),
+ count: Ember.computed.alias('model.grant_count'),
count_warning: function() {
if (this.get('count') <= 10) {
diff --git a/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6
index 284b8bfd09..fc2e062794 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6
@@ -1,36 +1,31 @@
import ModalFunctionality from 'discourse/mixins/modal-functionality';
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ["admin-flags-list"],
+ adminFlagsList: Ember.inject.controller(),
actions: {
+ deletePostDeferFlag() {
+ const adminFlagController = this.get("adminFlagsList");
+ const post = this.get("content");
- deletePostDeferFlag: function () {
- var adminFlagController = this.get("controllers.admin-flags-list");
- var post = this.get("content");
- var self = this;
-
- return post.deferFlags(true).then(function () {
- adminFlagController.removeObject(post);
- self.send("closeModal");
+ return post.deferFlags(true).then(() => {
+ adminFlagController.get('model').removeObject(post);
+ this.send("closeModal");
}, function () {
bootbox.alert(I18n.t("admin.flags.error"));
});
},
- deletePostAgreeFlag: function () {
- var adminFlagController = this.get("controllers.admin-flags-list");
- var post = this.get("content");
- var self = this;
+ deletePostAgreeFlag() {
+ const adminFlagController = this.get("adminFlagsList");
+ const post = this.get("content");
- return post.agreeFlags("delete").then(function () {
- adminFlagController.removeObject(post);
- self.send("closeModal");
+ return post.agreeFlags("delete").then(() => {
+ adminFlagController.get('model').removeObject(post);
+ this.send("closeModal");
}, function () {
bootbox.alert(I18n.t("admin.flags.error"));
});
}
-
}
-
});
diff --git a/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6
index 086080c173..fe0416bc30 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6
@@ -1,6 +1,5 @@
import { ajax } from 'discourse/lib/ajax';
export default Ember.Controller.extend({
- needs: ['modal'],
modelChanged: function(){
const model = this.get('model');
diff --git a/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6
index 15cd838245..c041b24f74 100644
--- a/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6
+++ b/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6
@@ -2,31 +2,27 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
import Backup from 'admin/models/backup';
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ["adminBackupsLogs"],
+ adminBackupsLogs: Ember.inject.controller(),
- _startBackup: function (withUploads) {
- var self = this;
- Discourse.User.currentProp("hideReadOnlyAlert", true);
- Backup.start(withUploads).then(function() {
- self.get("controllers.adminBackupsLogs").clear();
- self.send("backupStarted");
+ _startBackup(withUploads) {
+ this.currentUser.set('hideReadOnlyAlert', true);
+ Backup.start(withUploads).then(() => {
+ this.get("adminBackupsLogs.logs").clear();
+ this.send("backupStarted");
});
},
actions: {
-
- startBackup: function () {
+ startBackup() {
this._startBackup();
},
- startBackupWithoutUpload: function () {
+ startBackupWithoutUpload() {
this._startBackup(false);
},
- cancel: function () {
+ cancel() {
this.send("closeModal");
}
-
}
-
});
diff --git a/app/assets/javascripts/admin/models/backup.js.es6 b/app/assets/javascripts/admin/models/backup.js.es6
index d7baceebac..7fe81441c3 100644
--- a/app/assets/javascripts/admin/models/backup.js.es6
+++ b/app/assets/javascripts/admin/models/backup.js.es6
@@ -2,7 +2,6 @@ import { ajax } from 'discourse/lib/ajax';
import PreloadStore from 'preload-store';
const Backup = Discourse.Model.extend({
-
destroy() {
return ajax("/admin/backups/" + this.get("filename"), { type: "DELETE" });
},
@@ -13,11 +12,9 @@ const Backup = Discourse.Model.extend({
data: { client_id: window.MessageBus.clientId }
});
}
-
});
Backup.reopenClass({
-
find() {
return PreloadStore.getAndRemove("backups", () => ajax("/admin/backups.json"))
.then(backups => backups.map(backup => Backup.create(backup)));
diff --git a/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6
index cd01295f5d..c036a10742 100644
--- a/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6
@@ -5,17 +5,17 @@ export default Ember.Route.extend({
// since the logs are pushed via the message bus
// we only want to preload them (hence the beforeModel hook)
beforeModel() {
- const logsController = this.controllerFor("adminBackupsLogs");
+ const logs = this.controllerFor("adminBackupsLogs").get('logs');
// preload the logs if any
PreloadStore.getAndRemove("logs").then(function (preloadedLogs) {
if (preloadedLogs && preloadedLogs.length) {
// we need to filter out message like: "[SUCCESS]"
// and convert POJOs to Ember Objects
- const logs = _.chain(preloadedLogs)
- .reject(function (log) { return log.message.length === 0 || log.message[0] === "["; })
- .map(function (log) { return Em.Object.create(log); })
- .value();
- logsController.pushObjects(logs);
+ const newLogs = _.chain(preloadedLogs)
+ .reject(function (log) { return log.message.length === 0 || log.message[0] === "["; })
+ .map(function (log) { return Em.Object.create(log); })
+ .value();
+ logs.pushObjects(newLogs);
}
});
},
diff --git a/app/assets/javascripts/admin/routes/admin-backups.js.es6 b/app/assets/javascripts/admin/routes/admin-backups.js.es6
index d590019431..ad6f79a8cb 100644
--- a/app/assets/javascripts/admin/routes/admin-backups.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-backups.js.es6
@@ -15,7 +15,7 @@ export default Discourse.Route.extend({
_processLogMessage(log) {
if (log.message === "[STARTED]") {
this.controllerFor("adminBackups").set("model.isOperationRunning", true);
- this.controllerFor("adminBackupsLogs").clear();
+ this.controllerFor("adminBackupsLogs").get('logs').clear();
} else if (log.message === "[FAILED]") {
this.controllerFor("adminBackups").set("model.isOperationRunning", false);
bootbox.alert(I18n.t("admin.backups.operations.failed", { operation: log.operation }));
@@ -27,7 +27,7 @@ export default Discourse.Route.extend({
window.location.pathname = Discourse.getURL("/");
}
} else {
- this.controllerFor("adminBackupsLogs").pushObject(Em.Object.create(log));
+ this.controllerFor("adminBackupsLogs").get('logs').pushObject(Em.Object.create(log));
}
},
diff --git a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6
index 03d091d228..537fdcfda8 100644
--- a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6
@@ -13,7 +13,7 @@ export default Ember.Route.extend({
name: I18n.t('admin.badges.new_badge')
});
}
- return this.modelFor('adminBadges').findProperty('id', parseInt(params.badge_id));
+ return this.modelFor('adminBadges').findBy('id', parseInt(params.badge_id));
},
actions: {
diff --git a/app/assets/javascripts/admin/routes/admin-badges.js.es6 b/app/assets/javascripts/admin/routes/admin-badges.js.es6
index 68da5edb6b..96ecddab23 100644
--- a/app/assets/javascripts/admin/routes/admin-badges.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-badges.js.es6
@@ -5,21 +5,20 @@ import BadgeGrouping from 'discourse/models/badge-grouping';
export default Discourse.Route.extend({
_json: null,
- model: function() {
- var self = this;
- return ajax('/admin/badges.json').then(function(json) {
- self._json = json;
+ model() {
+ return ajax('/admin/badges.json').then(json => {
+ this._json = json;
return Badge.createFromJson(json);
});
},
- setupController: function(controller, model) {
- var json = this._json,
- triggers = [],
- badgeGroupings = [];
+ setupController(controller, model) {
+ const json = this._json;
+ const badgeTriggers = [];
+ const badgeGroupings = [];
_.each(json.admin_badges.triggers,function(v,k){
- triggers.push({id: v, name: I18n.t('admin.badges.trigger_type.'+k)});
+ badgeTriggers.push({id: v, name: I18n.t('admin.badges.trigger_type.'+k)});
});
json.badge_groupings.forEach(function(badgeGroupingJson) {
@@ -30,8 +29,8 @@ export default Discourse.Route.extend({
badgeGroupings: badgeGroupings,
badgeTypes: json.badge_types,
protectedSystemFields: json.admin_badges.protected_system_fields,
- badgeTriggers: triggers,
- model: model
+ badgeTriggers,
+ model
});
}
});
diff --git a/app/assets/javascripts/admin/routes/admin-customize-css-html-show.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-css-html-show.js.es6
index dc38f3c51f..7df829706f 100644
--- a/app/assets/javascripts/admin/routes/admin-customize-css-html-show.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-customize-css-html-show.js.es6
@@ -1,7 +1,7 @@
export default Ember.Route.extend({
model(params) {
const all = this.modelFor('adminCustomizeCssHtml');
- const model = all.findProperty('id', parseInt(params.site_customization_id));
+ const model = all.findBy('id', parseInt(params.site_customization_id));
return model ? { model, section: params.section } : this.replaceWith('adminCustomizeCssHtml.index');
},
diff --git a/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6
index b6e4e36bf9..7c759995fb 100644
--- a/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6
@@ -3,7 +3,7 @@ import { scrollTop } from 'discourse/mixins/scroll-top';
export default Ember.Route.extend({
model(params) {
const all = this.modelFor('adminCustomizeEmailTemplates');
- return all.findProperty('id', params.id);
+ return all.findBy('id', params.id);
},
setupController(controller, emailTemplate) {
diff --git a/app/assets/javascripts/admin/routes/admin-group.js.es6 b/app/assets/javascripts/admin/routes/admin-group.js.es6
index 298bffaa43..3575496edd 100644
--- a/app/assets/javascripts/admin/routes/admin-group.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-group.js.es6
@@ -7,8 +7,7 @@ export default Discourse.Route.extend({
return Group.create({ automatic: false, visible: true });
}
- const group = this.modelFor('adminGroupsType')
- .findProperty('name', params.name);
+ const group = this.modelFor('adminGroupsType').findBy('name', params.name);
if (!group) { return this.transitionTo('adminGroups.index'); }
diff --git a/app/assets/javascripts/admin/templates/api-keys.hbs b/app/assets/javascripts/admin/templates/api-keys.hbs
index 4123e57638..60449052bb 100644
--- a/app/assets/javascripts/admin/templates/api-keys.hbs
+++ b/app/assets/javascripts/admin/templates/api-keys.hbs
@@ -30,5 +30,4 @@
{{#unless hasMasterKey}}
-{{/unless }}
-
+{{/unless}}
diff --git a/app/assets/javascripts/admin/templates/backups-logs.hbs b/app/assets/javascripts/admin/templates/backups-logs.hbs
new file mode 100644
index 0000000000..34ec15f84a
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/backups-logs.hbs
@@ -0,0 +1 @@
+{{admin-backups-logs logs=logs status=status}}
diff --git a/app/assets/javascripts/admin/templates/backups_index.hbs b/app/assets/javascripts/admin/templates/backups_index.hbs
index c7323ebea0..308e73f0fd 100644
--- a/app/assets/javascripts/admin/templates/backups_index.hbs
+++ b/app/assets/javascripts/admin/templates/backups_index.hbs
@@ -6,9 +6,9 @@
{{resumable-upload target="/admin/backups/upload" success="uploadSuccess" error="uploadError" uploadText=uploadLabel title="admin.backups.upload.title"}}
{{#if site.isReadOnly}}
- {{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.model.isOperationRunning title="admin.backups.read_only.disable.title" label="admin.backups.read_only.disable.label"}}
+ {{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.isOperationRunning title="admin.backups.read_only.disable.title" label="admin.backups.read_only.disable.label"}}
{{else}}
- {{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.model.isOperationRunning title="admin.backups.read_only.enable.title" label="admin.backups.read_only.enable.label"}}
+ {{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.isOperationRunning title="admin.backups.read_only.enable.title" label="admin.backups.read_only.enable.label"}}
{{/if}}
@@ -20,12 +20,12 @@
{{fa-icon "download"}}{{i18n 'admin.backups.operations.download.label'}}
- {{#if status.model.isOperationRunning}}
+ {{#if status.isOperationRunning}}
{{d-button icon="trash-o" action="destroyBackup" actionParam=backup class="btn-danger" disabled="true" title="admin.backups.operations.is_running"}}
- {{d-button icon="play" action="startRestore" actionParam=backup disabled=status.model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
+ {{d-button icon="play" action="startRestore" actionParam=backup disabled=status.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
{{else}}
{{d-button icon="trash-o" action="destroyBackup" actionParam=backup class="btn-danger" title="admin.backups.operations.destroy.title"}}
- {{d-button icon="play" action="startRestore" actionParam=backup disabled=status.model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
+ {{d-button icon="play" action="startRestore" actionParam=backup disabled=status.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}}
{{/if}}
diff --git a/app/assets/javascripts/admin/templates/emojis.hbs b/app/assets/javascripts/admin/templates/emojis.hbs
index ca6fd742d4..8972e2ab27 100644
--- a/app/assets/javascripts/admin/templates/emojis.hbs
+++ b/app/assets/javascripts/admin/templates/emojis.hbs
@@ -5,7 +5,7 @@
{{emoji-uploader done="emojiUploaded"}}
- {{#if model}}
+ {{#if sortedEmojis}}
@@ -16,7 +16,7 @@
- {{#each model as |e|}}
+ {{#each sortedEmojis as |e|}}

:{{e.name}}:
diff --git a/app/assets/javascripts/admin/templates/groups_type.hbs b/app/assets/javascripts/admin/templates/groups_type.hbs
index 45bb054ad7..d1d2223c2b 100644
--- a/app/assets/javascripts/admin/templates/groups_type.hbs
+++ b/app/assets/javascripts/admin/templates/groups_type.hbs
@@ -2,7 +2,7 @@
{{i18n 'admin.groups.edit'}}
- {{#each model as |group|}}
+ {{#each sortedGroups as |group|}}
-
{{#link-to "adminGroup" group.type group.name}}{{group.name}}
{{#if group.userCountDisplay}}
diff --git a/app/assets/javascripts/deprecated.js b/app/assets/javascripts/deprecated.js
index ee6592848a..151ed975d0 100644
--- a/app/assets/javascripts/deprecated.js
+++ b/app/assets/javascripts/deprecated.js
@@ -1,31 +1,7 @@
(function() {
var Discourse = require('discourse').default;
- function deprecate(module, methods) {
- var result = {};
-
- methods.forEach(function(m) {
- result[m] = function() {
- Ember.warn("Discourse." + module + "." + m + " is deprecated. Export a setup() function instead");
- };
- });
-
- Discourse[module] = result;
- }
-
- deprecate('Markdown', ['whiteListTag', 'whiteListIframe']);
- deprecate('Dialect', ['inlineRegexp', 'inlineBetween', 'addPreProcessor', 'replaceBlock',
- 'inlineReplace', 'registerInline', 'registerEmoji']);
-
- deprecate('BBCode', ['replaceBBCode', 'register', 'rawBBCode', 'replaceBBCodeParamsRaw']);
-
Discourse.dialect_deprecated = true;
- Discourse.ajax = function() {
- var ajax = require('discourse/lib/ajax').ajax;
- Ember.warn("Discourse.ajax is deprecated. Import the module and use it instead");
- return ajax.apply(this, arguments);
- };
-
window.Discourse = Discourse;
})();
diff --git a/app/assets/javascripts/discourse-common/components/combo-box.js.es6 b/app/assets/javascripts/discourse-common/components/combo-box.js.es6
index ce222e2114..2a2c4e2ba7 100644
--- a/app/assets/javascripts/discourse-common/components/combo-box.js.es6
+++ b/app/assets/javascripts/discourse-common/components/combo-box.js.es6
@@ -1,13 +1,14 @@
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
import { on, observes } from 'ember-addons/ember-computed-decorators';
-export default Ember.Component.extend({
+export default Ember.Component.extend(bufferedRender({
tagName: 'select',
attributeBindings: ['tabindex', 'disabled'],
classNames: ['combobox'],
valueAttribute: 'id',
nameProperty: 'name',
- render(buffer) {
+ buildBuffer(buffer) {
const nameProperty = this.get('nameProperty');
const none = this.get('none');
@@ -48,11 +49,11 @@ export default Ember.Component.extend({
@observes('content.[]')
_rerenderOnChange() {
- this.rerender();
+ this.rerenderBuffer();
},
- @on('didInsertElement')
- _initializeCombo() {
+ didInsertElement() {
+ this._super();
// Workaround for https://github.com/emberjs/ember.js/issues/9813
// Can be removed when fixed. Without it, the wrong option is selected
@@ -60,7 +61,7 @@ export default Ember.Component.extend({
// observer for item names changing (optional)
if (this.get('nameChanges')) {
- this.addObserver('content.@each.' + this.get('nameProperty'), this.rerender);
+ this.addObserver('content.@each.' + this.get('nameProperty'), this.rerenderBuffer);
}
const $elem = this.$();
@@ -80,7 +81,11 @@ export default Ember.Component.extend({
}
this.set('value', val);
});
- $elem.trigger('change');
+ Ember.run.scheduleOnce('afterRender', this, this._triggerChange);
+ },
+
+ _triggerChange() {
+ this.$().trigger('change');
},
@on('willDestroyElement')
@@ -88,4 +93,4 @@ export default Ember.Component.extend({
this.$().select2('destroy');
}
-});
+}));
diff --git a/app/assets/javascripts/discourse-common/lib/buffered-render.js.es6 b/app/assets/javascripts/discourse-common/lib/buffered-render.js.es6
new file mode 100644
index 0000000000..4873bfc778
--- /dev/null
+++ b/app/assets/javascripts/discourse-common/lib/buffered-render.js.es6
@@ -0,0 +1,53 @@
+// Ember 2.0 removes buffered rendering, but we can still implement it ourselves.
+// In the long term we'll want to remove this.
+
+const Mixin = {
+ __bufferTimeout: null,
+
+ _customRender() {
+ Ember.run.cancel(this.__bufferTimeout);
+ if (!this.element || this.isDestroying || this.isDestroyed) { return; }
+
+ const buffer = [];
+ this.buildBuffer(buffer);
+ this.element.innerHTML = buffer.join('');
+ },
+
+ rerenderBuffer() {
+ Ember.run.scheduleOnce('render', this, this._customRender);
+ }
+};
+
+export function bufferedRender(obj) {
+
+ if (!obj.buildBuffer) {
+ Ember.warn('Missing `buildBuffer` method');
+ return obj;
+ }
+
+ const caller = {};
+
+ // True in 1.13 or greater
+ if (Ember.Helper) {
+ caller.didRender = function() {
+ this._super();
+ this._customRender();
+ };
+ } else {
+ caller.didInsertElement = function() {
+ this._super();
+ this._customRender();
+ };
+ }
+
+ const triggers = obj.rerenderTriggers;
+ if (triggers) {
+ caller.init = function() {
+ this._super();
+ triggers.forEach(k => this.addObserver(k, this.rerenderBuffer));
+ };
+ }
+ delete obj.rerenderTriggers;
+
+ return Ember.Mixin.create(Mixin, caller, obj);
+}
diff --git a/app/assets/javascripts/discourse-common/lib/helpers.js.es6 b/app/assets/javascripts/discourse-common/lib/helpers.js.es6
index 45c065124c..dbff7e1186 100644
--- a/app/assets/javascripts/discourse-common/lib/helpers.js.es6
+++ b/app/assets/javascripts/discourse-common/lib/helpers.js.es6
@@ -3,8 +3,9 @@ import { get } from 'discourse-common/lib/raw-handlebars';
// `Ember.Helper` is only available in versions after 1.12
export function htmlHelper(fn) {
if (Ember.Helper) {
- return Ember.Helper.helper(function() {
- return new Handlebars.SafeString(fn.apply(this, Array.prototype.slice.call(arguments)) || '');
+ return Ember.Helper.helper(function(...args) {
+ args = (args.length > 1) ? args[0].concat({ hash: args[args.length-1] }) : args;
+ return new Handlebars.SafeString(fn.apply(this, args) || '');
});
} else {
return Ember.Handlebars.makeBoundHelper(function() {
@@ -13,8 +14,24 @@ export function htmlHelper(fn) {
}
}
+const _helpers = {};
+
export function registerHelper(name, fn) {
- Ember.HTMLBars._registerHelper(name, fn);
+ if (Ember.Helper) {
+ _helpers[name] = Ember.Helper.helper(fn);
+ } else {
+ return Ember.HTMLBars._registerHelper(name, fn);
+ }
+}
+
+export function findHelper(name) {
+ return _helpers[name] || _helpers[name.dasherize()];
+}
+
+export function registerHelpers(registry) {
+ Object.keys(_helpers).forEach(name => {
+ registry.register(`helper:${name}`, _helpers[name], { singleton: false });
+ });
}
function resolveParams(ctx, options) {
@@ -39,6 +56,7 @@ function resolveParams(ctx, options) {
}
export function registerUnbound(name, fn) {
+
const func = function(property, options) {
if (options.types && (options.types[0] === "ID" || options.types[0] === "PathExpression")) {
property = get(this, property, options);
@@ -47,6 +65,14 @@ export function registerUnbound(name, fn) {
return fn.call(this, property, resolveParams(this, options));
};
+ if (Ember.Helper) {
+ _helpers[name] = Ember.Helper.extend({
+ compute: (params, args) => fn(params[0], args)
+ });
+ Handlebars.registerHelper(name, func);
+ return;
+ }
+
Handlebars.registerHelper(name, func);
Ember.Handlebars.registerHelper(name, func);
}
diff --git a/app/assets/javascripts/discourse-common/resolver.js.es6 b/app/assets/javascripts/discourse-common/resolver.js.es6
index 34222872df..15c099cc28 100644
--- a/app/assets/javascripts/discourse-common/resolver.js.es6
+++ b/app/assets/javascripts/discourse-common/resolver.js.es6
@@ -1,5 +1,6 @@
-/* global requirejs, require */
+import { findHelper } from 'discourse-common/lib/helpers';
+/* global requirejs, require */
var classify = Ember.String.classify;
var get = Ember.get;
@@ -109,7 +110,9 @@ export function buildResolver(baseName) {
},
resolveHelper(parsedName) {
- return this.customResolve(parsedName) || this._super(parsedName);
+ return findHelper(parsedName.fullNameWithoutType) ||
+ this.customResolve(parsedName) ||
+ this._super(parsedName);
},
resolveController(parsedName) {
@@ -178,6 +181,7 @@ export function buildResolver(baseName) {
return this._super(parsedName) ||
templates[slashedType] ||
templates[withoutType] ||
+ templates[withoutType.replace(/\.raw$/, '')] ||
templates[dashed] ||
templates[decamelized.replace(/\./, '/')] ||
templates[decamelized.replace(/\_/, '/')] ||
diff --git a/app/assets/javascripts/discourse.js.es6 b/app/assets/javascripts/discourse.js.es6
index 523b0ee225..cbbc0bf9cf 100644
--- a/app/assets/javascripts/discourse.js.es6
+++ b/app/assets/javascripts/discourse.js.es6
@@ -135,15 +135,6 @@ const Discourse = Ember.Application.extend({
}
});
});
-
- const utils = require('discourse/lib/utilities');
- Discourse.Utilities = {};
- Object.keys(utils).forEach(function(k) {
- Discourse.Utilities[k] = function() {
- Ember.warn('Discourse.Utilities is deprecated. Import it as a module');
- return utils[k].apply(utils, arguments);
- };
- });
},
@computed('currentAssetVersion', 'desiredAssetVersion')
diff --git a/app/assets/javascripts/discourse/components/activity-filter.js.es6 b/app/assets/javascripts/discourse/components/activity-filter.js.es6
deleted file mode 100644
index c0cf5b4e4e..0000000000
--- a/app/assets/javascripts/discourse/components/activity-filter.js.es6
+++ /dev/null
@@ -1,66 +0,0 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
-import UserAction from "discourse/models/user-action";
-
-export default Ember.Component.extend(StringBuffer, {
- tagName: 'li',
- classNameBindings: ['active', 'noGlyph'],
-
- rerenderTriggers: ['content.count', 'count'],
- noGlyph: Em.computed.empty('icon'),
-
- isIndexStream: function() {
- return !this.get('content');
- }.property('content.count'),
-
- active: function() {
- if (this.get('isIndexStream')) {
- return !this.get('userActionType');
- }
- const content = this.get('content');
- if (content) {
- return parseInt(this.get('userActionType'), 10) === parseInt(Em.get(content, 'action_type'), 10);
- }
- }.property('userActionType', 'isIndexStream'),
-
- activityCount: function() {
- return this.get('content.count') || this.get('count') || 0;
- }.property('content.count', 'count'),
-
- typeKey: function() {
- const actionType = this.get('content.action_type');
- if (actionType === UserAction.TYPES.messages_received) { return ""; }
-
- const result = UserAction.TYPES_INVERTED[actionType];
- if (!result) { return ""; }
-
- // We like our URLS to have hyphens, not underscores
- return "/" + result.replace("_", "-");
- }.property('content.action_type'),
-
- url: function() {
- return "/users/" + this.get('user.username_lower') + "/activity" + this.get('typeKey');
- }.property('typeKey', 'user.username_lower'),
-
- description: function() {
- return this.get('content.description') || I18n.t("user.filters.all");
- }.property('content.description'),
-
- renderString(buffer) {
- buffer.push("");
- const icon = this.get('icon');
- if (icon) {
- buffer.push(" ");
- }
- buffer.push(this.get('description') + " (" + this.get('activityCount') + ")");
- },
-
- icon: function() {
- switch(parseInt(this.get('content.action_type'), 10)) {
- case UserAction.TYPES.likes_received: return "heart";
- case UserAction.TYPES.bookmarks: return "bookmark";
- case UserAction.TYPES.edits: return "pencil";
- case UserAction.TYPES.replies: return "reply";
- case UserAction.TYPES.mentions: return "at";
- }
- }.property("content.action_type")
-});
diff --git a/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 b/app/assets/javascripts/discourse/components/basic-topic-list.js.es6
index 75c4d370c0..d7cdc32744 100644
--- a/app/assets/javascripts/discourse/components/basic-topic-list.js.es6
+++ b/app/assets/javascripts/discourse/components/basic-topic-list.js.es6
@@ -47,12 +47,10 @@ export default Ember.Component.extend({
target = target.find('a');
}
- const topic = this.get('topics').findProperty('id', parseInt(topicId));
+ const topic = this.get('topics').findBy('id', parseInt(topicId));
this.sendAction('postsAction', {topic, position: target.offset()});
}
return false;
}
-
}
-
});
diff --git a/app/assets/javascripts/discourse/components/bread-crumbs.js.es6 b/app/assets/javascripts/discourse/components/bread-crumbs.js.es6
index 6841e8e456..28a06d7000 100644
--- a/app/assets/javascripts/discourse/components/bread-crumbs.js.es6
+++ b/app/assets/javascripts/discourse/components/bread-crumbs.js.es6
@@ -35,9 +35,4 @@ export default Ember.Component.extend({
});
}.property('firstCategory', 'hideSubcategories'),
- render(buffer) {
- if (this.get('hidden')) { return; }
- this._super(buffer);
- }
-
});
diff --git a/app/assets/javascripts/discourse/components/check-mark.js.es6 b/app/assets/javascripts/discourse/components/check-mark.js.es6
index a934a490a4..34585e1a0f 100644
--- a/app/assets/javascripts/discourse/components/check-mark.js.es6
+++ b/app/assets/javascripts/discourse/components/check-mark.js.es6
@@ -7,10 +7,5 @@ export default Ember.Component.extend({
@computed('checked')
status(checked) {
return checked ? 'status-checked' : 'status-unchecked';
- },
-
- render(buffer) {
- const icon = this.get('checked') ? 'check' : 'times';
- buffer.push(``);
}
});
diff --git a/app/assets/javascripts/discourse/components/color-picker-choice.js.es6 b/app/assets/javascripts/discourse/components/color-picker-choice.js.es6
new file mode 100644
index 0000000000..78f444a1c1
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/color-picker-choice.js.es6
@@ -0,0 +1,27 @@
+import computed from 'ember-addons/ember-computed-decorators';
+
+export default Ember.Component.extend({
+ tagName: 'button',
+ attributeBindings: ['style', 'title'],
+ classNameBindings: [':colorpicker', 'isUsed:used-color:unused-color'],
+
+ @computed('color', 'usedColors')
+ isUsed(color, usedColors) {
+ return (usedColors || []).indexOf(color.toUpperCase()) >= 0;
+ },
+
+ @computed('isUsed')
+ title(isUsed) {
+ return isUsed ? I18n.t("category.already_used") : null;
+ },
+
+ @computed('color')
+ style(color) {
+ return `background-color: #${color};`.htmlSafe();
+ },
+
+ click(e) {
+ e.preventDefault();
+ this.sendAction('selectColor', this.get('color'));
+ }
+});
diff --git a/app/assets/javascripts/discourse/components/color-picker.js.es6 b/app/assets/javascripts/discourse/components/color-picker.js.es6
index d1acf7d811..30c95f9ca2 100644
--- a/app/assets/javascripts/discourse/components/color-picker.js.es6
+++ b/app/assets/javascripts/discourse/components/color-picker.js.es6
@@ -1,30 +1,9 @@
-import DiscourseContainerView from 'discourse/views/container';
-
-export default DiscourseContainerView.extend({
+export default Ember.Component.extend({
classNames: 'colors-container',
- _createButtons: function() {
- var colors = this.get('colors'),
- isUsed, usedColors = this.get('usedColors') || [];
-
- if (!colors) return;
-
- var self = this;
- colors.forEach(function(color) {
- isUsed = usedColors.indexOf(color.toUpperCase()) >= 0;
-
- self.attachViewWithArgs({
- tagName: 'button',
- attributeBindings: ['style', 'title'],
- classNames: ['colorpicker'].concat( isUsed ? ['used-color'] : ['unused-color'] ),
- style: ('background-color: #' + color + ';').htmlSafe(),
- title: isUsed ? I18n.t("category.already_used") : null,
- click: function() {
- self.set("value", color);
- return false;
- }
- });
-
- });
- }.on('init')
+ actions: {
+ selectColor(color) {
+ this.set('value', color);
+ }
+ }
});
diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6
index f16acd43b9..6503e051c2 100644
--- a/app/assets/javascripts/discourse/components/composer-editor.js.es6
+++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6
@@ -2,7 +2,7 @@ import userSearch from 'discourse/lib/user-search';
import { default as computed, on } from 'ember-addons/ember-computed-decorators';
import { linkSeenMentions, fetchUnseenMentions } from 'discourse/lib/link-mentions';
import { linkSeenCategoryHashtags, fetchUnseenCategoryHashtags } from 'discourse/lib/link-category-hashtags';
-import { fetchUnseenTagHashtags, linkSeenTagHashtags } from 'discourse/lib/link-tag-hashtag';
+import { linkSeenTagHashtags, fetchUnseenTagHashtags } from 'discourse/lib/link-tag-hashtag';
import { load } from 'pretty-text/oneboxer';
import { ajax } from 'discourse/lib/ajax';
import InputValidation from 'discourse/models/input-validation';
@@ -41,22 +41,6 @@ export default Ember.Component.extend({
return showPreview ? I18n.t('composer.hide_preview') : I18n.t('composer.show_preview');
},
- _renderUnseenTagHashtags($preview, unseen) {
- fetchUnseenTagHashtags(unseen).then(() => {
- linkSeenTagHashtags($preview);
- });
- },
-
- @on('previewRefreshed')
- paintTagHashtags($preview) {
- if (!this.siteSettings.tagging_enabled) { return; }
-
- const unseenTagHashtags = linkSeenTagHashtags($preview);
- if (unseenTagHashtags.length) {
- Ember.run.debounce(this, this._renderUnseenTagHashtags, $preview, unseenTagHashtags, 500);
- }
- },
-
@computed
markdownOptions() {
return {
@@ -66,7 +50,7 @@ export default Ember.Component.extend({
const posts = topic.get('postStream.posts');
if (posts && topicId === topic.get('id')) {
- const quotedPost = posts.findProperty("post_number", postNumber);
+ const quotedPost = posts.findBy("post_number", postNumber);
if (quotedPost) {
return tinyAvatar(quotedPost.get('avatar_template'));
}
@@ -152,19 +136,38 @@ export default Ember.Component.extend({
$preview.scrollTop(desired + 50);
},
- _renderUnseenMentions: function($preview, unseen) {
- fetchUnseenMentions($preview, unseen).then(() => {
+ _renderUnseenMentions($preview, unseen) {
+ fetchUnseenMentions(unseen).then(() => {
linkSeenMentions($preview, this.siteSettings);
this._warnMentionedGroups($preview);
});
},
- _renderUnseenCategoryHashtags: function($preview, unseen) {
+ _renderUnseenCategoryHashtags($preview, unseen) {
fetchUnseenCategoryHashtags(unseen).then(() => {
linkSeenCategoryHashtags($preview);
});
},
+ _renderUnseenTagHashtags($preview, unseen) {
+ fetchUnseenTagHashtags(unseen).then(() => {
+ linkSeenTagHashtags($preview);
+ });
+ },
+
+ _loadOneboxes($oneboxes) {
+ const post = this.get('composer.post');
+ let refresh = false;
+
+ // If we are editing a post, we'll refresh its contents once.
+ if (post && !post.get('refreshedPost')) {
+ refresh = true;
+ post.set('refreshedPost', true);
+ }
+
+ $oneboxes.each((_, o) => load(o, refresh, ajax));
+ },
+
_warnMentionedGroups($preview) {
Ember.run.scheduleOnce('afterRender', () => {
this._warnedMentions = this._warnedMentions || [];
@@ -481,31 +484,33 @@ export default Ember.Component.extend({
previewUpdated($preview) {
// Paint mentions
- const unseen = linkSeenMentions($preview, this.siteSettings);
- if (unseen.length) {
- Ember.run.debounce(this, this._renderUnseenMentions, $preview, unseen, 500);
+ const unseenMentions = linkSeenMentions($preview, this.siteSettings);
+ if (unseenMentions.length) {
+ Ember.run.debounce(this, this._renderUnseenMentions, $preview, unseenMentions, 450);
}
this._warnMentionedGroups($preview);
// Paint category hashtags
- const unseenHashtags = linkSeenCategoryHashtags($preview);
- if (unseenHashtags.length) {
- Ember.run.debounce(this, this._renderUnseenCategoryHashtags, $preview, unseenHashtags, 500);
+ const unseenCategoryHashtags = linkSeenCategoryHashtags($preview);
+ if (unseenCategoryHashtags.length) {
+ Ember.run.debounce(this, this._renderUnseenCategoryHashtags, $preview, unseenCategoryHashtags, 450);
}
- const post = this.get('composer.post');
- let refresh = false;
-
- // If we are editing a post, we'll refresh its contents once. This is a feature that
- // allows a user to refresh its contents once.
- if (post && !post.get('refreshedPost')) {
- refresh = true;
- post.set('refreshedPost', true);
+ // Paint tag hashtags
+ if (this.siteSettings.tagging_enabled) {
+ const unseenTagHashtags = linkSeenTagHashtags($preview);
+ if (unseenTagHashtags.length) {
+ Ember.run.debounce(this, this._renderUnseenTagHashtags, $preview, unseenTagHashtags, 450);
+ }
}
// Paint oneboxes
- $('a.onebox', $preview).each((i, e) => load(e, refresh, ajax));
+ const $oneboxes = $('a.onebox', $preview);
+ if ($oneboxes.length > 0 && $oneboxes.length <= this.siteSettings.max_oneboxes_per_post) {
+ Ember.run.debounce(this, this._loadOneboxes, $oneboxes, 450);
+ }
+
this.trigger('previewRefreshed', $preview);
this.sendAction('afterRefresh', $preview);
},
diff --git a/app/assets/javascripts/discourse/components/composer-messages.js.es6 b/app/assets/javascripts/discourse/components/composer-messages.js.es6
index 52d1da32a6..59b3586dd3 100644
--- a/app/assets/javascripts/discourse/components/composer-messages.js.es6
+++ b/app/assets/javascripts/discourse/components/composer-messages.js.es6
@@ -15,12 +15,12 @@ export default Ember.Component.extend({
didInsertElement() {
this._super();
- this.reset();
this.appEvents.on('composer:typed-reply', this, this._typedReply);
this.appEvents.on('composer:opened', this, this._findMessages);
this.appEvents.on('composer:find-similar', this, this._findSimilar);
this.appEvents.on('composer-messages:close', this, this._closeTop);
this.appEvents.on('composer-messages:create', this, this._create);
+ Ember.run.scheduleOnce('afterRender', this, this.reset);
},
willDestroyElement() {
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 49e2eefca1..c248ea5b95 100644
--- a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6
+++ b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6
@@ -1,19 +1,10 @@
+import computed from 'ember-addons/ember-computed-decorators';
+
export default Ember.Component.extend({
classNameBindings: ['containerClass', 'condition:visible'],
- containerClass: function() {
- return this.get('size') === 'small' ? 'inline-spinner' : undefined;
- }.property('size'),
-
- render: function(buffer) {
- if (this.get('condition')) {
- buffer.push('');
- } else {
- return this._super(buffer);
- }
- },
-
- _conditionChanged: function() {
- this.rerender();
- }.observes('condition')
+ @computed('size')
+ containerClass(size) {
+ return size === 'small' ? 'inline-spinner' : undefined;
+ }
});
diff --git a/app/assets/javascripts/discourse/components/count-i18n.js.es6 b/app/assets/javascripts/discourse/components/count-i18n.js.es6
index 28c908be23..0197b6bb76 100644
--- a/app/assets/javascripts/discourse/components/count-i18n.js.es6
+++ b/app/assets/javascripts/discourse/components/count-i18n.js.es6
@@ -1,8 +1,10 @@
-export default Ember.Component.extend(Discourse.StringBuffer, {
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
+
+export default Ember.Component.extend(bufferedRender({
tagName: 'span',
rerenderTriggers: ['count', 'suffix'],
- renderString: function(buffer) {
+ buildBuffer(buffer) {
buffer.push(I18n.t(this.get('key') + (this.get('suffix') || ''), { count: this.get('count') }));
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/d-button.js.es6 b/app/assets/javascripts/discourse/components/d-button.js.es6
index 66e393ba71..bd606facaf 100644
--- a/app/assets/javascripts/discourse/components/d-button.js.es6
+++ b/app/assets/javascripts/discourse/components/d-button.js.es6
@@ -1,7 +1,9 @@
-import { iconHTML } from 'discourse-common/helpers/fa-icon';
-import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
+import { default as computed } from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
+ // subclasses need this
+ layoutName: 'components/d-button',
+
tagName: 'button',
classNameBindings: [':btn', 'noText'],
attributeBindings: ['disabled', 'translatedTitle:title'],
@@ -18,24 +20,6 @@ export default Ember.Component.extend({
if (label) return I18n.t(label);
},
- @observes('icon')
- iconChanged() {
- this.rerender();
- },
-
- render(buffer) {
- const label = this.get('translatedLabel'),
- icon = this.get('icon');
-
- if (label || icon) {
- if (icon) { buffer.push(iconHTML(icon) + ' '); }
- if (label) { buffer.push(label); }
- } else {
- // If no label or icon is present, yield
- return this._super(buffer);
- }
- },
-
click() {
this.sendAction("action", this.get("actionParam"));
return false;
diff --git a/app/assets/javascripts/discourse/components/d-editor.js.es6 b/app/assets/javascripts/discourse/components/d-editor.js.es6
index 8367599743..322959422f 100644
--- a/app/assets/javascripts/discourse/components/d-editor.js.es6
+++ b/app/assets/javascripts/discourse/components/d-editor.js.es6
@@ -123,7 +123,7 @@ class Toolbar {
}
addButton(button) {
- const g = this.groups.findProperty('group', button.group);
+ const g = this.groups.findBy('group', button.group);
if (!g) {
throw `Couldn't find toolbar group ${button.group}`;
}
@@ -201,18 +201,23 @@ export default Ember.Component.extend({
return null;
},
- @on('didInsertElement')
- _startUp() {
+ _readyNow() {
+ this.set('ready', true);
+ },
+
+ didInsertElement() {
+ this._super();
+
const container = this.get('container'),
$editorInput = this.$('.d-editor-input');
this._applyEmojiAutocomplete(container, $editorInput);
this._applyCategoryHashtagAutocomplete(container, $editorInput);
- this.set('ready', true);
+
+ Ember.run.scheduleOnce('afterRender', this, this._readyNow);
const mouseTrap = Mousetrap(this.$('.d-editor-input')[0]);
-
const shortcuts = this.get('toolbar.shortcuts');
Object.keys(shortcuts).forEach(sc => {
const button = shortcuts[sc];
@@ -232,7 +237,6 @@ export default Ember.Component.extend({
this.appEvents.on('composer:insert-text', text => this._addText(this._getSelected(), text));
this.appEvents.on('composer:replace-text', (oldVal, newVal) => this._replaceText(oldVal, newVal));
-
this._mouseTrap = mouseTrap;
},
@@ -267,7 +271,6 @@ export default Ember.Component.extend({
if (this._state !== "inDOM") { return; }
const $preview = this.$('.d-editor-preview');
if ($preview.length === 0) return;
-
this.sendAction('previewUpdated', $preview);
});
},
diff --git a/app/assets/javascripts/discourse/components/d-link.js.es6 b/app/assets/javascripts/discourse/components/d-link.js.es6
deleted file mode 100644
index 1c94bdc823..0000000000
--- a/app/assets/javascripts/discourse/components/d-link.js.es6
+++ /dev/null
@@ -1,69 +0,0 @@
-import computed from 'ember-addons/ember-computed-decorators';
-import { iconHTML } from 'discourse-common/helpers/fa-icon';
-import interceptClick from 'discourse/lib/intercept-click';
-
-export default Ember.Component.extend({
- tagName: 'a',
- classNames: ['d-link'],
- attributeBindings: ['translatedTitle:title', 'translatedTitle:aria-title', 'href'],
-
- @computed('path')
- href(path) {
- if (path) { return path; }
-
- const route = this.get('route');
- if (route) {
- const router = this.container.lookup('router:main');
- if (router && router.router) {
- const params = [route];
- const model = this.get('model');
- if (model) {
- params.push(model);
- }
-
- return Discourse.getURL(router.router.generate.apply(router.router, params));
- }
- }
-
- return '';
- },
-
- @computed("title")
- translatedTitle(title) {
- if (title) return I18n.t(title);
- },
-
- click(e) {
- const action = this.get('action');
- if (action) {
- this.sendAction('action');
- return false;
- }
-
- return interceptClick(e);
- },
-
- render(buffer) {
- if (!!this.get('template')) {
- return this._super(buffer);
- }
-
- const icon = this.get('icon');
- if (icon) {
- buffer.push(iconHTML(icon));
- }
-
- const label = this.get('label');
- if (label) {
- if (icon) { buffer.push(" "); }
-
- if (this.get('translateLabel') === "false") {
- buffer.push(label);
- } else {
- const count = this.get('count');
- buffer.push(I18n.t(label, { count }));
- }
- }
- }
-
-});
diff --git a/app/assets/javascripts/discourse/components/directory-toggle.js.es6 b/app/assets/javascripts/discourse/components/directory-toggle.js.es6
index 168db163c5..3f55ec0543 100644
--- a/app/assets/javascripts/discourse/components/directory-toggle.js.es6
+++ b/app/assets/javascripts/discourse/components/directory-toggle.js.es6
@@ -1,7 +1,7 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
import { iconHTML } from 'discourse-common/helpers/fa-icon';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
tagName: 'th',
classNames: ['sortable'],
attributeBindings: ['title'],
@@ -12,8 +12,7 @@ export default Ember.Component.extend(StringBuffer, {
return I18n.t(labelKey + '_long', { defaultValue: I18n.t(labelKey) });
}.property('field'),
- renderString(buffer) {
-
+ buildBuffer(buffer) {
const icon = this.get('icon');
if (icon) {
buffer.push(iconHTML(icon));
@@ -37,4 +36,4 @@ export default Ember.Component.extend(StringBuffer, {
this.setProperties({ order: field, asc: null });
}
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/discourse-banner.js.es6 b/app/assets/javascripts/discourse/components/discourse-banner.js.es6
index 56374168e6..40db3dce8a 100644
--- a/app/assets/javascripts/discourse/components/discourse-banner.js.es6
+++ b/app/assets/javascripts/discourse/components/discourse-banner.js.es6
@@ -1,6 +1,4 @@
-import VisibleComponent from "discourse/components/visible";
-
-export default VisibleComponent.extend({
+export default Ember.Component.extend({
visible: function () {
var bannerKey = this.get("banner.key"),
@@ -14,7 +12,7 @@ export default VisibleComponent.extend({
}.property("user.dismissed_banner_key", "banner.key", "hide"),
actions: {
- dismiss: function () {
+ dismiss() {
if (this.get("user")) {
this.get("user").dismissBanner(this.get("banner.key"));
} else {
diff --git a/app/assets/javascripts/discourse/components/dropdown-button.js.es6 b/app/assets/javascripts/discourse/components/dropdown-button.js.es6
index 0037ec17f2..032c80e2af 100644
--- a/app/assets/javascripts/discourse/components/dropdown-button.js.es6
+++ b/app/assets/javascripts/discourse/components/dropdown-button.js.es6
@@ -1,6 +1,6 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
classNameBindings: [':btn-group', 'hidden'],
rerenderTriggers: ['text', 'longDescription'],
@@ -23,7 +23,7 @@ export default Ember.Component.extend(StringBuffer, {
this.$().off('click.dropdown-button', 'ul li');
}.on('willDestroyElement'),
- renderString(buffer) {
+ buildBuffer(buffer) {
const title = this.get('title');
if (title) {
buffer.push("
" + title + "
");
@@ -56,4 +56,4 @@ export default Ember.Component.extend(StringBuffer, {
buffer.push("");
}
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6
index 049157609e..41a4d2b20f 100644
--- a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6
+++ b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6
@@ -1,7 +1,25 @@
import { setting } from 'discourse/lib/computed';
import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
+import computed from "ember-addons/ember-computed-decorators";
export default buildCategoryPanel('settings', {
emailInEnabled: setting('email_in'),
showPositionInput: setting('fixed_category_positions'),
+
+ isDefaultSortOrder: Em.computed.empty('category.sort_order'),
+
+ @computed
+ availableSorts() {
+ return ['likes', 'op_likes', 'views', 'posts', 'activity', 'posters', 'category', 'created']
+ .map(s => ({ name: I18n.t('category.sort_options.' + s), value: s }))
+ .sort((a,b) => { return a.name > b.name; });
+ },
+
+ @computed
+ sortAscendingOptions() {
+ return [
+ {name: I18n.t('category.sort_ascending'), value: 'true'},
+ {name: I18n.t('category.sort_descending'), value: 'false'}
+ ];
+ }
});
diff --git a/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 b/app/assets/javascripts/discourse/components/edit-category-tab.js.es6
index 9e47066067..556e072ea1 100644
--- a/app/assets/javascripts/discourse/components/edit-category-tab.js.es6
+++ b/app/assets/javascripts/discourse/components/edit-category-tab.js.es6
@@ -14,9 +14,14 @@ export default Em.Component.extend({
return I18n.t('category.' + this.get('tab').replace('-', '_'));
}.property('tab'),
+ didInsertElement() {
+ this._super();
+ Ember.run.scheduleOnce('afterRender', this, this._addToCollection);
+ },
+
_addToCollection: function() {
this.get('panels').addObject(this.get('tabClassName'));
- }.on('didInsertElement'),
+ },
actions: {
select: function() {
diff --git a/app/assets/javascripts/discourse/components/global-notice.js.es6 b/app/assets/javascripts/discourse/components/global-notice.js.es6
index bd45e777a4..0b291384c6 100644
--- a/app/assets/javascripts/discourse/components/global-notice.js.es6
+++ b/app/assets/javascripts/discourse/components/global-notice.js.es6
@@ -1,12 +1,12 @@
import { on } from 'ember-addons/ember-computed-decorators';
-import StringBuffer from 'discourse/mixins/string-buffer';
import { iconHTML } from 'discourse-common/helpers/fa-icon';
import LogsNotice from 'discourse/services/logs-notice';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
rerenderTriggers: ['site.isReadOnly'],
- renderString: function(buffer) {
+ buildBuffer(buffer) {
let notices = [];
if (this.site.get("isReadOnly")) {
@@ -51,7 +51,7 @@ export default Ember.Component.extend(StringBuffer, {
@on('didInsertElement')
_setupLogsNotice() {
LogsNotice.current().addObserver('hidden', () => {
- this.rerenderString();
+ this.rerenderBuffer();
});
this.$().on('click.global-notice', '.alert-logs-notice .close', () => {
@@ -63,4 +63,4 @@ export default Ember.Component.extend(StringBuffer, {
_teardownLogsNotice() {
this.$().off('click.global-notice');
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/image-uploader.js.es6 b/app/assets/javascripts/discourse/components/image-uploader.js.es6
index 08359fa869..8e7d0420c6 100644
--- a/app/assets/javascripts/discourse/components/image-uploader.js.es6
+++ b/app/assets/javascripts/discourse/components/image-uploader.js.es6
@@ -6,7 +6,7 @@ export default Em.Component.extend(UploadMixin, {
@computed('imageUrl')
backgroundStyle(imageUrl) {
- if (Em.isNone(imageUrl)) { return; }
+ if (Em.isNone(imageUrl)) { return "".htmlSafe(); }
return `background-image: url(${imageUrl})`.htmlSafe();
},
diff --git a/app/assets/javascripts/discourse/components/input-tip.js.es6 b/app/assets/javascripts/discourse/components/input-tip.js.es6
index cb1bad446e..0178ad7cac 100644
--- a/app/assets/javascripts/discourse/components/input-tip.js.es6
+++ b/app/assets/javascripts/discourse/components/input-tip.js.es6
@@ -1,17 +1,17 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
import { iconHTML } from 'discourse-common/helpers/fa-icon';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
classNameBindings: [':tip', 'good', 'bad'],
rerenderTriggers: ['validation'],
bad: Em.computed.alias('validation.failed'),
good: Em.computed.not('bad'),
- renderString(buffer) {
+ buildBuffer(buffer) {
const reason = this.get('validation.reason');
if (reason) {
buffer.push(iconHTML(this.get('good') ? 'check' : 'times') + ' ' + reason);
}
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/login-reply-button.js.es6 b/app/assets/javascripts/discourse/components/login-reply-button.js.es6
new file mode 100644
index 0000000000..e162faf267
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/login-reply-button.js.es6
@@ -0,0 +1,7 @@
+import Button from 'discourse/components/d-button';
+
+export default Button.extend({
+ label: 'topic.reply.title',
+ icon: 'reply',
+ action: 'showLogin'
+});
diff --git a/app/assets/javascripts/discourse/components/navigation-item.js.es6 b/app/assets/javascripts/discourse/components/navigation-item.js.es6
index 758e4a385c..62f6a37fde 100644
--- a/app/assets/javascripts/discourse/components/navigation-item.js.es6
+++ b/app/assets/javascripts/discourse/components/navigation-item.js.es6
@@ -1,7 +1,7 @@
import computed from "ember-addons/ember-computed-decorators";
-import StringBuffer from 'discourse/mixins/string-buffer';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
tagName: 'li',
classNameBindings: ['active', 'content.hasIcon:has-icon'],
attributeBindings: ['title'],
@@ -26,7 +26,7 @@ export default Ember.Component.extend(StringBuffer, {
filterMode.indexOf(contentFilterMode) === 0;
},
- renderString(buffer) {
+ buildBuffer(buffer) {
const content = this.get('content');
buffer.push("");
if (content.get('hasIcon')) {
@@ -35,4 +35,4 @@ export default Ember.Component.extend(StringBuffer, {
buffer.push(this.get('content.displayName'));
buffer.push("");
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 b/app/assets/javascripts/discourse/components/popup-input-tip.js.es6
index 2c164ddf5e..59e5856db0 100644
--- a/app/assets/javascripts/discourse/components/popup-input-tip.js.es6
+++ b/app/assets/javascripts/discourse/components/popup-input-tip.js.es6
@@ -1,8 +1,8 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
import { iconHTML } from 'discourse-common/helpers/fa-icon';
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
classNameBindings: [':popup-tip', 'good', 'bad', 'lastShownAt::hide'],
animateAttribute: null,
bouncePixels: 6,
@@ -37,7 +37,7 @@ export default Ember.Component.extend(StringBuffer, {
}
},
- renderString(buffer) {
+ buildBuffer(buffer) {
const reason = this.get('validation.reason');
if (!reason) { return; }
@@ -55,4 +55,4 @@ export default Ember.Component.extend(StringBuffer, {
$elem.animate({ right: '-=' + this.bouncePixels }, this.bounceDelay).animate({ right: '+=' + this.bouncePixels }, this.bounceDelay);
}
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/queued-post.js.es6 b/app/assets/javascripts/discourse/components/queued-post.js.es6
index 28f5a90fdd..9629724b43 100644
--- a/app/assets/javascripts/discourse/components/queued-post.js.es6
+++ b/app/assets/javascripts/discourse/components/queued-post.js.es6
@@ -13,7 +13,6 @@ function updateState(state, opts) {
post.update(args).then(() => {
this.sendAction('removePost', post);
- // this.get('controllers.queued-posts.model').removeObject(post);
}).catch(popupAjaxError);
};
}
diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6
index 242bce46d5..b45f54b530 100644
--- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6
+++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6
@@ -88,7 +88,6 @@ export default Em.Component.extend({
return;
}
- this.findSearchTerms();
this.setSearchedTermValue('searchedTerms.username', REGEXP_USERNAME_PREFIX);
this.setSearchedTermValueForCategory();
this.setSearchedTermValueForGroup();
@@ -117,11 +116,11 @@ export default Em.Component.extend({
result.push(block);
});
- this.set('searchTermBlocks', result);
+ return result;
},
filterBlocks(regexPrefix) {
- const blocks = this.get('searchTermBlocks');
+ const blocks = this.findSearchTerms();
if (!blocks) return [];
let result = [];
diff --git a/app/assets/javascripts/discourse/components/tag-drop-link.js.es6 b/app/assets/javascripts/discourse/components/tag-drop-link.js.es6
index 8cfad3cd2a..f2f671e403 100644
--- a/app/assets/javascripts/discourse/components/tag-drop-link.js.es6
+++ b/app/assets/javascripts/discourse/components/tag-drop-link.js.es6
@@ -17,10 +17,6 @@ export default Ember.Component.extend({
return "tag-" + this.get('tagId');
}.property('tagId'),
- render(buffer) {
- buffer.push(Handlebars.Utils.escapeExpression(this.get('tagId')));
- },
-
click(e) {
e.preventDefault();
DiscourseURL.routeTo(this.get('href'));
diff --git a/app/assets/javascripts/discourse/components/text-overflow.js.es6 b/app/assets/javascripts/discourse/components/text-overflow.js.es6
index 73a4637bfd..4906ad1a50 100644
--- a/app/assets/javascripts/discourse/components/text-overflow.js.es6
+++ b/app/assets/javascripts/discourse/components/text-overflow.js.es6
@@ -1,12 +1,9 @@
export default Ember.Component.extend({
- _parse: function() {
+ didInsertElement() {
+ this._super();
Ember.run.next(null, () => {
this.$().find('hr').remove();
this.$().ellipsis();
});
- }.on('didInsertElement'),
-
- render(buffer) {
- buffer.push(this.get('text'));
}
});
diff --git a/app/assets/javascripts/discourse/components/topic-closing.js.es6 b/app/assets/javascripts/discourse/components/topic-closing.js.es6
index b92f774035..f4ab5748ce 100644
--- a/app/assets/javascripts/discourse/components/topic-closing.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-closing.js.es6
@@ -1,6 +1,6 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
elementId: 'topic-closing-info',
delayedRerender: null,
@@ -9,7 +9,7 @@ export default Ember.Component.extend(StringBuffer, {
'topic.details.auto_close_based_on_last_post',
'topic.details.auto_close_hours'],
- renderString(buffer) {
+ buildBuffer(buffer) {
if (!!Ember.isEmpty(this.get('topic.details.auto_close_at'))) return;
if (this.get("topic.closed")) return;
@@ -48,4 +48,4 @@ export default Ember.Component.extend(StringBuffer, {
Em.run.cancel(this.get('delayedRerender'));
}
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 b/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6
index 1b41ae04dc..d9aad34dcc 100644
--- a/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6
@@ -1,23 +1,52 @@
-import ContainerView from 'discourse/views/container';
+import computed from 'ember-addons/ember-computed-decorators';
-export default ContainerView.extend({
+export default Ember.Component.extend({
elementId: 'topic-footer-buttons',
+ // Allow us to extend it
+ layoutName: 'components/topic-footer-buttons',
+
init() {
this._super();
- if (this.currentUser) {
- const viewArgs = this.getProperties('topic', 'topicDelegated');
- viewArgs.currentUser = this.currentUser;
+ this._actions = this._actions || {};
- this.attachViewWithArgs(viewArgs, 'topic-footer-main-buttons');
- this.attachViewWithArgs(viewArgs, 'pinned-button');
- this.attachViewWithArgs(viewArgs, 'topic-notifications-button');
+ (this.get('topicDelegated') || []).forEach(m => {
+ this._actions[m] = function() {
+ this.sendAction(m);
+ };
+ this.set(m, m);
+ });
+ },
+
+ @computed('topic.details.can_invite_to')
+ canInviteTo(result) {
+ return !this.site.mobileView && result;
+ },
+
+ inviteDisabled: Ember.computed.or('topic.archived', 'topic.closed', 'topic.deleted'),
+
+ @computed
+ showAdminButton() {
+ return !this.site.mobileView && this.currentUser.get('canManageTopic');
+ },
+
+ @computed('topic.message_archived')
+ archiveIcon: archived => archived ? '' : 'folder',
+
+ @computed('topic.message_archived')
+ archiveTitle: archived => archived ? 'topic.move_to_inbox.help' : 'topic.archive_message.help',
+
+ @computed('topic.message_archived')
+ archiveLabel: archived => archived ? "topic.move_to_inbox.title" : "topic.archive_message.title",
+
+ @computed('topic.bookmarked')
+ bookmarkClass: bookmarked => bookmarked ? 'bookmark bookmarked' : 'bookmark',
+
+ @computed('topic.bookmarked')
+ bookmarkLabel: bookmarked => bookmarked ? 'bookmarked.clear_bookmarks' : 'bookmarked.title',
+
+ @computed('topic.bookmarked')
+ bookmarkTitle: bookmarked => bookmarked ? "bookmarked.help.unbookmark" : "bookmarked.help.bookmark",
- this.trigger('additionalButtons', this);
- } else {
- // If not logged in give them a login control
- this.attachViewClass('login-reply-button');
- }
- }
});
diff --git a/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 b/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6
index 413085aef8..3ed113419e 100644
--- a/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6
@@ -27,7 +27,7 @@ export default Combobox.extend({
}
this.comboTemplate = (item) => {
- const contentItem = content.findProperty('id', item.id);
+ const contentItem = content.findBy('id', item.id);
if (!contentItem) { return item.text; }
return `${iconHTML(contentItem.icon)} ${item.text}`;
};
@@ -59,7 +59,7 @@ export default Combobox.extend({
refresh();
break;
case 'flag':
- controller.send('showFlagTopic', topic);
+ controller.send('showFlagTopic');
refresh();
break;
}
diff --git a/app/assets/javascripts/discourse/components/topic-list-item.js.es6 b/app/assets/javascripts/discourse/components/topic-list-item.js.es6
index 06f9b4bfa6..1fc7cf53a6 100644
--- a/app/assets/javascripts/discourse/components/topic-list-item.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-list-item.js.es6
@@ -1,5 +1,5 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
import computed from 'ember-addons/ember-computed-decorators';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
export function showEntrance(e) {
let target = $(e.target);
@@ -16,17 +16,23 @@ export function showEntrance(e) {
}
}
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
rerenderTriggers: ['bulkSelectEnabled', 'topic.pinned'],
tagName: 'tr',
- rawTemplate: 'list/topic-list-item.raw',
classNameBindings: [':topic-list-item', 'unboundClassNames'],
attributeBindings: ['data-topic-id'],
'data-topic-id': Em.computed.alias('topic.id'),
actions: {
toggleBookmark() {
- this.get('topic').toggleBookmark().finally(() => this.rerender());
+ this.get('topic').toggleBookmark().finally(() => this.rerenderBuffer());
+ }
+ },
+
+ buildBuffer(buffer) {
+ const template = Discourse.__container__.lookup('template:list/topic-list-item.raw');
+ if (template) {
+ buffer.push(template(this));
}
},
@@ -142,4 +148,4 @@ export default Ember.Component.extend(StringBuffer, {
}
}.on('didInsertElement')
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/topic-list.js.es6 b/app/assets/javascripts/discourse/components/topic-list.js.es6
index 0f080e83af..522efc4346 100644
--- a/app/assets/javascripts/discourse/components/topic-list.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-list.js.es6
@@ -32,7 +32,7 @@ export default Ember.Component.extend({
return this.get('order') === "op_likes";
}.property('order'),
- @observes('topics.@each')
+ @observes('topics.[]')
topicsAdded() {
// special case so we don't keep scanning huge lists
if (!this.get('lastVisitedTopic')) {
diff --git a/app/assets/javascripts/discourse/components/topic-navigation.js.es6 b/app/assets/javascripts/discourse/components/topic-navigation.js.es6
index c7b28ca17c..1dd1e81216 100644
--- a/app/assets/javascripts/discourse/components/topic-navigation.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-navigation.js.es6
@@ -5,6 +5,8 @@ export default Ember.Component.extend({
info: Em.Object.create(),
_checkSize() {
+ if (!this.element || this.isDestroying || this.isDestroyed) { return; }
+
let info = this.get('info');
if (info.get('topicProgressExpanded')) {
@@ -47,7 +49,7 @@ export default Ember.Component.extend({
if (this.get('info.topicProgressExpanded')) {
$(window).on('click.hide-fullscreen', (e) => {
if ( $(e.target).is('.topic-timeline') ||
- !$(e.target).parents().is('.timeline-container, #topic-progress-wrapper')) {
+ !$(e.target).parents().is('#topic-progress-wrapper')) {
this._collapseFullscreen();
}
});
@@ -110,7 +112,7 @@ export default Ember.Component.extend({
$('#reply-control').on('div-resized.discourse-topic-navigation', () => this._checkSize());
}
- this._checkSize();
+ Ember.run.scheduleOnce('afterRender', this, this._checkSize);
},
willDestroyElement() {
diff --git a/app/assets/javascripts/discourse/components/topic-post-badges.js.es6 b/app/assets/javascripts/discourse/components/topic-post-badges.js.es6
index 333967ff5a..9eb07ade4f 100644
--- a/app/assets/javascripts/discourse/components/topic-post-badges.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-post-badges.js.es6
@@ -1,4 +1,4 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
// Creates a link
function link(buffer, prop, url, cssClass, i18nKey, text) {
@@ -7,15 +7,15 @@ function link(buffer, prop, url, cssClass, i18nKey, text) {
buffer.push(`${text || prop}\n`);
}
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
tagName: 'span',
classNameBindings: [':topic-post-badges'],
rerenderTriggers: ['url', 'unread', 'newPosts', 'unseen'],
- renderString(buffer) {
+ buildBuffer(buffer) {
const url = this.get('url');
link(buffer, this.get('unread'), url, 'unread', 'unread_posts');
link(buffer, this.get('newPosts'), url, 'new-posts', 'new_posts');
link(buffer, this.get('unseen'), url, 'new-topic', 'new', I18n.t('filters.new.lower_title'));
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/topic-status.js.es6 b/app/assets/javascripts/discourse/components/topic-status.js.es6
index 2fa076736f..5afba3db76 100644
--- a/app/assets/javascripts/discourse/components/topic-status.js.es6
+++ b/app/assets/javascripts/discourse/components/topic-status.js.es6
@@ -1,8 +1,8 @@
import { iconHTML } from 'discourse-common/helpers/fa-icon';
-import StringBuffer from 'discourse/mixins/string-buffer';
+import { bufferedRender } from 'discourse-common/lib/buffered-render';
import { escapeExpression } from 'discourse/lib/utilities';
-export default Ember.Component.extend(StringBuffer, {
+export default Ember.Component.extend(bufferedRender({
classNames: ['topic-statuses'],
rerenderTriggers: ['topic.archived', 'topic.closed', 'topic.pinned', 'topic.visible', 'topic.unpinned', 'topic.is_warning'],
@@ -26,7 +26,7 @@ export default Ember.Component.extend(StringBuffer, {
return Discourse.User.current() && !this.get('disableActions');
}.property('disableActions'),
- renderString(buffer) {
+ buildBuffer(buffer) {
const self = this;
const renderIcon = function(name, key, actionable) {
@@ -57,4 +57,4 @@ export default Ember.Component.extend(StringBuffer, {
renderIconIf('topic.unpinned', 'thumb-tack', 'unpinned', this.get("canAct"));
renderIconIf('topic.invisible', 'eye-slash', 'invisible');
}
-});
+}));
diff --git a/app/assets/javascripts/discourse/components/visible.js.es6 b/app/assets/javascripts/discourse/components/visible.js.es6
deleted file mode 100644
index f9570e412e..0000000000
--- a/app/assets/javascripts/discourse/components/visible.js.es6
+++ /dev/null
@@ -1,12 +0,0 @@
-export default Ember.Component.extend({
- visibleChanged: function(){
- this.rerender();
- }.observes("visible"),
-
- render: function(buffer){
- if (this._state !== 'inDOM' && this._state !== 'preRender' && this._state !== 'inBuffer') { return; }
- if (!this.get("visible")) { return; }
-
- return this._super(buffer);
- }
-});
diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6
index 086e353c07..f7f79f14c4 100644
--- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6
+++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6
@@ -5,7 +5,7 @@ export default Ember.Controller.extend({
queryParams: ['username'],
noMoreBadges: false,
userBadges: null,
- needs: ["application"],
+ application: Ember.inject.controller(),
@computed('username')
user(username) {
@@ -55,7 +55,7 @@ export default Ember.Controller.extend({
@observes('canLoadMore')
_showFooter() {
- this.set("controllers.application.showFooter", !this.get("canLoadMore"));
+ this.set("application.showFooter", !this.get("canLoadMore"));
}
});
diff --git a/app/assets/javascripts/discourse/controllers/bulk-notification-level.js.es6 b/app/assets/javascripts/discourse/controllers/bulk-notification-level.js.es6
index d4a3ebbd2a..cd0cf9c11b 100644
--- a/app/assets/javascripts/discourse/controllers/bulk-notification-level.js.es6
+++ b/app/assets/javascripts/discourse/controllers/bulk-notification-level.js.es6
@@ -3,7 +3,7 @@ import { topicLevels } from 'discourse/lib/notification-levels';
// Support for changing the notification level of various topics
export default Ember.Controller.extend({
- needs: ['topic-bulk-actions'],
+ topicBulkActions: Ember.inject.controller(),
notificationLevelId: null,
@computed
@@ -21,7 +21,7 @@ export default Ember.Controller.extend({
actions: {
changeNotificationLevel() {
- this.get('controllers.topic-bulk-actions').performAndRefresh({
+ this.get('topicBulkActions').performAndRefresh({
type: 'change_notification_level',
notification_level_id: this.get('notificationLevelId')
});
diff --git a/app/assets/javascripts/discourse/controllers/change-owner.js.es6 b/app/assets/javascripts/discourse/controllers/change-owner.js.es6
index 532b21a0bb..84c323b88a 100644
--- a/app/assets/javascripts/discourse/controllers/change-owner.js.es6
+++ b/app/assets/javascripts/discourse/controllers/change-owner.js.es6
@@ -4,9 +4,7 @@ import DiscourseURL from 'discourse/lib/url';
// Modal related to changing the ownership of posts
export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, {
- needs: ['topic'],
-
- topicController: Em.computed.alias('controllers.topic'),
+ topicController: Ember.inject.controller('topic'),
selectedPosts: Em.computed.alias('topicController.selectedPosts'),
saving: false,
new_user: null,
diff --git a/app/assets/javascripts/discourse/controllers/change-timestamp.js.es6 b/app/assets/javascripts/discourse/controllers/change-timestamp.js.es6
index 1cd859cfa6..c24cf785c9 100644
--- a/app/assets/javascripts/discourse/controllers/change-timestamp.js.es6
+++ b/app/assets/javascripts/discourse/controllers/change-timestamp.js.es6
@@ -4,9 +4,8 @@ import DiscourseURL from 'discourse/lib/url';
// Modal related to changing the timestamp of posts
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ['topic'],
- topicController: Em.computed.alias('controllers.topic'),
+ topicController: Ember.inject.controller('topic'),
saving: false,
date: '',
time: '',
diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6
index c04063ed1b..30a5c7af93 100644
--- a/app/assets/javascripts/discourse/controllers/composer.js.es6
+++ b/app/assets/javascripts/discourse/controllers/composer.js.es6
@@ -51,7 +51,9 @@ export function addPopupMenuOptionsCallback(callback) {
}
export default Ember.Controller.extend({
- needs: ['modal', 'topic', 'application'],
+ topicController: Ember.inject.controller('topic'),
+ application: Ember.inject.controller(),
+
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Composer.REPLY_AS_NEW_TOPIC_KEY),
checkedMessages: false,
messageCount: null,
@@ -102,7 +104,7 @@ export default Ember.Controller.extend({
}
}),
- topicModel: Ember.computed.alias('controllers.topic.model'),
+ topicModel: Ember.computed.alias('topicController.model'),
@computed('model.canEditTitle', 'model.creatingPrivateMessage')
canEditTags(canEditTitle, creatingPrivateMessage) {
@@ -484,7 +486,7 @@ export default Ember.Controller.extend({
self.appEvents.one('composer:will-open', () => bootbox.alert(error));
});
- if (this.get('controllers.application.currentRouteName').split('.')[0] === 'topic' &&
+ if (this.get('application.currentRouteName').split('.')[0] === 'topic' &&
composer.get('topic.id') === this.get('topicModel.id')) {
staged = composer.get('stagedPost');
}
@@ -616,10 +618,10 @@ export default Ember.Controller.extend({
let category;
if (!splitCategory[1]) {
- category = this.site.get('categories').findProperty('nameLower', splitCategory[0].toLowerCase());
+ category = this.site.get('categories').findBy('nameLower', splitCategory[0].toLowerCase());
} else {
const categories = Discourse.Category.list();
- const mainCategory = categories.findProperty('nameLower', splitCategory[0].toLowerCase());
+ const mainCategory = categories.findBy('nameLower', splitCategory[0].toLowerCase());
category = categories.find(function(item) {
return item && item.get('nameLower') === splitCategory[1].toLowerCase() && item.get('parent_category_id') === mainCategory.id;
});
diff --git a/app/assets/javascripts/discourse/controllers/create-account.js.es6 b/app/assets/javascripts/discourse/controllers/create-account.js.es6
index 9bed6142a4..3135eb0f95 100644
--- a/app/assets/javascripts/discourse/controllers/create-account.js.es6
+++ b/app/assets/javascripts/discourse/controllers/create-account.js.es6
@@ -7,7 +7,7 @@ import { emailValid } from 'discourse/lib/utilities';
import InputValidation from 'discourse/models/input-validation';
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ['login'],
+ login: Ember.inject.controller(),
uniqueUsernameValidation: null,
globalNicknameExists: false,
@@ -56,7 +56,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
// Validate required fields
let userFields = this.get('userFields');
- if (userFields) { userFields = userFields.filterProperty('field.required'); }
+ if (userFields) { userFields = userFields.filterBy('field.required'); }
if (!Ember.isEmpty(userFields)) {
const anyEmpty = userFields.any(function(uf) {
const val = uf.get('value');
@@ -345,7 +345,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
actions: {
externalLogin(provider) {
- this.get('controllers.login').send('externalLogin', provider);
+ this.get('login').send('externalLogin', provider);
},
createAccount() {
diff --git a/app/assets/javascripts/discourse/controllers/discovery-sortable.js.es6 b/app/assets/javascripts/discourse/controllers/discovery-sortable.js.es6
index 5ac8d4b733..91fd948990 100644
--- a/app/assets/javascripts/discourse/controllers/discovery-sortable.js.es6
+++ b/app/assets/javascripts/discourse/controllers/discovery-sortable.js.es6
@@ -1,5 +1,5 @@
// Just add query params here to have them automatically passed to topic list filters.
-export var queryParams = {
+export const queryParams = {
order: { replace: true, refreshModel: true },
ascending: { replace: true, refreshModel: true },
status: { replace: true, refreshModel: true },
@@ -10,12 +10,12 @@ export var queryParams = {
};
// Basic controller options
-var controllerOpts = {
- needs: ['discovery/topics'],
+const controllerOpts = {
+ discoveryTopics: Ember.inject.controller('discovery/topics'),
queryParams: Object.keys(queryParams),
};
// Aliases for the values
-controllerOpts.queryParams.forEach(p => controllerOpts[p] = Em.computed.alias(`controllers.discovery/topics.${p}`));
+controllerOpts.queryParams.forEach(p => controllerOpts[p] = Ember.computed.alias(`discoveryTopics.${p}`));
export default Ember.Controller.extend(controllerOpts);
diff --git a/app/assets/javascripts/discourse/controllers/discovery.js.es6 b/app/assets/javascripts/discourse/controllers/discovery.js.es6
index 2be7bfd206..79128e82ad 100644
--- a/app/assets/javascripts/discourse/controllers/discovery.js.es6
+++ b/app/assets/javascripts/discourse/controllers/discovery.js.es6
@@ -1,16 +1,19 @@
import DiscourseURL from 'discourse/lib/url';
export default Ember.Controller.extend({
- needs: ['navigation/category', 'discovery/topics', 'application'],
+ discoveryTopics: Ember.inject.controller('discovery/topics'),
+ navigationCategory: Ember.inject.controller('navigation/category'),
+ application: Ember.inject.controller(),
+
loading: false,
- category: Em.computed.alias('controllers.navigation/category.category'),
- noSubcategories: Em.computed.alias('controllers.navigation/category.noSubcategories'),
+ category: Em.computed.alias('navigationCategory.category'),
+ noSubcategories: Em.computed.alias('navigationCategory.noSubcategories'),
- loadedAllItems: Em.computed.not("controllers.discovery/topics.model.canLoadMore"),
+ loadedAllItems: Em.computed.not("discoveryTopics.model.canLoadMore"),
_showFooter: function() {
- this.set("controllers.application.showFooter", this.get("loadedAllItems"));
+ this.set("application.showFooter", this.get("loadedAllItems"));
}.observes("loadedAllItems"),
showMoreUrl(period) {
diff --git a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6
index 2202a0793e..5b435b8d9a 100644
--- a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6
+++ b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6
@@ -2,7 +2,7 @@ import computed from 'ember-addons/ember-computed-decorators';
import DiscoveryController from 'discourse/controllers/discovery';
export default DiscoveryController.extend({
- needs: ['modal', 'discovery'],
+ discovery: Ember.inject.controller(),
// this makes sure the composer isn't scoping to a specific category
category: null,
@@ -20,7 +20,10 @@ export default DiscoveryController.extend({
@computed("model.parentCategory")
categoryPageStyle(parentCategory) {
const style = this.siteSettings.desktop_category_page_style;
- return parentCategory && style === "categories_and_latest_topics" ? "categories_only" : style;
+ const componentName = (parentCategory && style === "categories_and_latest_topics") ?
+ "categories_only" :
+ style;
+ return Ember.String.dasherize(componentName);
}
});
diff --git a/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6
index 008ab29a3b..4c92f6da87 100644
--- a/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6
+++ b/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6
@@ -5,13 +5,14 @@ import { endWith } from 'discourse/lib/computed';
import showModal from 'discourse/lib/show-modal';
const controllerOpts = {
- needs: ['discovery'],
+ discovery: Ember.inject.controller(),
+ discoveryTopics: Ember.inject.controller('discovery/topics'),
+
period: null,
- canStar: Em.computed.alias('controllers.discovery/topics.currentUser.id'),
- showTopicPostBadges: Em.computed.not('controllers.discovery/topics.new'),
-
- redirectedReason: Em.computed.alias('currentUser.redirected_to_top.reason'),
+ canStar: Ember.computed.alias('currentUser.id'),
+ showTopicPostBadges: Ember.computed.not('discoveryTopics.new'),
+ redirectedReason: Ember.computed.alias('currentUser.redirected_to_top.reason'),
order: 'default',
ascending: false,
@@ -46,12 +47,12 @@ const controllerOpts = {
this.setProperties({ order: "default", ascending: false });
// Don't refresh if we're still loading
- if (this.get('controllers.discovery.loading')) { return; }
+ if (this.get('discovery.loading')) { return; }
// If we `send('loading')` here, due to returning true it bubbles up to the
// router and ember throws an error due to missing `handlerInfos`.
// Lesson learned: Don't call `loading` yourself.
- this.set('controllers.discovery.loading', true);
+ this.set('discovery.loading', true);
this.store.findFiltered('topicList', {filter}).then(list => {
const TopicList = require('discourse/models/topic-list').default;
diff --git a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 b/app/assets/javascripts/discourse/controllers/edit-category.js.es6
index d77783bc0a..cdc773d592 100644
--- a/app/assets/javascripts/discourse/controllers/edit-category.js.es6
+++ b/app/assets/javascripts/discourse/controllers/edit-category.js.es6
@@ -20,9 +20,9 @@ export default Ember.Controller.extend(ModalFunctionality, {
changeSize: function() {
if (!Ember.isEmpty(this.get('model.description'))) {
- this.set('controllers.modal.modalClass', 'edit-category-modal full');
+ this.set('modal.modalClass', 'edit-category-modal full');
} else {
- this.set('controllers.modal.modalClass', 'edit-category-modal small');
+ this.set('modal.modalClass', 'edit-category-modal small');
}
}.observes('model.description'),
@@ -34,7 +34,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
}.property('model.id', 'model.name'),
titleChanged: function() {
- this.set('controllers.modal.title', this.get('title'));
+ this.set('modal.title', this.get('title'));
}.observes('title'),
disabled: function() {
diff --git a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6
index bb195b636b..997f2a0888 100644
--- a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6
+++ b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6
@@ -5,7 +5,7 @@ import computed from 'ember-addons/ember-computed-decorators';
import InputValidation from 'discourse/models/input-validation';
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ["topic"],
+ topicController: Ember.inject.controller('topic'),
loading: true,
pinnedInCategoryCount: 0,
@@ -106,7 +106,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
},
_forwardAction(name) {
- this.get("controllers.topic").send(name);
+ this.get("topicController").send(name);
this.send("closeModal");
},
diff --git a/app/assets/javascripts/discourse/controllers/flag.js.es6 b/app/assets/javascripts/discourse/controllers/flag.js.es6
index a5119b383e..760390d3d4 100644
--- a/app/assets/javascripts/discourse/controllers/flag.js.es6
+++ b/app/assets/javascripts/discourse/controllers/flag.js.es6
@@ -20,7 +20,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
let flagsAvailable = this.get('model.flagsAvailable');
// "message user" option should be at the top
- const notifyUserIndex = flagsAvailable.indexOf(flagsAvailable.filterProperty('name_key', 'notify_user')[0]);
+ const notifyUserIndex = flagsAvailable.indexOf(flagsAvailable.filterBy('name_key', 'notify_user')[0]);
if (notifyUserIndex !== -1) {
const notifyUser = flagsAvailable[notifyUserIndex];
flagsAvailable.splice(notifyUserIndex, 1);
@@ -93,7 +93,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
let postAction; // an instance of ActionSummary
if (!this.get('flagTopic')) {
- postAction = this.get('model.actions_summary').findProperty('id', this.get('selected.id'));
+ postAction = this.get('model.actions_summary').findBy('id', this.get('selected.id'));
} else {
postAction = this.get('topicActionByName.' + this.get('selected.name_key'));
}
diff --git a/app/assets/javascripts/discourse/controllers/full-page-search.js.es6 b/app/assets/javascripts/discourse/controllers/full-page-search.js.es6
index d699866126..91e5b907d2 100644
--- a/app/assets/javascripts/discourse/controllers/full-page-search.js.es6
+++ b/app/assets/javascripts/discourse/controllers/full-page-search.js.es6
@@ -14,7 +14,7 @@ const SortOrders = [
];
export default Ember.Controller.extend({
- needs: ["application"],
+ application: Ember.inject.controller(),
bulkSelectEnabled: null,
loading: Em.computed.not("model"),
@@ -131,7 +131,7 @@ export default Ember.Controller.extend({
@observes('loading')
_showFooter() {
- this.set("controllers.application.showFooter", !this.get("loading"));
+ this.set("application.showFooter", !this.get("loading"));
},
@computed('hasResults')
diff --git a/app/assets/javascripts/discourse/controllers/group-posts.js.es6 b/app/assets/javascripts/discourse/controllers/group-posts.js.es6
index c9e791c1f1..c2434c83c6 100644
--- a/app/assets/javascripts/discourse/controllers/group-posts.js.es6
+++ b/app/assets/javascripts/discourse/controllers/group-posts.js.es6
@@ -1,19 +1,18 @@
import { fmt } from 'discourse/lib/computed';
-export default Ember.ArrayController.extend({
- needs: ['group'],
+export default Ember.Controller.extend({
+ group: Ember.inject.controller(),
loading: false,
emptyText: fmt('type', 'groups.empty.%@'),
actions: {
loadMore() {
-
if (this.get('loading')) { return; }
this.set('loading', true);
const posts = this.get('model');
if (posts && posts.length) {
const beforePostId = posts[posts.length-1].get('id');
- const group = this.get('controllers.group.model');
+ const group = this.get('group.model');
const opts = { beforePostId, type: this.get('type') };
group.findPosts(opts).then(newPosts => {
diff --git a/app/assets/javascripts/discourse/controllers/invite.js.es6 b/app/assets/javascripts/discourse/controllers/invite.js.es6
index cd4c6afec3..03d848e6a2 100644
--- a/app/assets/javascripts/discourse/controllers/invite.js.es6
+++ b/app/assets/javascripts/discourse/controllers/invite.js.es6
@@ -2,7 +2,7 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
import { emailValid } from 'discourse/lib/utilities';
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ['user-invited-show'],
+ userInvitedShow: Ember.inject.controller('user-invited-show'),
// If this isn't defined, it will proxy to the user model on the preferences
// page which is wrong.
@@ -169,7 +169,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
if (this.get('disabled')) { return; }
const groupNames = this.get('model.groupNames'),
- userInvitedController = this.get('controllers.user-invited-show'),
+ userInvitedController = this.get('userInvitedShow'),
model = this.get('model');
model.setProperties({ saving: true, error: false });
@@ -215,7 +215,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
if (this.get('disabled')) { return; }
const groupNames = this.get('model.groupNames'),
- userInvitedController = this.get('controllers.user-invited-show'),
+ userInvitedController = this.get('userInvitedShow'),
model = this.get('model');
var topicId = null;
diff --git a/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js.es6 b/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js.es6
index 5e0414bcd0..7a50811e57 100644
--- a/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js.es6
+++ b/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js.es6
@@ -1,9 +1,7 @@
import ModalFunctionality from 'discourse/mixins/modal-functionality';
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ['modal'],
-
- onShow: function() {
- this.set('controllers.modal.modalClass', 'keyboard-shortcuts-modal');
+ onShow() {
+ this.set('modal.modalClass', 'keyboard-shortcuts-modal');
}
});
diff --git a/app/assets/javascripts/discourse/controllers/login.js.es6 b/app/assets/javascripts/discourse/controllers/login.js.es6
index 8909993cca..1996e723b6 100644
--- a/app/assets/javascripts/discourse/controllers/login.js.es6
+++ b/app/assets/javascripts/discourse/controllers/login.js.es6
@@ -11,13 +11,17 @@ const AuthErrors =
'not_allowed_from_ip_address'];
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ['modal', 'createAccount', 'forgotPassword', 'application'],
+
+ createAccount: Ember.inject.controller(),
+ forgotPassword: Ember.inject.controller(),
+ application: Ember.inject.controller(),
+
authenticate: null,
loggingIn: false,
loggedIn: false,
canLoginLocal: setting('enable_local_logins'),
- loginRequired: Em.computed.alias('controllers.application.loginRequired'),
+ loginRequired: Em.computed.alias('application.loginRequired'),
resetForm: function() {
this.set('authenticate', null);
@@ -37,7 +41,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
loginDisabled: Em.computed.or('loggingIn', 'loggedIn'),
showSignupLink: function() {
- return this.get('controllers.application.canSignUp') &&
+ return this.get('application.canSignUp') &&
!this.get('loggingIn') &&
Ember.isEmpty(this.get('authenticate'));
}.property('loggingIn', 'authenticate'),
@@ -160,7 +164,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
},
createAccount: function() {
- const createAccountController = this.get('controllers.createAccount');
+ const createAccountController = this.get('createAccount');
if (createAccountController) {
createAccountController.resetForm();
const loginName = this.get('loginName');
@@ -174,7 +178,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
},
forgotPassword: function() {
- const forgotPasswordController = this.get('controllers.forgotPassword');
+ const forgotPasswordController = this.get('forgotPassword');
if (forgotPasswordController) { forgotPasswordController.set("accountEmailOrUsername", this.get("loginName")); }
this.send("showForgotPassword");
}
@@ -182,7 +186,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
authMessage: (function() {
if (Ember.isEmpty(this.get('authenticate'))) return "";
- const method = findAll(this.siteSettings, this.capabilities, this.isMobileDevice).findProperty("name", this.get("authenticate"));
+ const method = findAll(this.siteSettings, this.capabilities, this.isMobileDevice).findBy("name", this.get("authenticate"));
if(method){
return method.get('message');
}
@@ -229,7 +233,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
return;
}
- const createAccountController = this.get('controllers.createAccount');
+ const createAccountController = this.get('createAccount');
createAccountController.setProperties({
accountEmail: options.email,
accountUsername: options.username,
diff --git a/app/assets/javascripts/discourse/controllers/merge-topic.js.es6 b/app/assets/javascripts/discourse/controllers/merge-topic.js.es6
index 197c9fcb37..34bfa8ba34 100644
--- a/app/assets/javascripts/discourse/controllers/merge-topic.js.es6
+++ b/app/assets/javascripts/discourse/controllers/merge-topic.js.es6
@@ -5,12 +5,11 @@ import DiscourseURL from 'discourse/lib/url';
// Modal related to merging of topics
export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, {
- needs: ['topic'],
+ topicController: Ember.inject.controller('topic'),
saving: false,
selectedTopicId: null,
- topicController: Em.computed.alias('controllers.topic'),
selectedPosts: Em.computed.alias('topicController.selectedPosts'),
selectedReplies: Em.computed.alias('topicController.selectedReplies'),
allPostsSelected: Em.computed.alias('topicController.allPostsSelected'),
@@ -26,7 +25,7 @@ export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, {
}.property('saving'),
onShow() {
- this.set('controllers.modal.modalClass', 'split-modal');
+ this.set('modal.modalClass', 'split-modal');
},
actions: {
diff --git a/app/assets/javascripts/discourse/controllers/navigation/default.js.es6 b/app/assets/javascripts/discourse/controllers/navigation/default.js.es6
index 1d23c1fb2b..93ae014e47 100644
--- a/app/assets/javascripts/discourse/controllers/navigation/default.js.es6
+++ b/app/assets/javascripts/discourse/controllers/navigation/default.js.es6
@@ -1,7 +1,8 @@
import computed from "ember-addons/ember-computed-decorators";
export default Ember.Controller.extend({
- needs: ['discovery', 'discovery/topics'],
+ discovery: Ember.inject.controller(),
+ discoveryTopics: Ember.inject.controller('discovery/topics'),
@computed()
categories() {
diff --git a/app/assets/javascripts/discourse/controllers/preferences.js.es6 b/app/assets/javascripts/discourse/controllers/preferences.js.es6
index b94d993ed1..4e96336563 100644
--- a/app/assets/javascripts/discourse/controllers/preferences.js.es6
+++ b/app/assets/javascripts/discourse/controllers/preferences.js.es6
@@ -25,7 +25,7 @@ export default Ember.Controller.extend(CanCheckEmails, {
// Staff can edit fields that are not `editable`
if (!this.get('currentUser.staff')) {
- siteUserFields = siteUserFields.filterProperty('editable', true);
+ siteUserFields = siteUserFields.filterBy('editable', true);
}
return siteUserFields.sortBy('position').map(function(field) {
const value = userFields ? userFields[field.get('id').toString()] : null;
@@ -79,7 +79,8 @@ export default Ember.Controller.extend(CanCheckEmails, {
mailingListModeOptions() {
return [
{name: I18n.t('user.mailing_list_mode.daily'), value: 0},
- {name: this.get('frequencyEstimate'), value: 1}
+ {name: this.get('frequencyEstimate'), value: 1},
+ {name: I18n.t('user.mailing_list_mode.individual_no_echo'), value: 2}
];
},
diff --git a/app/assets/javascripts/discourse/controllers/preferences/badge-title.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/badge-title.js.es6
index b71660d17f..f2c543e6be 100644
--- a/app/assets/javascripts/discourse/controllers/preferences/badge-title.js.es6
+++ b/app/assets/javascripts/discourse/controllers/preferences/badge-title.js.es6
@@ -1,27 +1,26 @@
import { ajax } from 'discourse/lib/ajax';
import BadgeSelectController from "discourse/mixins/badge-select-controller";
-export default Ember.ArrayController.extend(BadgeSelectController, {
+export default Ember.Controller.extend(BadgeSelectController, {
filteredList: function() {
return this.get('model').filterBy('badge.allow_title', true);
}.property('model'),
actions: {
- save: function() {
+ save() {
this.setProperties({ saved: false, saving: true });
- var self = this;
ajax(this.get('user.path') + "/preferences/badge_title", {
type: "PUT",
- data: { user_badge_id: self.get('selectedUserBadgeId') }
- }).then(function() {
- self.setProperties({
+ data: { user_badge_id: this.get('selectedUserBadgeId') }
+ }).then(() => {
+ this.setProperties({
saved: true,
saving: false,
- "user.title": self.get('selectedUserBadge.badge.name')
+ "user.title": this.get('selectedUserBadge.badge.name')
});
- }, function() {
+ }, () => {
bootbox.alert(I18n.t('generic_error'));
});
}
diff --git a/app/assets/javascripts/discourse/controllers/preferences/card-badge.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/card-badge.js.es6
index d0c42fb558..9f820f9647 100644
--- a/app/assets/javascripts/discourse/controllers/preferences/card-badge.js.es6
+++ b/app/assets/javascripts/discourse/controllers/preferences/card-badge.js.es6
@@ -1,7 +1,7 @@
import { ajax } from 'discourse/lib/ajax';
import BadgeSelectController from "discourse/mixins/badge-select-controller";
-export default Ember.ArrayController.extend(BadgeSelectController, {
+export default Ember.Controller.extend(BadgeSelectController, {
filteredList: function() {
return this.get('model').filter(function(b) {
return !Ember.isEmpty(b.get('badge.image'));
@@ -12,18 +12,17 @@ export default Ember.ArrayController.extend(BadgeSelectController, {
save: function() {
this.setProperties({ saved: false, saving: true });
- var self = this;
ajax(this.get('user.path') + "/preferences/card-badge", {
type: "PUT",
- data: { user_badge_id: self.get('selectedUserBadgeId') }
- }).then(function() {
- self.setProperties({
+ data: { user_badge_id: this.get('selectedUserBadgeId') }
+ }).then(() => {
+ this.setProperties({
saved: true,
saving: false,
- "user.card_image_badge": self.get('selectedUserBadge.badge.image')
+ "user.card_image_badge": this.get('selectedUserBadge.badge.image')
});
- }).catch(function() {
- self.set('saving', false);
+ }).catch(() => {
+ this.set('saving', false);
bootbox.alert(I18n.t('generic_error'));
});
}
diff --git a/app/assets/javascripts/discourse/controllers/quote-button.js.es6 b/app/assets/javascripts/discourse/controllers/quote-button.js.es6
index f3e0447a7f..d91712542e 100644
--- a/app/assets/javascripts/discourse/controllers/quote-button.js.es6
+++ b/app/assets/javascripts/discourse/controllers/quote-button.js.es6
@@ -3,13 +3,14 @@ import computed from 'ember-addons/ember-computed-decorators';
import { selectedText } from 'discourse/lib/utilities';
export default Ember.Controller.extend({
- needs: ['topic', 'composer'],
+ topic: Ember.inject.controller(),
+ composer: Ember.inject.controller(),
@computed('buffer', 'postId')
post(buffer, postId) {
if (!postId || Ember.isEmpty(buffer)) { return null; }
- const postStream = this.get('controllers.topic.model.postStream');
+ const postStream = this.get('topic.model.postStream');
const post = postStream.findLoadedPost(postId);
return post;
@@ -22,7 +23,7 @@ export default Ember.Controller.extend({
if (!this.currentUser) return;
// don't display the "quote-reply" button if we can't reply
- const topicDetails = this.get('controllers.topic.model.details');
+ const topicDetails = this.get('topic.model.details');
if (!(topicDetails.get('can_reply_as_new_topic') || topicDetails.get('can_create_post'))) {
return;
}
@@ -106,7 +107,7 @@ export default Ember.Controller.extend({
// defer load if needed, if in an expanded replies section
if (!post) {
- const postStream = this.get('controllers.topic.model.postStream');
+ const postStream = this.get('topic.model.postStream');
return postStream.loadPost(postId).then(p => {
this.set('post', p);
return this.quoteText();
@@ -114,12 +115,12 @@ export default Ember.Controller.extend({
}
// If we can't create a post, delegate to reply as new topic
- if (!this.get('controllers.topic.model.details.can_create_post')) {
- this.get('controllers.topic').send('replyAsNewTopic', post);
+ if (!this.get('topic.model.details.can_create_post')) {
+ this.get('topic').send('replyAsNewTopic', post);
return;
}
- const composerController = this.get('controllers.composer');
+ const composerController = this.get('composer');
const composerOpts = {
action: Composer.REPLY,
draftKey: post.get('topic.draft_key')
diff --git a/app/assets/javascripts/discourse/controllers/search-help.js.es6 b/app/assets/javascripts/discourse/controllers/search-help.js.es6
index 7f5958ae4d..0d5bb50104 100644
--- a/app/assets/javascripts/discourse/controllers/search-help.js.es6
+++ b/app/assets/javascripts/discourse/controllers/search-help.js.es6
@@ -1,8 +1,6 @@
import ModalFunctionality from 'discourse/mixins/modal-functionality';
export default Ember.Controller.extend(ModalFunctionality, {
- needs: ['modal'],
-
showGoogleSearch: function() {
return !Discourse.SiteSettings.login_required;
}.property()
diff --git a/app/assets/javascripts/discourse/controllers/share.js.es6 b/app/assets/javascripts/discourse/controllers/share.js.es6
index 97f1fb4d26..00dc536364 100644
--- a/app/assets/javascripts/discourse/controllers/share.js.es6
+++ b/app/assets/javascripts/discourse/controllers/share.js.es6
@@ -3,10 +3,10 @@ import { longDateNoYear } from 'discourse/lib/formatter';
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({
- needs: ['topic'],
+ topic: Ember.inject.controller(),
- title: Ember.computed.alias('controllers.topic.model.title'),
- canReplyAsNewTopic: Ember.computed.alias('controllers.topic.model.details.can_reply_as_new_topic'),
+ title: Ember.computed.alias('topic.model.title'),
+ canReplyAsNewTopic: Ember.computed.alias('topic.model.details.can_reply_as_new_topic'),
@computed('type', 'postNumber')
shareTitle(type, postNumber) {
@@ -31,7 +31,7 @@ export default Ember.Controller.extend({
},
replyAsNewTopic() {
- const topicController = this.get("controllers.topic");
+ const topicController = this.get("topic");
const postStream = topicController.get("model.postStream");
const postId = this.get("postId") || postStream.findPostIdForPostNumber(1);
const post = postStream.findLoadedPost(postId);
diff --git a/app/assets/javascripts/discourse/controllers/split-topic.js.es6 b/app/assets/javascripts/discourse/controllers/split-topic.js.es6
index b8a1a72509..c8ea321570 100644
--- a/app/assets/javascripts/discourse/controllers/split-topic.js.es6
+++ b/app/assets/javascripts/discourse/controllers/split-topic.js.es6
@@ -6,12 +6,11 @@ import DiscourseURL from 'discourse/lib/url';
// Modal related to auto closing of topics
export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, {
- needs: ['topic'],
topicName: null,
saving: false,
categoryId: null,
- topicController: Em.computed.alias('controllers.topic'),
+ topicController: Ember.inject.controller('topic'),
selectedPosts: Em.computed.alias('topicController.selectedPosts'),
selectedReplies: Em.computed.alias('topicController.selectedReplies'),
allPostsSelected: Em.computed.alias('topicController.allPostsSelected'),
@@ -28,7 +27,7 @@ export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, {
onShow() {
this.setProperties({
- 'controllers.modal.modalClass': 'split-modal',
+ 'modal.modalClass': 'split-modal',
saving: false,
categoryId: null,
topicName: ''
diff --git a/app/assets/javascripts/discourse/controllers/static.js.es6 b/app/assets/javascripts/discourse/controllers/static.js.es6
index 5b87c64c71..2c31b962c7 100644
--- a/app/assets/javascripts/discourse/controllers/static.js.es6
+++ b/app/assets/javascripts/discourse/controllers/static.js.es6
@@ -2,13 +2,13 @@ import { ajax } from 'discourse/lib/ajax';
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({
- needs: ['application'],
+ application: Ember.inject.controller(),
showLoginButton: Em.computed.equal("model.path", "login"),
@computed("model.path")
showSignupButton() {
- return this.get("model.path") === "login" && this.get('controllers.application.canSignUp');
+ return this.get("model.path") === "login" && this.get('application.canSignUp');
},
actions: {
diff --git a/app/assets/javascripts/discourse/controllers/tag-groups-show.js.es6 b/app/assets/javascripts/discourse/controllers/tag-groups-show.js.es6
index 1eca5728ab..d575844cad 100644
--- a/app/assets/javascripts/discourse/controllers/tag-groups-show.js.es6
+++ b/app/assets/javascripts/discourse/controllers/tag-groups-show.js.es6
@@ -1,5 +1,5 @@
export default Ember.Controller.extend({
- needs: ['tagGroups'],
+ tagGroups: Ember.inject.controller(),
actions: {
save() {
@@ -7,17 +7,16 @@ export default Ember.Controller.extend({
},
destroy() {
- const self = this;
return bootbox.confirm(
I18n.t("tagging.groups.confirm_delete"),
I18n.t("no_value"),
I18n.t("yes_value"),
- function(destroy) {
+ destroy => {
if (destroy) {
- const c = self.controllerFor('tagGroups');
- return self.get('model').destroy().then(function() {
- c.removeObject(self.get('model'));
- self.transitionToRoute('tagGroups');
+ const c = this.get('tagGroups.model');
+ return this.get('model').destroy().then(() => {
+ c.removeObject(this.get('model'));
+ this.transitionToRoute('tagGroups');
});
}
}
diff --git a/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 b/app/assets/javascripts/discourse/controllers/tag-groups.js.es6
index 4e52a8ce47..d4785f36aa 100644
--- a/app/assets/javascripts/discourse/controllers/tag-groups.js.es6
+++ b/app/assets/javascripts/discourse/controllers/tag-groups.js.es6
@@ -1,6 +1,6 @@
-export default Ember.ArrayController.extend({
+export default Ember.Controller.extend({
actions: {
- selectTagGroup: function(tagGroup) {
+ selectTagGroup(tagGroup) {
if (this.get('selectedItem')) { this.get('selectedItem').set('selected', false); }
this.set('selectedItem', tagGroup);
tagGroup.set('selected', true);
@@ -8,10 +8,10 @@ export default Ember.ArrayController.extend({
this.transitionToRoute('tagGroups.show', tagGroup);
},
- newTagGroup: function() {
+ newTagGroup() {
const newTagGroup = this.store.createRecord('tag-group');
newTagGroup.set('name', I18n.t('tagging.groups.new_name'));
- this.pushObject(newTagGroup);
+ this.get('model').pushObject(newTagGroup);
this.send('selectTagGroup', newTagGroup);
}
}
diff --git a/app/assets/javascripts/discourse/controllers/tags-show.js.es6 b/app/assets/javascripts/discourse/controllers/tags-show.js.es6
index f80b98c6c7..0e8e15db50 100644
--- a/app/assets/javascripts/discourse/controllers/tags-show.js.es6
+++ b/app/assets/javascripts/discourse/controllers/tags-show.js.es6
@@ -40,7 +40,7 @@ if (customNavItemHref) {
export default Ember.Controller.extend(BulkTopicSelection, {
- needs: ["application"],
+ application: Ember.inject.controller(),
tag: null,
additionalTags: null,
@@ -81,7 +81,7 @@ export default Ember.Controller.extend(BulkTopicSelection, {
},
_showFooter: function() {
- this.set("controllers.application.showFooter", !this.get("list.canLoadMore"));
+ this.set("application.showFooter", !this.get("list.canLoadMore"));
}.observes("list.canLoadMore"),
footerMessage: function() {
diff --git a/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 b/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6
index e1c710115c..d378084e8a 100644
--- a/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6
+++ b/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6
@@ -17,14 +17,14 @@ addBulkButton('unlistTopics', 'unlist_topics');
addBulkButton('showTagTopics', 'change_tags');
// Modal for performing bulk actions on topics
-export default Ember.ArrayController.extend(ModalFunctionality, {
+export default Ember.Controller.extend(ModalFunctionality, {
tags: null,
buttonRows: null,
emptyTags: Ember.computed.empty('tags'),
onShow() {
- this.set('controllers.modal.modalClass', 'topic-bulk-actions-modal small');
+ this.set('modal.modalClass', 'topic-bulk-actions-modal small');
const buttonRows = [];
let row = [];
@@ -86,7 +86,7 @@ export default Ember.ArrayController.extend(ModalFunctionality, {
showChangeCategory() {
this.send('changeBulkTemplate', 'modal/bulk_change_category');
- this.set('controllers.modal.modalClass', 'topic-bulk-actions-modal full');
+ this.set('modal.modalClass', 'topic-bulk-actions-modal full');
},
showNotificationLevel() {
diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6
index cf634b9832..787196c4a0 100644
--- a/app/assets/javascripts/discourse/controllers/topic.js.es6
+++ b/app/assets/javascripts/discourse/controllers/topic.js.es6
@@ -11,7 +11,10 @@ import { categoryBadgeHTML } from 'discourse/helpers/category-link';
import Post from 'discourse/models/post';
export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
- needs: ['modal', 'composer', 'quote-button', 'application'],
+ composer: Ember.inject.controller(),
+ quoteButton: Ember.inject.controller('quote-button'),
+ application: Ember.inject.controller(),
+
multiSelect: false,
allPostsSelected: false,
editingTopic: false,
@@ -24,6 +27,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
retrying: false,
userTriggeredProgress: null,
_progressIndex: null,
+ hasScrolled: null,
topicDelegated: [
'toggleMultiSelect',
@@ -39,9 +43,14 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
'convertToPrivateMessage',
'jumpTop',
'jumpToPost',
+ 'jumpToPostPrompt',
'jumpToIndex',
'jumpBottom',
- 'replyToPost'
+ 'replyToPost',
+ 'toggleArchiveMessage',
+ 'showInvite',
+ 'toggleBookmark',
+ 'showFlagTopic'
],
_titleChanged: function() {
@@ -265,24 +274,26 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
this.deleteTopic();
},
- archiveMessage() {
+ // Archive a PM (as opposed to archiving a topic)
+ toggleArchiveMessage() {
const topic = this.get('model');
- topic.archiveMessage().then(()=>{
- this.gotoInbox(topic.get("inboxGroupName"));
- });
- },
+ if (topic.get('archiving')) { return; }
- moveToInbox() {
- const topic = this.get('model');
- topic.moveToInbox().then(()=>{
- this.gotoInbox(topic.get("inboxGroupName"));
- });
+ if (topic.get('message_archived')) {
+ topic.moveToInbox().then(()=>{
+ this.gotoInbox(topic.get("inboxGroupName"));
+ });
+ } else {
+ topic.archiveMessage().then(()=>{
+ this.gotoInbox(topic.get("inboxGroupName"));
+ });
+ }
},
// Post related methods
replyToPost(post) {
- const composerController = this.get('controllers.composer'),
- quoteController = this.get('controllers.quote-button'),
+ const composerController = this.get('composer'),
+ quoteController = this.get('quoteButton'),
quotedText = Quote.build(quoteController.get('post'), quoteController.get('buffer')),
topic = post ? post.get('topic') : this.get('model');
@@ -379,7 +390,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
return false;
}
- const composer = this.get('controllers.composer'),
+ const composer = this.get('composer'),
composerModel = composer.get('model'),
opts = {
post: post,
@@ -415,6 +426,14 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
this._jumpToPostId(this.get('model.postStream.stream')[index-1]);
},
+ jumpToPostPrompt() {
+ const postText = prompt(I18n.t('topic.progress.jump_prompt_long'));
+ if (postText === null) { return; }
+ const postNumber = parseInt(postText, 10);
+ if (postNumber === 0) { return; }
+ this._jumpToPostId(this.get('model.postStream').findPostIdForPostNumber(postNumber));
+ },
+
jumpToPost(postNumber) {
this._jumpToPostId(this.get('model.postStream').findPostIdForPostNumber(postNumber));
},
@@ -601,8 +620,8 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
},
replyAsNewTopic(post) {
- const composerController = this.get('controllers.composer');
- const quoteController = this.get('controllers.quote-button');
+ const composerController = this.get('composer');
+ const quoteController = this.get('quoteButton');
post = post || quoteController.get('post');
const quotedText = Quote.build(post, quoteController.get('buffer'));
@@ -761,7 +780,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
const selectedReplies = this.get('selectedReplies');
selectedReplies.removeObject(post);
- const selectedReply = selectedReplies.findProperty('post_number', post.get('reply_to_post_number'));
+ const selectedReply = selectedReplies.findBy('post_number', post.get('reply_to_post_number'));
if (selectedReply) { selectedReplies.removeObject(selectedReply); }
this.set('allPostsSelected', false);
@@ -770,7 +789,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
postSelected(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; }
+ if (this.get('selectedReplies').findBy('post_number', post.get('reply_to_post_number'))) { return true; }
return false;
},
@@ -904,7 +923,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
_showFooter: function() {
const showFooter = this.get("model.postStream.loaded") && this.get("model.postStream.loadedAllPosts");
- this.set("controllers.application.showFooter", showFooter);
+ this.set("application.showFooter", showFooter);
}.observes("model.postStream.{loaded,loadedAllPosts}")
});
diff --git a/app/assets/javascripts/discourse/controllers/upload-customization.js.es6 b/app/assets/javascripts/discourse/controllers/upload-customization.js.es6
index d7a980a0b4..ae7575887a 100644
--- a/app/assets/javascripts/discourse/controllers/upload-customization.js.es6
+++ b/app/assets/javascripts/discourse/controllers/upload-customization.js.es6
@@ -2,7 +2,7 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
export default Ember.Controller.extend(ModalFunctionality, {
notReady: Em.computed.not('ready'),
- needs: ['adminCustomizeCssHtml'],
+ adminCustomizeCssHtml: Ember.inject.controller(),
ready: function() {
try {
@@ -22,7 +22,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
delete object.id;
delete object.key;
- const controller = this.get('controllers.adminCustomizeCssHtml');
+ const controller = this.get('adminCustomizeCssHtml');
controller.send('newCustomization', object);
}
}
diff --git a/app/assets/javascripts/discourse/controllers/user-activity.js.es6 b/app/assets/javascripts/discourse/controllers/user-activity.js.es6
index 55ab7846ca..b899408f42 100644
--- a/app/assets/javascripts/discourse/controllers/user-activity.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-activity.js.es6
@@ -1,11 +1,13 @@
import { exportUserArchive } from 'discourse/lib/export-csv';
export default Ember.Controller.extend({
+ application: Ember.inject.controller(),
+ user: Ember.inject.controller(),
+
userActionType: null,
- needs: ["application", "user"],
- currentPath: Em.computed.alias('controllers.application.currentPath'),
- viewingSelf: Em.computed.alias("controllers.user.viewingSelf"),
- showBookmarks: Em.computed.alias("controllers.user.showBookmarks"),
+ currentPath: Ember.computed.alias('application.currentPath'),
+ viewingSelf: Ember.computed.alias("user.viewingSelf"),
+ showBookmarks: Ember.computed.alias("user.showBookmarks"),
_showFooter: function() {
var showFooter;
@@ -15,7 +17,7 @@ export default Ember.Controller.extend({
} else {
showFooter = this.get("model.statsCountNonPM") <= this.get("model.stream.itemsLoaded");
}
- this.set("controllers.application.showFooter", showFooter);
+ this.set("application.showFooter", showFooter);
}.observes("userActionType", "model.stream.itemsLoaded"),
actions: {
diff --git a/app/assets/javascripts/discourse/controllers/user-badges.js.es6 b/app/assets/javascripts/discourse/controllers/user-badges.js.es6
index 76b2a05cd9..3089a07377 100644
--- a/app/assets/javascripts/discourse/controllers/user-badges.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-badges.js.es6
@@ -1,20 +1,6 @@
-export default Ember.ArrayController.extend({
- needs: ["user"],
- user: Em.computed.alias("controllers.user.model"),
- sortProperties: ['badge.badge_type.sort_order', 'badge.name'],
- orderBy: function(ub1, ub2){
- var sr1 = ub1.get('badge.badge_type.sort_order');
- var sr2 = ub2.get('badge.badge_type.sort_order');
-
-
- if(sr1 > sr2) {
- return -1;
- }
-
- if(sr2 > sr1) {
- return 1;
- }
-
- return ub1.get('badge.name') < ub2.get('badge.name') ? -1 : 1;
- }
+export default Ember.Controller.extend({
+ user: Ember.inject.controller(),
+ username: Ember.computed.alias('user.model.username_lower'),
+ sortedBadges: Ember.computed.sort('model', 'badgeSortOrder'),
+ badgeSortOrder: ['badge.badge_type.sort_order', 'badge.name'],
});
diff --git a/app/assets/javascripts/discourse/controllers/user-card.js.es6 b/app/assets/javascripts/discourse/controllers/user-card.js.es6
index 377ffb97a8..f7d7da11ad 100644
--- a/app/assets/javascripts/discourse/controllers/user-card.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-card.js.es6
@@ -3,7 +3,9 @@ import { propertyNotEqual, setting } from 'discourse/lib/computed';
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({
- needs: ['topic', 'application'],
+ topic: Ember.inject.controller(),
+ application: Ember.inject.controller(),
+
visible: false,
user: null,
username: null,
@@ -15,10 +17,10 @@ export default Ember.Controller.extend({
// If inside a topic
topicPostCount: null,
- postStream: Em.computed.alias('controllers.topic.model.postStream'),
+ postStream: Em.computed.alias('topic.model.postStream'),
enoughPostsForFiltering: Em.computed.gte('topicPostCount', 2),
- viewingTopic: Em.computed.match('controllers.application.currentPath', /^topic\./),
- viewingAdmin: Em.computed.match('controllers.application.currentPath', /^admin\./),
+ viewingTopic: Em.computed.match('application.currentPath', /^topic\./),
+ viewingAdmin: Em.computed.match('application.currentPath', /^admin\./),
showFilter: Em.computed.and('viewingTopic', 'postStream.hasNoFilters', 'enoughPostsForFiltering'),
showName: propertyNotEqual('user.name', 'user.username'),
hasUserFilters: Em.computed.gt('postStream.userFilters.length', 0),
@@ -39,7 +41,7 @@ export default Ember.Controller.extend({
const siteUserFields = this.site.get('user_fields');
if (!Ember.isEmpty(siteUserFields)) {
const userFields = this.get('user.user_fields');
- return siteUserFields.filterProperty('show_on_user_card', true).sortBy('position').map(field => {
+ return siteUserFields.filterBy('show_on_user_card', true).sortBy('position').map(field => {
Ember.set(field, 'dasherized_name', field.get('name').dasherize());
const value = userFields ? userFields[field.get('id')] : null;
return Ember.isEmpty(value) ? null : Ember.Object.create({ value, field });
@@ -97,7 +99,7 @@ export default Ember.Controller.extend({
this.setProperties({ username, userLoading: username, cardTarget: target, post });
const args = { stats: false };
- args.include_post_count_for = this.get('controllers.topic.model.id');
+ args.include_post_count_for = this.get('topic.model.id');
args.skip_track_visit = true;
return Discourse.User.findByUsername(username, args).then((user) => {
diff --git a/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 b/app/assets/javascripts/discourse/controllers/user-notifications.js.es6
index c185d2c29a..44b25f1043 100644
--- a/app/assets/javascripts/discourse/controllers/user-notifications.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-notifications.js.es6
@@ -1,12 +1,12 @@
import { ajax } from 'discourse/lib/ajax';
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
-export default Ember.ArrayController.extend({
- needs: ['application'],
+export default Ember.Controller.extend({
+ application: Ember.inject.controller(),
@observes('model.canLoadMore')
_showFooter() {
- this.set("controllers.application.showFooter", !this.get("model.canLoadMore"));
+ this.set("application.showFooter", !this.get("model.canLoadMore"));
},
@computed('model.content.length')
@@ -16,11 +16,9 @@ export default Ember.ArrayController.extend({
@computed('model.content.@each.read')
allNotificationsRead() {
- return !this.get('model.content').some((notification) => !notification.get('read'));
+ return !this.get('model.content').some(notification => !notification.get('read'));
},
- currentPath: Em.computed.alias('controllers.application.currentPath'),
-
actions: {
resetNew() {
ajax('/notifications/mark-read', { method: 'PUT' }).then(() => {
diff --git a/app/assets/javascripts/discourse/controllers/user-posts.js.es6 b/app/assets/javascripts/discourse/controllers/user-posts.js.es6
index e06143db48..25c730d97a 100644
--- a/app/assets/javascripts/discourse/controllers/user-posts.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-posts.js.es6
@@ -1,7 +1,7 @@
export default Ember.Controller.extend({
- needs: ["application"],
+ application: Ember.inject.controller(),
_showFooter: function() {
- this.set("controllers.application.showFooter", !this.get("model.canLoadMore"));
+ this.set("application.showFooter", !this.get("model.canLoadMore"));
}.observes("model.canLoadMore")
});
diff --git a/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 b/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6
index 18f010adcc..bb79db55d3 100644
--- a/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6
@@ -2,18 +2,21 @@ import computed from 'ember-addons/ember-computed-decorators';
import Topic from 'discourse/models/topic';
export default Ember.Controller.extend({
- needs: ["application", "user-topics-list", "user"],
+ application: Ember.inject.controller(),
+ userTopicsList: Ember.inject.controller('user-topics-list'),
+ user: Ember.inject.controller(),
+
pmView: false,
- viewingSelf: Em.computed.alias('controllers.user.viewingSelf'),
+ viewingSelf: Em.computed.alias('user.viewingSelf'),
isGroup: Em.computed.equal('pmView', 'groups'),
- currentPath: Em.computed.alias('controllers.application.currentPath'),
- selected: Em.computed.alias('controllers.user-topics-list.selected'),
- bulkSelectEnabled: Em.computed.alias('controllers.user-topics-list.bulkSelectEnabled'),
+ currentPath: Em.computed.alias('application.currentPath'),
+ selected: Em.computed.alias('userTopicsList.selected'),
+ bulkSelectEnabled: Em.computed.alias('userTopicsList.bulkSelectEnabled'),
showNewPM: function(){
- return this.get('controllers.user.viewingSelf') &&
+ return this.get('user.viewingSelf') &&
Discourse.User.currentProp('can_send_private_messages');
- }.property('controllers.user.viewingSelf'),
+ }.property('user.viewingSelf'),
@computed('selected.[]', 'bulkSelectEnabled')
hasSelection(selected, bulkSelectEnabled){
@@ -39,7 +42,7 @@ export default Ember.Controller.extend({
}
Topic.bulkOperation(selected,params).then(() => {
- const model = this.get('controllers.user-topics-list.model');
+ const model = this.get('userTopicsList.model');
const topics = model.get('topics');
topics.removeObjects(selected);
selected.clear();
diff --git a/app/assets/javascripts/discourse/controllers/user-summary.js.es6 b/app/assets/javascripts/discourse/controllers/user-summary.js.es6
index d41962d96c..c40014854c 100644
--- a/app/assets/javascripts/discourse/controllers/user-summary.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-summary.js.es6
@@ -6,8 +6,8 @@ const MAX_SUMMARY_RESULTS = 6;
const MAX_BADGES = 6;
export default Ember.Controller.extend({
- needs: ['user'],
- user: Ember.computed.alias('controllers.user.model'),
+ userController: Ember.inject.controller('user'),
+ user: Ember.computed.alias('userController.model'),
@computed("model.topics.length")
moreTopics(topicsLength) { return topicsLength >= MAX_SUMMARY_RESULTS; },
diff --git a/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 b/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6
index e4d428a4f9..8e150fd289 100644
--- a/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6
@@ -1,11 +1,12 @@
// Lists of topics on a user's page.
export default Ember.Controller.extend({
- needs: ["application", "user"],
+ application: Ember.inject.controller(),
+
hideCategory: false,
showPosters: false,
_showFooter: function() {
- this.set("controllers.application.showFooter", !this.get("model.canLoadMore"));
+ this.set("application.showFooter", !this.get("model.canLoadMore"));
}.observes("model.canLoadMore"),
actions: {
diff --git a/app/assets/javascripts/discourse/controllers/user.js.es6 b/app/assets/javascripts/discourse/controllers/user.js.es6
index b5151f1b33..95a89bc722 100644
--- a/app/assets/javascripts/discourse/controllers/user.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user.js.es6
@@ -6,14 +6,20 @@ import User from 'discourse/models/user';
export default Ember.Controller.extend(CanCheckEmails, {
indexStream: false,
userActionType: null,
- needs: ['application','user-notifications', 'user-topics-list'],
- currentPath: Em.computed.alias('controllers.application.currentPath'),
+ application: Ember.inject.controller(),
+ userNotifications: Ember.inject.controller('user-notifications'),
+ currentPath: Ember.computed.alias('application.currentPath'),
@computed("content.username")
viewingSelf(username) {
return username === User.currentProp('username');
},
+ @computed('model.profileBackground')
+ hasProfileBackground(background) {
+ return !Ember.isEmpty(background.toString());
+ },
+
@computed('indexStream', 'viewingSelf', 'forceExpand')
collapsedInfo(indexStream, viewingSelf, forceExpand){
return (!indexStream || viewingSelf) && !forceExpand;
@@ -75,7 +81,7 @@ export default Ember.Controller.extend(CanCheckEmails, {
const siteUserFields = this.site.get('user_fields');
if (!Ember.isEmpty(siteUserFields)) {
const userFields = this.get('model.user_fields');
- return siteUserFields.filterProperty('show_on_profile', true).sortBy('position').map(field => {
+ return siteUserFields.filterBy('show_on_profile', true).sortBy('position').map(field => {
field.dasherized_name = field.get('name').dasherize();
const value = userFields ? userFields[field.get('id').toString()] : null;
return Ember.isEmpty(value) ? null : Ember.Object.create({ value, field });
diff --git a/app/assets/javascripts/discourse/controllers/users.js.es6 b/app/assets/javascripts/discourse/controllers/users.js.es6
index 8ad3eabcba..f5bb196302 100644
--- a/app/assets/javascripts/discourse/controllers/users.js.es6
+++ b/app/assets/javascripts/discourse/controllers/users.js.es6
@@ -1,7 +1,7 @@
import debounce from 'discourse/lib/debounce';
export default Ember.Controller.extend({
- needs: ["application"],
+ application: Ember.inject.controller(),
queryParams: ["period", "order", "asc", "name"],
period: "weekly",
order: "likes_received",
@@ -15,7 +15,7 @@ export default Ember.Controller.extend({
}, 500).observes("nameInput"),
_showFooter: function() {
- this.set("controllers.application.showFooter", !this.get("model.canLoadMore"));
+ this.set("application.showFooter", !this.get("model.canLoadMore"));
}.observes("model.canLoadMore"),
actions: {
diff --git a/app/assets/javascripts/discourse/helpers/as-hash.js.es6 b/app/assets/javascripts/discourse/helpers/as-hash.js.es6
index c5c67a64e0..df5abfcdfd 100644
--- a/app/assets/javascripts/discourse/helpers/as-hash.js.es6
+++ b/app/assets/javascripts/discourse/helpers/as-hash.js.es6
@@ -1,8 +1,12 @@
+import { registerHelper } from 'discourse-common/lib/helpers';
+
// Note: Later versions of ember include `hash`
-export default function hashHelper(params) {
+registerHelper('as-hash', function(_, params) {
+ if (Ember.Helper) { return params; }
+
const hash = {};
- Object.keys(params.hash).forEach(k => {
- hash[k] = params.data.view.getStream(params.hash[k]).value();
+ Object.keys(params).forEach(k => {
+ hash[k] = params[k].value();
});
return hash;
-}
+});
diff --git a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 b/app/assets/javascripts/discourse/helpers/custom-html.js.es6
index d862cb02fd..5c77dbaf49 100644
--- a/app/assets/javascripts/discourse/helpers/custom-html.js.es6
+++ b/app/assets/javascripts/discourse/helpers/custom-html.js.es6
@@ -20,15 +20,7 @@ export function setCustomHTML(key, html) {
_customizations[key] = html;
}
-registerHelper('custom-html', function(params, hash, options, env) {
- const name = params[0];
- const html = getCustomHTML(name);
+registerHelper('custom-html', function([id]) {
+ const html = getCustomHTML(id);
if (html) { return html; }
-
- const contextString = params[1];
- const target = (env || contextString);
- const container = target.container || target.data.view.container;
- if (container.lookup('template:' + name)) {
- return env.helpers.partial.helperFunction.apply(this, arguments);
- }
});
diff --git a/app/assets/javascripts/discourse/helpers/inline-date.js.es6 b/app/assets/javascripts/discourse/helpers/inline-date.js.es6
index 874434fd3c..f483802ee0 100644
--- a/app/assets/javascripts/discourse/helpers/inline-date.js.es6
+++ b/app/assets/javascripts/discourse/helpers/inline-date.js.es6
@@ -1,6 +1,8 @@
import { relativeAge } from 'discourse/lib/formatter';
+import { registerHelper } from 'discourse-common/lib/helpers';
-export default function(dt, params) {
- dt = params.data.view.getStream(dt).value();
+registerHelper('inline-date', function([dt]) {
+ // TODO: Remove this in 1.13 or greater
+ if (dt.value) { dt = dt.value(); }
return relativeAge(new Date(dt));
-}
+});
diff --git a/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6 b/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6
index 69df920633..00a4307d7c 100644
--- a/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6
+++ b/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6
@@ -29,17 +29,6 @@
And it will be wired up automatically.
- ## The block form
-
- If you use the block form of the outlet, its contents will be displayed
- if no connectors are found. Example:
-
- ```handlebars
- {{#plugin-outlet "hello-world"}}
- Nobody says hello :'(
- {{/plugin-outlet}}
- ```
-
## Disabling
If a plugin returns a disabled status, the outlets will not be wired up for it.
@@ -129,7 +118,7 @@ function viewInjections(container) {
}
// unbound version of outlets, only has a template
-Handlebars.registerHelper('plugin-outlet', function(name){
+Handlebars.registerHelper('plugin-outlet', function(name) {
if (!_rawCache) { buildConnectorCache(); }
const functions = _rawCache[name];
@@ -145,9 +134,7 @@ Handlebars.registerHelper('plugin-outlet', function(name){
});
-registerHelper('plugin-outlet', function(params, hash, options, env) {
- const connectionName = params[0];
-
+registerHelper('plugin-outlet', function([connectionName], hash, options, env) {
if (!_connectorCache) { buildConnectorCache(); }
if (_connectorCache[connectionName]) {
@@ -157,30 +144,26 @@ registerHelper('plugin-outlet', function(params, hash, options, env) {
// just shove it in.
const viewClass = (childViews.length > 1) ? Ember.ContainerView : childViews[0];
- const newHash = $.extend({}, viewInjections(env.data.view.container));
- if (hash.tagName) { newHash.tagName = hash.tagName; }
+ // TODO: Figure out how to do this without a container view
+ if (env) {
+ const newHash = $.extend({}, viewInjections(env.data.view.container));
+ if (hash.tagName) { newHash.tagName = hash.tagName; }
- // we don't need the default template since we have a connector
- delete options.fn;
- delete options.template;
- env.helpers.view.helperFunction.call(this, [viewClass], newHash, options, env);
+ // we don't need the default template since we have a connector
+ delete options.fn;
+ delete options.template;
+ env.helpers.view.helperFunction.call(this, [viewClass], newHash, options, env);
- const cvs = env.data.view._childViews;
- if (childViews.length > 1 && cvs && cvs.length) {
- const inserted = cvs[cvs.length-1];
- if (inserted) {
- childViews.forEach(function(cv) {
- inserted.pushObject(cv.create());
- });
+ const cvs = env.data.view._childViews;
+ if (childViews.length > 1 && cvs && cvs.length) {
+ const inserted = cvs[cvs.length-1];
+ if (inserted) {
+ childViews.forEach(function(cv) {
+ inserted.pushObject(cv.create());
+ });
+ }
}
}
- } else if (options.isBlock) {
- const virtualView = Ember.View.extend({
- isVirtual: true,
- tagName: hash.tagName || '',
- template: options.template
- });
- env.helpers.view.helperFunction.call(this, [virtualView], hash, options, env);
}
});
diff --git a/app/assets/javascripts/discourse/helpers/raw.js.es6 b/app/assets/javascripts/discourse/helpers/raw.js.es6
index 506822b797..630cc2383a 100644
--- a/app/assets/javascripts/discourse/helpers/raw.js.es6
+++ b/app/assets/javascripts/discourse/helpers/raw.js.es6
@@ -1,17 +1,27 @@
import { registerUnbound } from 'discourse-common/lib/helpers';
-// see: https://github.com/emberjs/ember.js/issues/12634
-var missingViews = {};
+let _injections;
-function renderRaw(ctx, template, templateName, params) {
+function renderRaw(ctx, container, template, templateName, params) {
params.parent = params.parent || ctx;
- if (!params.view && !missingViews[templateName]) {
- var viewClass = Discourse.__container__.lookupFactory('view:' + templateName);
- if (viewClass) {
- params.view = viewClass.create(params);
- } else {
- missingViews[templateName] = true;
+ if (!params.view) {
+ if (!_injections) {
+ _injections = {
+ siteSettings: container.lookup('site-settings:main'),
+ currentUser: container.lookup('currentUser:main'),
+ site: container.lookup('site:main'),
+ session: container.lookup('session:main'),
+ topicTrackingState: container.lookup('topic-tracking-state:main')
+ };
+ }
+
+ const module = `discourse/views/${templateName}`;
+ if (requirejs.entries[module]) {
+ const viewClass = require(module, null, null, true);
+ if (viewClass && viewClass.default) {
+ params.view = viewClass.default.create(params, _injections);
+ }
}
}
@@ -19,10 +29,13 @@ function renderRaw(ctx, template, templateName, params) {
}
registerUnbound('raw', function(templateName, params) {
- var template = Discourse.__container__.lookup('template:' + templateName + '.raw');
+ templateName = templateName.replace('.', '/');
+
+ const container = Discourse.__container__;
+ var template = container.lookup('template:' + templateName + '.raw');
if (!template) {
Ember.warn('Could not find raw template: ' + templateName);
return;
}
- return renderRaw(this, template, templateName, params);
+ return renderRaw(this, container, template, templateName, params);
});
diff --git a/app/assets/javascripts/discourse/helpers/user-status.js.es6 b/app/assets/javascripts/discourse/helpers/user-status.js.es6
index cffd9e7acc..fb1a05efee 100644
--- a/app/assets/javascripts/discourse/helpers/user-status.js.es6
+++ b/app/assets/javascripts/discourse/helpers/user-status.js.es6
@@ -6,7 +6,10 @@ export default htmlHelper((user, args) => {
if (!user) { return; }
const name = escapeExpression(user.get('name'));
- const currentUser = args.hash.currentUser;
+ let currentUser;
+ if (args && args.hash) {
+ currentUser = args.hash.currentUser;
+ }
if (currentUser && user.get('admin') && currentUser.get('staff')) {
return iconHTML('shield', { label: I18n.t('user.admin', { user: name }) });
diff --git a/app/assets/javascripts/discourse/initializers/auto-load-modules.js.es6 b/app/assets/javascripts/discourse/initializers/auto-load-modules.js.es6
index b5bf7cc041..4920eca574 100644
--- a/app/assets/javascripts/discourse/initializers/auto-load-modules.js.es6
+++ b/app/assets/javascripts/discourse/initializers/auto-load-modules.js.es6
@@ -1,4 +1,6 @@
-export function autoLoadModules() {
+import { registerHelpers } from 'discourse-common/lib/helpers';
+
+export function autoLoadModules(container, registry) {
Object.keys(requirejs.entries).forEach(entry => {
if ((/\/helpers\//).test(entry)) {
require(entry, null, null, true);
@@ -7,6 +9,7 @@ export function autoLoadModules() {
require(entry, null, null, true);
}
});
+ registerHelpers(registry);
}
export default {
diff --git a/app/assets/javascripts/discourse/initializers/page-tracking.js.es6 b/app/assets/javascripts/discourse/initializers/page-tracking.js.es6
index 7e744a7de9..cf978f4300 100644
--- a/app/assets/javascripts/discourse/initializers/page-tracking.js.es6
+++ b/app/assets/javascripts/discourse/initializers/page-tracking.js.es6
@@ -1,4 +1,4 @@
-import { cleanDOM } from 'discourse/routes/discourse';
+import { cleanDOM } from 'discourse/lib/clean-dom';
import { startPageTracking, onPageChange } from 'discourse/lib/page-tracker';
import { viewTrackingRequired } from 'discourse/lib/ajax';
@@ -10,10 +10,7 @@ export default {
// Tell our AJAX system to track a page transition
const router = container.lookup('router:main');
router.on('willTransition', viewTrackingRequired);
-
- router.on('didTransition', function() {
- Em.run.scheduleOnce('afterRender', Ember.Route, cleanDOM);
- });
+ router.on('didTransition', cleanDOM);
startPageTracking(router);
diff --git a/app/assets/javascripts/discourse/lib/clean-dom.js.es6 b/app/assets/javascripts/discourse/lib/clean-dom.js.es6
new file mode 100644
index 0000000000..8f86e6a6fd
--- /dev/null
+++ b/app/assets/javascripts/discourse/lib/clean-dom.js.es6
@@ -0,0 +1,32 @@
+function _clean() {
+ if (window.MiniProfiler) {
+ window.MiniProfiler.pageTransition();
+ }
+
+ // Close some elements that may be open
+ $('header ul.icons li').removeClass('active');
+ $('[data-toggle="dropdown"]').parent().removeClass('open');
+ // close the lightbox
+ if ($.magnificPopup && $.magnificPopup.instance) {
+ $.magnificPopup.instance.close();
+ $('body').removeClass('mfp-zoom-out-cur');
+ }
+
+ // Remove any link focus
+ // NOTE: the '.not("body")' is here to prevent a bug in IE10 on Win7
+ // cf. https://stackoverflow.com/questions/5657371
+ $(document.activeElement).not("body").not(".no-blur").blur();
+
+ Discourse.set('notifyCount',0);
+ Discourse.__container__.lookup('route:application').send('closeModal');
+ const hideDropDownFunction = $('html').data('hide-dropdown');
+ if (hideDropDownFunction) { hideDropDownFunction(); }
+
+ // TODO: Avoid container lookup here
+ const appEvents = Discourse.__container__.lookup('app-events:main');
+ appEvents.trigger('dom:clean');
+}
+
+export function cleanDOM() {
+ Ember.run.scheduleOnce('afterRender', _clean);
+}
diff --git a/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 b/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6
index fff8079cf3..68e9528184 100644
--- a/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6
+++ b/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6
@@ -68,7 +68,7 @@ function initializeRecentlyUsedIcons() {
recent.forEach(emoji => recentlyUsedIcons.push(emoji.title));
- const recentGroup = groups.findProperty('name', 'recent');
+ const recentGroup = groups.findBy('name', 'recent');
if (recentGroup) {
recentGroup.icons = recentlyUsedIcons;
} else {
diff --git a/app/assets/javascripts/discourse/lib/link-mentions.js.es6 b/app/assets/javascripts/discourse/lib/link-mentions.js.es6
index 149b151617..d41bd7e5b9 100644
--- a/app/assets/javascripts/discourse/lib/link-mentions.js.es6
+++ b/app/assets/javascripts/discourse/lib/link-mentions.js.es6
@@ -1,37 +1,34 @@
import { ajax } from 'discourse/lib/ajax';
+
function replaceSpan($e, username, opts) {
if (opts && opts.group) {
- var extra = "", extraClass = "";
+ let extra = "";
+ let extraClass = "";
if (opts.mentionable) {
- extra = " data-name='" + username + "' data-mentionable-user-count='" + opts.mentionable.user_count + "' ";
- extraClass = " notify";
+ extra = `data-name='${username}' data-mentionable-user-count='${opts.mentionable.user_count}'`;
+ extraClass = "notify";
}
- $e.replaceWith("@" + username + "");
+ $e.replaceWith(`@${username}`);
} else {
- $e.replaceWith("@" + username + "");
+ $e.replaceWith(`@${username}`);
}
}
-const found = [];
-const foundGroups = [];
-const mentionableGroups = [];
-const checked = [];
+const found = {};
+const foundGroups = {};
+const mentionableGroups = {};
+const checked = {};
function updateFound($mentions, usernames) {
Ember.run.scheduleOnce('afterRender', function() {
$mentions.each((i, e) => {
const $e = $(e);
const username = usernames[i];
- if (found.indexOf(username.toLowerCase()) !== -1) {
+ if (found[username.toLowerCase()]) {
replaceSpan($e, username);
- } else if (foundGroups.indexOf(username) !== -1) {
- const mentionable = _(mentionableGroups).where({name: username}).first();
- replaceSpan($e, username, {group: true, mentionable: mentionable});
- } else if (checked.indexOf(username) !== -1) {
+ } else if (foundGroups[username]) {
+ replaceSpan($e, username, { group: true, mentionable: mentionableGroups[username] });
+ } else if (checked[username]) {
$e.addClass('mention-tested');
}
});
@@ -42,22 +39,18 @@ export function linkSeenMentions($elem, siteSettings) {
const $mentions = $('span.mention:not(.mention-tested)', $elem);
if ($mentions.length) {
const usernames = $mentions.map((_, e) => $(e).text().substr(1));
- const unseen = _.uniq(usernames).filter((u) => {
- return u.length >= siteSettings.min_username_length && checked.indexOf(u) === -1;
- });
updateFound($mentions, usernames);
- return unseen;
+ return _.uniq(usernames).filter(u => !checked[u] && u.length >= siteSettings.min_username_length);
}
-
return [];
}
-export function fetchUnseenMentions($elem, usernames) {
- return ajax("/users/is_local_username", { data: { usernames } }).then(function(r) {
- found.push.apply(found, r.valid);
- foundGroups.push.apply(foundGroups, r.valid_groups);
- mentionableGroups.push.apply(mentionableGroups, r.mentionable_groups);
- checked.push.apply(checked, usernames);
+export function fetchUnseenMentions(usernames) {
+ return ajax("/users/is_local_username", { data: { usernames } }).then(r => {
+ r.valid.forEach(v => found[v] = true);
+ r.valid_groups.forEach(vg => foundGroups[vg] = true);
+ r.mentionable_groups.forEach(mg => mentionableGroups[mg] = true);
+ usernames.forEach(u => checked[u] = true);
return r;
});
}
diff --git a/app/assets/javascripts/discourse/lib/search.js.es6 b/app/assets/javascripts/discourse/lib/search.js.es6
index c4e9567b83..9dc3b38e2f 100644
--- a/app/assets/javascripts/discourse/lib/search.js.es6
+++ b/app/assets/javascripts/discourse/lib/search.js.es6
@@ -37,7 +37,7 @@ export function translateResults(results, opts) {
});
results.categories = results.categories.map(function(category){
- return Category.list().findProperty('id', category.id);
+ return Category.list().findBy('id', category.id);
}).compact();
const r = results.grouped_search_result;
diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6
index 6237163d06..0306b001e0 100644
--- a/app/assets/javascripts/discourse/lib/show-modal.js.es6
+++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6
@@ -26,6 +26,7 @@ export default function(name, opts) {
}
if (controller) {
+ controller.set('modal', modalController);
const model = opts.model;
if (model) { controller.set('model', model); }
if (controller.onShow) { controller.onShow(); }
diff --git a/app/assets/javascripts/discourse/lib/text.js.es6 b/app/assets/javascripts/discourse/lib/text.js.es6
index 5a140b48c1..56f460852f 100644
--- a/app/assets/javascripts/discourse/lib/text.js.es6
+++ b/app/assets/javascripts/discourse/lib/text.js.es6
@@ -19,7 +19,7 @@ export function cook(text) {
}
export function sanitize(text) {
- return textSanitize(text, new WhiteLister(getOpts().features));
+ return textSanitize(text, new WhiteLister(getOpts()));
}
function emojiOptions() {
diff --git a/app/assets/javascripts/discourse/lib/url.js.es6 b/app/assets/javascripts/discourse/lib/url.js.es6
index 8101a2a7d3..7621ae4ce9 100644
--- a/app/assets/javascripts/discourse/lib/url.js.es6
+++ b/app/assets/javascripts/discourse/lib/url.js.es6
@@ -168,9 +168,6 @@ const DiscourseURL = Ember.Object.extend({
if (this.navigatedToPost(oldPath, path, opts)) { return; }
- // Schedule a DOM cleanup event
- Em.run.scheduleOnce('afterRender', Discourse.Route, 'cleanDOM');
-
if (oldPath === path) {
// If navigating to the same path send an app event. Views can watch it
// and tell their controllers to refresh
diff --git a/app/assets/javascripts/discourse/lib/user-search.js.es6 b/app/assets/javascripts/discourse/lib/user-search.js.es6
index eb5bc209b3..def5e2e883 100644
--- a/app/assets/javascripts/discourse/lib/user-search.js.es6
+++ b/app/assets/javascripts/discourse/lib/user-search.js.es6
@@ -59,7 +59,7 @@ function organizeResults(r, options) {
if (r.groups) {
r.groups.every(function(g) {
- if (results.length > limit) return false;
+ if (results.length > limit && options.term !== g.name) return false;
if (exclude.indexOf(g.name) === -1) {
groups.push(g);
results.push(g);
diff --git a/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 b/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6
index 42a279b803..7394488fcb 100644
--- a/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6
+++ b/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6
@@ -1,8 +1,6 @@
-export default Em.Mixin.create({
+export default Ember.Mixin.create({
flashMessage: null,
- needs: ['modal'],
-
flash(message, messageClass) {
this.set('flashMessage', Em.Object.create({ message, messageClass }));
}
diff --git a/app/assets/javascripts/discourse/mixins/string-buffer.js.es6 b/app/assets/javascripts/discourse/mixins/string-buffer.js.es6
deleted file mode 100644
index 943a972c6e..0000000000
--- a/app/assets/javascripts/discourse/mixins/string-buffer.js.es6
+++ /dev/null
@@ -1,45 +0,0 @@
-export default Ember.Mixin.create({
-
- _watchProps: function() {
- const args = this.get('rerenderTriggers');
- if (!Ember.isNone(args)) {
- args.forEach(k => this.addObserver(k, this.rerenderString));
- }
- }.on('init'),
-
- render(buffer) {
- this.renderString(buffer);
- },
-
- renderString(buffer){
- const template = Discourse.__container__.lookup('template:' + this.rawTemplate);
- if (template) {
- buffer.push(template(this));
- }
- },
-
- _rerenderString() {
- const $sel = this.$();
- if (!$sel) { return; }
-
- const buffer = [];
- this.renderString(buffer);
-
- // Chrome likes scrolling after HTML is set
- // This happens if you navigate back and forth a few times
- // Before removing this code confirm that this does not cause scrolling
- // 1. Sort by views
- // 2. Go to last post on one of the topics
- // 3. Hit back
- // 4. Go to last post on same topic
- // 5. Expand likes
- const scrollTop = $(window).scrollTop();
- $sel.html(buffer.join(''));
- $(window).scrollTop(scrollTop);
- },
-
- rerenderString() {
- Ember.run.once(this, '_rerenderString');
- }
-
-});
diff --git a/app/assets/javascripts/discourse/models/admin-post.js.es6 b/app/assets/javascripts/discourse/models/admin-post.js.es6
index 4504fcbe24..8de331ac95 100644
--- a/app/assets/javascripts/discourse/models/admin-post.js.es6
+++ b/app/assets/javascripts/discourse/models/admin-post.js.es6
@@ -9,7 +9,7 @@ export default Post.extend({
}
}.on("init"),
- presentName: Em.computed.any('name', 'username'),
+ presentName: Ember.computed.or('name', 'username'),
sameUser: function() {
return this.get("username") === Discourse.User.currentProp("username");
diff --git a/app/assets/javascripts/discourse/models/category.js.es6 b/app/assets/javascripts/discourse/models/category.js.es6
index 724a266469..b77a4abdf3 100644
--- a/app/assets/javascripts/discourse/models/category.js.es6
+++ b/app/assets/javascripts/discourse/models/category.js.es6
@@ -98,7 +98,9 @@ const Category = RestModel.extend({
topic_template: this.get('topic_template'),
suppress_from_homepage: this.get('suppress_from_homepage'),
allowed_tags: this.get('allowed_tags'),
- allowed_tag_groups: this.get('allowed_tag_groups')
+ allowed_tag_groups: this.get('allowed_tag_groups'),
+ sort_order: this.get('sort_order'),
+ sort_ascending: this.get('sort_ascending')
},
type: id ? 'PUT' : 'POST'
});
diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6
index 511f4ea853..3bfdcc904a 100644
--- a/app/assets/javascripts/discourse/models/composer.js.es6
+++ b/app/assets/javascripts/discourse/models/composer.js.es6
@@ -118,7 +118,7 @@ const Composer = RestModel.extend({
}.property().volatile(),
archetype: function() {
- return this.get('archetypes').findProperty('id', this.get('archetypeId'));
+ return this.get('archetypes').findBy('id', this.get('archetypeId'));
}.property('archetypeId'),
archetypeChanged: function() {
@@ -378,14 +378,14 @@ const Composer = RestModel.extend({
// If the user didn't change the template, clear it
if (oldCategoryId) {
- const oldCat = this.site.categories.findProperty('id', oldCategoryId);
+ const oldCat = this.site.categories.findBy('id', oldCategoryId);
if (oldCat && (oldCat.get('topic_template') === reply)) {
reply = "";
}
}
if (!Ember.isEmpty(reply)) { return; }
- const category = this.site.categories.findProperty('id', categoryId);
+ const category = this.site.categories.findBy('id', categoryId);
if (category) {
this.set('reply', category.get('topic_template') || "");
}
diff --git a/app/assets/javascripts/discourse/models/nav-item.js.es6 b/app/assets/javascripts/discourse/models/nav-item.js.es6
index 7eb1616485..58845c2d51 100644
--- a/app/assets/javascripts/discourse/models/nav-item.js.es6
+++ b/app/assets/javascripts/discourse/models/nav-item.js.es6
@@ -29,7 +29,7 @@ const NavItem = Discourse.Model.extend({
categorySlug: function() {
var split = this.get('name').split('/');
if (split[0] === 'category' && split[1]) {
- var cat = Discourse.Site.current().categories.findProperty('nameLower', split[1].toLowerCase());
+ var cat = Discourse.Site.current().categories.findBy('nameLower', split[1].toLowerCase());
return cat ? Discourse.Category.slugFor(cat) : null;
}
return null;
diff --git a/app/assets/javascripts/discourse/models/post-stream.js.es6 b/app/assets/javascripts/discourse/models/post-stream.js.es6
index a96f0e0248..2473b6660b 100644
--- a/app/assets/javascripts/discourse/models/post-stream.js.es6
+++ b/app/assets/javascripts/discourse/models/post-stream.js.es6
@@ -59,7 +59,7 @@ export default RestModel.extend({
@computed('hasLoadedData', 'firstPostId', 'posts.[]')
firstPostPresent(hasLoadedData, firstPostId) {
if (!hasLoadedData) { return false; }
- return !!this.get('posts').findProperty('id', firstPostId);
+ return !!this.get('posts').findBy('id', firstPostId);
},
firstPostNotLoaded: Ember.computed.not('firstPostPresent'),
@@ -71,7 +71,7 @@ export default RestModel.extend({
if (!hasLoadedData) { return false; }
if (lastPostId === -1) { return true; }
- return !!this.get('posts').findProperty('id', lastPostId);
+ return !!this.get('posts').findBy('id', lastPostId);
},
lastPostNotLoaded: Ember.computed.not('loadedAllPosts'),
@@ -208,7 +208,7 @@ export default RestModel.extend({
if (opts.forceLoad) {
this.set('loaded', false);
} else {
- const postWeWant = this.get('posts').findProperty('post_number', opts.nearPost);
+ const postWeWant = this.get('posts').findBy('post_number', opts.nearPost);
if (postWeWant) { return Ember.RSVP.resolve(); }
}
diff --git a/app/assets/javascripts/discourse/models/post.js.es6 b/app/assets/javascripts/discourse/models/post.js.es6
index 7e96dc3ba1..b15683ca4a 100644
--- a/app/assets/javascripts/discourse/models/post.js.es6
+++ b/app/assets/javascripts/discourse/models/post.js.es6
@@ -76,7 +76,7 @@ const Post = RestModel.extend({
internalLinks: function() {
if (Ember.isEmpty(this.get('link_counts'))) return null;
- return this.get('link_counts').filterProperty('internal').filterProperty('title');
+ return this.get('link_counts').filterBy('internal').filterBy('title');
}.property('link_counts.@each.internal'),
flagsAvailable: function() {
diff --git a/app/assets/javascripts/discourse/models/site.js.es6 b/app/assets/javascripts/discourse/models/site.js.es6
index eb417c7429..5b421c46be 100644
--- a/app/assets/javascripts/discourse/models/site.js.es6
+++ b/app/assets/javascripts/discourse/models/site.js.es6
@@ -20,7 +20,7 @@ const Site = RestModel.extend({
flagTypes() {
const postActionTypes = this.get('post_action_types');
if (!postActionTypes) return [];
- return postActionTypes.filterProperty('is_flag', true);
+ return postActionTypes.filterBy('is_flag', true);
},
topicCountDesc: ['topic_count:desc'],
@@ -64,7 +64,7 @@ const Site = RestModel.extend({
removeCategory(id) {
const categories = this.get('categories');
- const existingCategory = categories.findProperty('id', id);
+ const existingCategory = categories.findBy('id', id);
if (existingCategory) {
categories.removeObject(existingCategory);
delete this.get('categoriesById').categoryId;
@@ -74,7 +74,7 @@ const Site = RestModel.extend({
updateCategory(newCategory) {
const categories = this.get('categories');
const categoryId = Em.get(newCategory, 'id');
- const existingCategory = categories.findProperty('id', categoryId);
+ const existingCategory = categories.findBy('id', categoryId);
// Don't update null permissions
if (newCategory.permission === null) { delete newCategory.permission; }
diff --git a/app/assets/javascripts/discourse/models/topic-details.js.es6 b/app/assets/javascripts/discourse/models/topic-details.js.es6
index 25714b0c4b..72ef0d0fe9 100644
--- a/app/assets/javascripts/discourse/models/topic-details.js.es6
+++ b/app/assets/javascripts/discourse/models/topic-details.js.es6
@@ -72,7 +72,7 @@ const TopicDetails = RestModel.extend({
type: 'PUT',
data: { name: name }
}).then(() => {
- groups.removeObject(groups.findProperty('name', name));
+ groups.removeObject(groups.findBy('name', name));
});
},
@@ -84,7 +84,7 @@ const TopicDetails = RestModel.extend({
type: 'PUT',
data: { username: username }
}).then(() => {
- users.removeObject(users.findProperty('username', username));
+ users.removeObject(users.findBy('username', username));
});
}
});
diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6
index 15b181fae8..e59c60029d 100644
--- a/app/assets/javascripts/discourse/models/topic.js.es6
+++ b/app/assets/javascripts/discourse/models/topic.js.es6
@@ -120,7 +120,7 @@ const Topic = RestModel.extend({
const categoryName = this.get('categoryName');
let category;
if (categoryName) {
- category = Discourse.Category.list().findProperty('name', categoryName);
+ category = Discourse.Category.list().findBy('name', categoryName);
}
this.set('category', category);
}.observes('categoryName'),
@@ -213,7 +213,7 @@ const Topic = RestModel.extend({
}.property('views'),
archetypeObject: function() {
- return Discourse.Site.currentProp('archetypes').findProperty('id', this.get('archetype'));
+ return Discourse.Site.currentProp('archetypes').findBy('id', this.get('archetype'));
}.property('archetype'),
isPrivateMessage: Em.computed.equal('archetype', 'private_message'),
diff --git a/app/assets/javascripts/discourse/models/user-action.js.es6 b/app/assets/javascripts/discourse/models/user-action.js.es6
index 024089799a..ebc4be7381 100644
--- a/app/assets/javascripts/discourse/models/user-action.js.es6
+++ b/app/assets/javascripts/discourse/models/user-action.js.es6
@@ -76,9 +76,9 @@ const UserAction = RestModel.extend({
return targetUsername === Discourse.User.currentProp('username');
},
- presentName: Em.computed.any('name', 'username'),
- targetDisplayName: Em.computed.any('target_name', 'target_username'),
- actingDisplayName: Em.computed.any('acting_name', 'acting_username'),
+ presentName: Ember.computed.or('name', 'username'),
+ targetDisplayName: Ember.computed.or('target_name', 'target_username'),
+ actingDisplayName: Ember.computed.or('acting_name', 'acting_username'),
targetUserUrl: url('target_username', '/users/%@'),
@computed("username")
diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6
index ede02127a3..e4f92d6b34 100644
--- a/app/assets/javascripts/discourse/models/user.js.es6
+++ b/app/assets/javascripts/discourse/models/user.js.es6
@@ -64,7 +64,7 @@ const User = RestModel.extend({
@computed('profile_background')
profileBackground(bgUrl) {
- if (Em.isEmpty(bgUrl) || !Discourse.SiteSettings.allow_profile_backgrounds) { return; }
+ if (Em.isEmpty(bgUrl) || !Discourse.SiteSettings.allow_profile_backgrounds) { return "".htmlSafe(); }
return ('background-image: url(' + Discourse.getURLWithCDN(bgUrl) + ')').htmlSafe();
},
@@ -153,7 +153,7 @@ const User = RestModel.extend({
@computed("trust_level")
trustLevel(trustLevel) {
- return Discourse.Site.currentProp('trustLevels').findProperty('id', parseInt(trustLevel, 10));
+ return Discourse.Site.currentProp('trustLevels').findBy('id', parseInt(trustLevel, 10));
},
isBasic: Em.computed.equal('trust_level', 0),
@@ -322,7 +322,7 @@ const User = RestModel.extend({
@computed("stats.@each.isPM")
statsExcludingPms() {
if (Ember.isEmpty(this.get('stats'))) return [];
- return this.get('stats').rejectProperty('isPM');
+ return this.get('stats').rejectBy('isPM');
},
findDetails(options) {
@@ -525,12 +525,12 @@ User.reopenClass(Singleton, {
action_type: UserAction.TYPES.replies
});
- stats.filterProperty('isResponse').forEach(stat => {
+ stats.filterBy('isResponse').forEach(stat => {
responses.set('count', responses.get('count') + stat.get('count'));
});
const result = Em.A();
- result.pushObjects(stats.rejectProperty('isResponse'));
+ result.pushObjects(stats.rejectBy('isResponse'));
let insertAt = 0;
result.forEach((item, index) => {
diff --git a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6
index 04729de959..5e3de23fee 100644
--- a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6
+++ b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6
@@ -7,7 +7,6 @@ import DiscourseLocation from 'discourse/lib/discourse-location';
import SearchService from 'discourse/services/search';
import { startTracking, default as TopicTrackingState } from 'discourse/models/topic-tracking-state';
import ScreenTrack from 'discourse/lib/screen-track';
-import TopicFooterButtons from 'discourse/components/topic-footer-buttons';
function inject() {
const app = arguments[0],
@@ -63,7 +62,9 @@ export default {
app.register('screen-track:main', screenTrack, { instantiate: false });
inject(app, 'screenTrack', 'component', 'route');
- inject(app, 'currentUser', 'component', 'route', 'controller');
+ if (currentUser) {
+ inject(app, 'currentUser', 'component', 'route', 'controller');
+ }
app.register('location:discourse-location', DiscourseLocation);
@@ -71,13 +72,6 @@ export default {
app.register('key-value-store:main', keyValueStore, { instantiate: false });
injectAll(app, 'keyValueStore');
- Discourse.TopicFooterButtonsView = {
- reopen(obj) {
- Ember.warn('`Discourse.TopicFooterButtonsView` is deprecated. Use the `topic-footer-buttons` component instead');
- TopicFooterButtons.reopen(obj);
- }
- };
-
startTracking(topicTrackingState);
}
};
diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
index 8341e4cf57..002f998c35 100644
--- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6
+++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
@@ -132,7 +132,7 @@ export default function() {
this.route('showCategory' + filter.capitalize(), {path: '/c/:category/:tag_id/l/' + filter});
this.route('showParentCategory' + filter.capitalize(), {path: '/c/:parent_category/:category/:tag_id/l/' + filter});
});
- this.route('intersection', {path: 'intersection/:tag_id/*additional_tags'});
+ this.route('show', {path: 'intersection/:tag_id/*additional_tags'});
});
this.resource('tagGroups', {path: '/tag_groups'}, function() {
diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6
index df074f01d3..d506852e36 100644
--- a/app/assets/javascripts/discourse/routes/application.js.es6
+++ b/app/assets/javascripts/discourse/routes/application.js.es6
@@ -20,14 +20,7 @@ function unlessReadOnly(method, message) {
const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
siteTitle: setting('title'),
- _handleLogout() {
- if (this.currentUser) {
- this.currentUser.destroySession().then(() => logout(this.siteSettings, this.keyValueStore));
- }
- },
-
actions: {
-
toggleAnonymous() {
ajax("/users/toggle-anon", {method: 'POST'}).then(() => {
window.location.reload();
@@ -179,6 +172,14 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
});
},
+ renderTemplate() {
+ this.render('application');
+ this.render('user-card', { into: 'application', outlet: 'user-card' });
+ this.render('modal', { into: 'application', outlet: 'modal' });
+ this.render('topic-entrance', { into: 'application', outlet: 'topic-entrance' });
+ this.render('composer', { into: 'application', outlet: 'composer' });
+ },
+
handleShowLogin() {
if (this.siteSettings.enable_sso) {
const returnPath = encodeURIComponent(window.location.pathname);
@@ -198,7 +199,6 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
},
_autoLogin(modal, modalClass, notAuto) {
-
const methods = findAll(this.siteSettings,
this.container.lookup('capabilities:main'),
this.site.isMobileDevice);
@@ -212,6 +212,11 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
}
},
+ _handleLogout() {
+ if (this.currentUser) {
+ this.currentUser.destroySession().then(() => logout(this.siteSettings, this.keyValueStore));
+ }
+ },
});
RSVP.EventTarget.mixin(ApplicationRoute);
diff --git a/app/assets/javascripts/discourse/routes/discourse.js.es6 b/app/assets/javascripts/discourse/routes/discourse.js.es6
index 8b4c7b8465..8b3d3bbc31 100644
--- a/app/assets/javascripts/discourse/routes/discourse.js.es6
+++ b/app/assets/javascripts/discourse/routes/discourse.js.es6
@@ -74,33 +74,4 @@ const DiscourseRoute = Ember.Route.extend({
}
});
-export function cleanDOM() {
- if (window.MiniProfiler) {
- window.MiniProfiler.pageTransition();
- }
-
- // Close some elements that may be open
- $('header ul.icons li').removeClass('active');
- $('[data-toggle="dropdown"]').parent().removeClass('open');
- // close the lightbox
- if ($.magnificPopup && $.magnificPopup.instance) {
- $.magnificPopup.instance.close();
- $('body').removeClass('mfp-zoom-out-cur');
- }
-
- // Remove any link focus
- // NOTE: the '.not("body")' is here to prevent a bug in IE10 on Win7
- // cf. https://stackoverflow.com/questions/5657371
- $(document.activeElement).not("body").not(".no-blur").blur();
-
- Discourse.set('notifyCount',0);
- Discourse.__container__.lookup('route:application').send('closeModal');
- const hideDropDownFunction = $('html').data('hide-dropdown');
- if (hideDropDownFunction) { hideDropDownFunction(); }
-
- // TODO: Avoid container lookup here
- const appEvents = Discourse.__container__.lookup('app-events:main');
- appEvents.trigger('dom:clean');
-}
-
export default DiscourseRoute;
diff --git a/app/assets/javascripts/discourse/routes/tags-show.js.es6 b/app/assets/javascripts/discourse/routes/tags-show.js.es6
index c82acb9eab..db344ef884 100644
--- a/app/assets/javascripts/discourse/routes/tags-show.js.es6
+++ b/app/assets/javascripts/discourse/routes/tags-show.js.es6
@@ -140,16 +140,6 @@ export default Discourse.Route.extend({
didTransition() {
this.controllerFor("tags.show")._showFooter();
return true;
- },
-
- willTransition(transition) {
- if (!Discourse.SiteSettings.show_filter_by_tag) { return true; }
-
- if ((transition.targetName.indexOf("discovery.parentCategory") !== -1 ||
- transition.targetName.indexOf("discovery.category") !== -1) && !transition.queryParams.allTags ) {
- this.transitionTo("/tags" + transition.intent.url + "/" + this.currentModel.get("id"));
- }
- return true;
}
}
});
diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6
index a31736bc15..0ee442dde5 100644
--- a/app/assets/javascripts/discourse/routes/topic.js.es6
+++ b/app/assets/javascripts/discourse/routes/topic.js.es6
@@ -45,7 +45,8 @@ const TopicRoute = Discourse.Route.extend({
this.controllerFor('flag').setProperties({ selected: null, flagTopic: false });
},
- showFlagTopic(model) {
+ showFlagTopic() {
+ const model = this.modelFor('topic');
showModal('flag', { model });
this.controllerFor('flag').setProperties({ selected: null, flagTopic: true });
},
diff --git a/app/assets/javascripts/discourse/templates/application.hbs b/app/assets/javascripts/discourse/templates/application.hbs
index a01b222b00..5a013ead74 100644
--- a/app/assets/javascripts/discourse/templates/application.hbs
+++ b/app/assets/javascripts/discourse/templates/application.hbs
@@ -1,4 +1,4 @@
-
+{{plugin-outlet "above-site-header"}}
{{site-header canSignUp=canSignUp
showCreateAccount="showCreateAccount"
showLogin="showLogin"
@@ -6,6 +6,7 @@
toggleMobileView="toggleMobileView"
toggleAnonymous="toggleAnonymous"
logout="logout"}}
+{{plugin-outlet "below-site-header"}}
@@ -16,7 +17,7 @@
{{create-topics-notice}}
{{outlet}}
- {{render "user-card"}}
+ {{outlet "user-card"}}
{{plugin-outlet "above-footer"}}
@@ -25,6 +26,6 @@
{{/if}}
{{plugin-outlet "below-footer"}}
-{{render "modal"}}
-{{render "topic-entrance"}}
-{{render "composer"}}
+{{outlet "modal"}}
+{{outlet "topic-entrance"}}
+{{outlet "composer"}}
diff --git a/app/assets/javascripts/discourse/templates/components/categories_with_featured_topics.hbs b/app/assets/javascripts/discourse/templates/components/categories-with-featured-topics.hbs
similarity index 100%
rename from app/assets/javascripts/discourse/templates/components/categories_with_featured_topics.hbs
rename to app/assets/javascripts/discourse/templates/components/categories-with-featured-topics.hbs
diff --git a/app/assets/javascripts/discourse/templates/components/check-mark.hbs b/app/assets/javascripts/discourse/templates/components/check-mark.hbs
new file mode 100644
index 0000000000..85c38d59ac
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/check-mark.hbs
@@ -0,0 +1,5 @@
+{{#if checked}}
+ {{fa-icon "check"}}
+{{else}}
+ {{fa-icon "times"}}
+{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/color-picker.hbs b/app/assets/javascripts/discourse/templates/components/color-picker.hbs
new file mode 100644
index 0000000000..5842bf9151
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/color-picker.hbs
@@ -0,0 +1 @@
+{{#each colors as |c|}}{{color-picker-choice color=c usedColors=usedColors selectColor="selectColor"}}{{/each}}
diff --git a/app/assets/javascripts/discourse/templates/components/conditional-loading-spinner.hbs b/app/assets/javascripts/discourse/templates/components/conditional-loading-spinner.hbs
new file mode 100644
index 0000000000..e18527be3a
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/conditional-loading-spinner.hbs
@@ -0,0 +1,5 @@
+{{#if condition}}
+
+{{else}}
+ {{yield}}
+{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/d-button.hbs b/app/assets/javascripts/discourse/templates/components/d-button.hbs
new file mode 100644
index 0000000000..47b714b8dc
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/d-button.hbs
@@ -0,0 +1,6 @@
+{{#if icon}}
+ {{fa-icon icon}}
+{{/if}}
+
+{{{translatedLabel}}}
+{{yield}}
diff --git a/app/assets/javascripts/discourse/templates/components/discourse-banner.hbs b/app/assets/javascripts/discourse/templates/components/discourse-banner.hbs
index 1a647c5ea8..306f2924b4 100644
--- a/app/assets/javascripts/discourse/templates/components/discourse-banner.hbs
+++ b/app/assets/javascripts/discourse/templates/components/discourse-banner.hbs
@@ -1,11 +1,13 @@
-
-