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("
"); if (this.get('content')) { buffer.push(escapeExpression(this.get('content'))); @@ -66,4 +67,4 @@ export default Ember.Component.extend({ }); }.on('didInsertElement') -}); +})); diff --git a/app/assets/javascripts/admin/views/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 similarity index 76% rename from app/assets/javascripts/admin/views/admin-backups-logs.js.es6 rename to app/assets/javascripts/admin/components/admin-backups-logs.js.es6 index 1929abf5a2..01f4547b17 100644 --- a/app/assets/javascripts/admin/views/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 @@ -1,18 +1,27 @@ import debounce from 'discourse/lib/debounce'; import { renderSpinner } from 'discourse/helpers/loading-spinner'; import { escapeExpression } from 'discourse/lib/utilities'; +import { bufferedRender } from 'discourse-common/lib/buffered-render'; -export default Ember.View.extend({ +export default Ember.Component.extend(bufferedRender({ classNames: ["admin-backups-logs"], - _initialize: function() { this._reset(); }.on("init"), + init() { + this._super(); + this._reset(); + }, _reset() { this.setProperties({ formattedLogs: "", index: 0 }); }, + _scrollDown() { + const $div = this.$()[0]; + $div.scrollTop = $div.scrollHeight; + }, + _updateFormattedLogs: debounce(function() { - const logs = this.get("controller.model"); + const logs = this.get("logs"); if (logs.length === 0) { this._reset(); // reset the cached logs whenever the model is reset } else { @@ -26,11 +35,12 @@ export default Ember.View.extend({ // update the formatted logs & cache index this.setProperties({ formattedLogs: formattedLogs, index: logs.length }); // force rerender - this.rerender(); + this.rerenderBuffer(); } - }, 150).observes("controller.model.[]"), + Ember.run.scheduleOnce('afterRender', this, this._scrollDown); + }, 150).observes("logs.[]").on('init'), - render(buffer) { + buildBuffer(buffer) { const formattedLogs = this.get("formattedLogs"); if (formattedLogs && formattedLogs.length > 0) { 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|}} 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 @@ -
    -
:{{e.name}}:
diff --git a/app/assets/javascripts/discourse/templates/modal/topic-bulk-actions.hbs b/app/assets/javascripts/discourse/templates/modal/topic-bulk-actions.hbs index 330de1ad81..3e4734e9da 100644 --- a/app/assets/javascripts/discourse/templates/modal/topic-bulk-actions.hbs +++ b/app/assets/javascripts/discourse/templates/modal/topic-bulk-actions.hbs @@ -1,6 +1,6 @@