{{description}}
+ {{#if post.cooked}} + + {{/if}}diff --git a/Gemfile.lock b/Gemfile.lock index 593d89ab1f..725ea9068b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -145,7 +145,7 @@ GEM thor (~> 0.15) libv8 (3.16.14.7) listen (0.7.3) - logster (0.8.3) + logster (0.8.4.1.pre) lru_redux (1.1.0) mail (2.5.4) mime-types (~> 1.16) @@ -206,7 +206,7 @@ GEM omniauth-twitter (1.0.1) multi_json (~> 1.3) omniauth-oauth (~> 1.0) - onebox (1.5.22) + onebox (1.5.23) moneta (~> 0.8) multi_json (~> 1.11) mustache diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6 index ebb63486d2..1ce48a1448 100644 --- a/app/assets/javascripts/admin/models/report.js.es6 +++ b/app/assets/javascripts/admin/models/report.js.es6 @@ -1,14 +1,12 @@ import round from "discourse/lib/round"; const Report = Discourse.Model.extend({ - reportUrl: function() { - return("/admin/reports/" + this.get('type')); - }.property('type'), + reportUrl: Discourse.computed.fmt("type", "/admin/reports/%@"), valueAt(numDaysAgo) { if (this.data) { - var wantedDate = moment().subtract(numDaysAgo, 'days').format('YYYY-MM-DD'); - var item = this.data.find( function(d) { return d.x === wantedDate; } ); + const wantedDate = moment().subtract(numDaysAgo, "days").format("YYYY-MM-DD"); + const item = this.data.find(d => d.x === wantedDate); if (item) { return item.y; } @@ -16,128 +14,117 @@ const Report = Discourse.Model.extend({ return 0; }, - sumDays(startDaysAgo, endDaysAgo) { + valueFor(startDaysAgo, endDaysAgo) { if (this.data) { - var earliestDate = moment().subtract(endDaysAgo, 'days').startOf('day'); - var latestDate = moment().subtract(startDaysAgo, 'days').startOf('day'); - var d, sum = 0; - _.each(this.data,function(datum){ + const earliestDate = moment().subtract(endDaysAgo, "days").startOf("day"); + const latestDate = moment().subtract(startDaysAgo, "days").startOf("day"); + var d, sum = 0, count = 0; + _.each(this.data, datum => { d = moment(datum.x); - if(d >= earliestDate && d <= latestDate) { + if (d >= earliestDate && d <= latestDate) { sum += datum.y; + count++; } }); + if (this.get("method") === "average") { sum /= count; } return round(sum, -2); } }, - todayCount: function() { - return this.valueAt(0); - }.property('data'), + todayCount: function() { return this.valueAt(0); }.property("data"), + yesterdayCount: function() { return this.valueAt(1); }.property("data"), + sevenDaysAgoCount: function() { return this.valueAt(7); }.property("data"), + thirtyDaysAgoCount: function() { return this.valueAt(30); }.property("data"), - yesterdayCount: function() { - return this.valueAt(1); - }.property('data'), - - lastSevenDaysCount: function() { - return this.sumDays(1,7); - }.property('data'), - - lastThirtyDaysCount: function() { - return this.sumDays(1,30); - }.property('data'), - - sevenDaysAgoCount: function() { - return this.valueAt(7); - }.property('data'), - - thirtyDaysAgoCount: function() { - return this.valueAt(30); - }.property('data'), + lastSevenDaysCount: function() { return this.valueFor(1, 7); }.property("data"), + lastThirtyDaysCount: function() { return this.valueFor(1, 30); }.property("data"), yesterdayTrend: function() { - var yesterdayVal = this.valueAt(1); - var twoDaysAgoVal = this.valueAt(2); - if ( yesterdayVal > twoDaysAgoVal ) { - return 'trending-up'; - } else if ( yesterdayVal < twoDaysAgoVal ) { - return 'trending-down'; + const yesterdayVal = this.valueAt(1); + const twoDaysAgoVal = this.valueAt(2); + if (yesterdayVal > twoDaysAgoVal) { + return "trending-up"; + } else if (yesterdayVal < twoDaysAgoVal) { + return "trending-down"; } else { - return 'no-change'; + return "no-change"; } - }.property('data'), + }.property("data"), sevenDayTrend: function() { - var currentPeriod = this.sumDays(1,7); - var prevPeriod = this.sumDays(8,14); - if ( currentPeriod > prevPeriod ) { - return 'trending-up'; - } else if ( currentPeriod < prevPeriod ) { - return 'trending-down'; + const currentPeriod = this.valueFor(1, 7); + const prevPeriod = this.valueFor(8, 14); + if (currentPeriod > prevPeriod) { + return "trending-up"; + } else if (currentPeriod < prevPeriod) { + return "trending-down"; } else { - return 'no-change'; + return "no-change"; } - }.property('data'), + }.property("data"), thirtyDayTrend: function() { - if( this.get('prev30Days') ) { - var currentPeriod = this.sumDays(1,30); - if( currentPeriod > this.get('prev30Days') ) { - return 'trending-up'; - } else if ( currentPeriod < this.get('prev30Days') ) { - return 'trending-down'; + if (this.get("prev30Days")) { + const currentPeriod = this.valueFor(1, 30); + if (currentPeriod > this.get("prev30Days")) { + return "trending-up"; + } else if (currentPeriod < this.get("prev30Days")) { + return "trending-down"; } } - return 'no-change'; - }.property('data', 'prev30Days'), + return "no-change"; + }.property("data", "prev30Days"), icon: function() { - switch( this.get('type') ) { - case 'flags': - return 'flag'; - case 'likes': - return 'heart'; - default: - return null; + switch (this.get("type")) { + case "flags": return "flag"; + case "likes": return "heart"; + default: return null; } - }.property('type'), + }.property("type"), + + method: function() { + if (this.get("type") === "time_to_first_response") { + return "average"; + } else { + return "sum"; + } + }.property("type"), percentChangeString(val1, val2) { - var val = ((val1 - val2) / val2) * 100; - if( isNaN(val) || !isFinite(val) ) { + const val = ((val1 - val2) / val2) * 100; + if (isNaN(val) || !isFinite(val)) { return null; - } else if( val > 0 ) { - return '+' + val.toFixed(0) + '%'; + } else if (val > 0) { + return "+" + val.toFixed(0) + "%"; } else { - return val.toFixed(0) + '%'; + return val.toFixed(0) + "%"; } }, changeTitle(val1, val2, prevPeriodString) { - var title = ''; - var percentChange = this.percentChangeString(val1, val2); - if( percentChange ) { - title += percentChange + ' change. '; - } - title += 'Was ' + val2 + ' ' + prevPeriodString + '.'; + const percentChange = this.percentChangeString(val1, val2); + var title = ""; + if (percentChange) { title += percentChange + " change. "; } + title += "Was " + val2 + " " + prevPeriodString + "."; return title; }, yesterdayCountTitle: function() { - return this.changeTitle( this.valueAt(1), this.valueAt(2),'two days ago'); - }.property('data'), + return this.changeTitle(this.valueAt(1), this.valueAt(2), "two days ago"); + }.property("data"), sevenDayCountTitle: function() { - return this.changeTitle( this.sumDays(1,7), this.sumDays(8,14), 'two weeks ago'); - }.property('data'), + return this.changeTitle(this.valueFor(1, 7), this.valueFor(8, 14), "two weeks ago"); + }.property("data"), thirtyDayCountTitle: function() { - return this.changeTitle( this.sumDays(1,30), this.get('prev30Days'), 'in the previous 30 day period'); - }.property('data'), + return this.changeTitle(this.valueFor(1, 30), this.get("prev30Days"), "in the previous 30 day period"); + }.property("data"), dataReversed: function() { - return this.get('data').toArray().reverse(); - }.property('data') + return this.get("data").toArray().reverse(); + }.property("data") }); diff --git a/app/assets/javascripts/admin/templates/admin.hbs b/app/assets/javascripts/admin/templates/admin.hbs index d8e88712c4..c7746a6d4a 100644 --- a/app/assets/javascripts/admin/templates/admin.hbs +++ b/app/assets/javascripts/admin/templates/admin.hbs @@ -1,5 +1,4 @@
" + result + "
"; - - if (!Em.isEmpty(cooked)) { - result += ""; - } - - return result; - } - }.property('actionCode', 'post.created_at', 'post.cooked'), + description: actionDescription('actionCode', 'post.created_at'), icon: function() { return icons[this.get('actionCode')] || 'exclamation'; diff --git a/app/assets/javascripts/discourse/components/stream-item.js.es6 b/app/assets/javascripts/discourse/components/stream-item.js.es6 new file mode 100644 index 0000000000..9a29d87438 --- /dev/null +++ b/app/assets/javascripts/discourse/components/stream-item.js.es6 @@ -0,0 +1,13 @@ +import { actionDescription } from "discourse/components/small-action"; + +export default Ember.Component.extend({ + classNameBindings: [":item", "item.hidden", "item.deleted", "moderatorAction"], + moderatorAction: Discourse.computed.propertyEqual("item.post_type", "site.post_types.moderator_action"), + actionDescription: actionDescription("item.action_code", "item.created_at"), + + actions: { + removeBookmark(userAction) { + this.sendAction("removeBookmark", userAction); + } + } +}); diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index 8ad012dd28..c4f1ac21b4 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -413,7 +413,7 @@ export default Ember.ObjectController.extend(Presence, { } // we need a draft sequence for the composer to work - if (opts.draftSequence === void 0) { + if (opts.draftSequence === undefined) { return Discourse.Draft.get(opts.draftKey).then(function(data) { opts.draftSequence = data.draft_sequence; opts.draft = data.draft; 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 a763a94c3d..4f3c38b629 100644 --- a/app/assets/javascripts/discourse/controllers/full-page-search.js.es6 +++ b/app/assets/javascripts/discourse/controllers/full-page-search.js.es6 @@ -1,32 +1,39 @@ -import DiscourseController from 'discourse/controllers/controller'; -import { translateResults } from 'discourse/lib/search-for-term'; +import DiscourseController from "discourse/controllers/controller"; +import { translateResults } from "discourse/lib/search-for-term"; export default DiscourseController.extend({ - loading: Em.computed.not('model'), - queryParams: ['q'], + needs: ["application"], + + loading: Em.computed.not("model"), + queryParams: ["q"], q: null, - modelChanged: function(){ - if (this.get('searchTerm') !== this.get('q')) { - this.set('searchTerm', this.get('q')); - } - }.observes('model'), - qChanged: function(){ - var model = this.get('model'); - if (model && this.get('model.q') !== this.get('q')){ - this.set('searchTerm', this.get('q')); - this.send('search'); + modelChanged: function() { + if (this.get("searchTerm") !== this.get("q")) { + this.set("searchTerm", this.get("q")); } - }.observes('q'), + }.observes("model"), + + qChanged: function() { + const model = this.get("model"); + if (model && this.get("model.q") !== this.get("q")) { + this.set("searchTerm", this.get("q")); + this.send("search"); + } + }.observes("q"), + + _showFooter: function() { + this.set("controllers.application.showFooter", !this.get("loading")); + }.observes("loading"), + actions: { - search: function(){ - var self = this; - this.set('q', this.get('searchTerm')); - this.set('model', null); + search() { + this.set("q", this.get("searchTerm")); + this.set("model", null); - Discourse.ajax('/search', {data: {q: this.get('searchTerm')}}).then(function(results) { - self.set('model', translateResults(results) || {}); - self.set('model.q', self.get('q')); + Discourse.ajax("/search", { data: { q: this.get("searchTerm") } }).then(results => { + this.set("model", translateResults(results) || {}); + this.set("model.q", this.get("q")); }); } } diff --git a/app/assets/javascripts/discourse/controllers/merge-topic.js.es6 b/app/assets/javascripts/discourse/controllers/merge-topic.js.es6 index c923aaf2da..44f374ddbf 100644 --- a/app/assets/javascripts/discourse/controllers/merge-topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/merge-topic.js.es6 @@ -1,12 +1,15 @@ import Presence from 'discourse/mixins/presence'; import SelectedPostsCount from 'discourse/mixins/selected-posts-count'; import ModalFunctionality from 'discourse/mixins/modal-functionality'; -import ObjectController from 'discourse/controllers/object'; +import { movePosts, mergeTopic } from 'discourse/models/topic'; // Modal related to merging of topics -export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, Presence, { +export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, Presence, { needs: ['topic'], + saving: false, + selectedTopicId: null, + topicController: Em.computed.alias('controllers.topic'), selectedPosts: Em.computed.alias('topicController.selectedPosts'), selectedReplies: Em.computed.alias('topicController.selectedReplies'), @@ -22,38 +25,40 @@ export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, P return I18n.t('topic.merge_topic.title'); }.property('saving'), - onShow: function() { + onShow() { this.set('controllers.modal.modalClass', 'split-modal'); }, actions: { - movePostsToExistingTopic: function() { + movePostsToExistingTopic() { + const topicId = this.get('model.id'); + this.set('saving', true); - var promise = null; + let promise = null; if (this.get('allPostsSelected')) { - promise = Discourse.Topic.mergeTopic(this.get('id'), this.get('selectedTopicId')); + promise = mergeTopic(topicId, this.get('selectedTopicId')); } else { - var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }), - replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }); + const postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }); + const replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }); - promise = Discourse.Topic.movePosts(this.get('id'), { + promise = movePosts(topicId, { destination_topic_id: this.get('selectedTopicId'), post_ids: postIds, reply_post_ids: replyPostIds }); } - var mergeTopicController = this; + const self = this; promise.then(function(result) { // Posts moved - mergeTopicController.send('closeModal'); - mergeTopicController.get('topicController').send('toggleMultiSelect'); + self.send('closeModal'); + self.get('topicController').send('toggleMultiSelect'); Em.run.next(function() { Discourse.URL.routeTo(result.url); }); - }, function() { - // Error moving posts - mergeTopicController.flash(I18n.t('topic.merge_topic.error')); - mergeTopicController.set('saving', false); + }).catch(function() { + self.flash(I18n.t('topic.merge_topic.error')); + }).finally(function() { + self.set('saving', false); }); return false; } diff --git a/app/assets/javascripts/discourse/controllers/split-topic.js.es6 b/app/assets/javascripts/discourse/controllers/split-topic.js.es6 index 98aed2dcce..0c75ae3503 100644 --- a/app/assets/javascripts/discourse/controllers/split-topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/split-topic.js.es6 @@ -1,15 +1,20 @@ import Presence from 'discourse/mixins/presence'; import SelectedPostsCount from 'discourse/mixins/selected-posts-count'; import ModalFunctionality from 'discourse/mixins/modal-functionality'; -import ObjectController from 'discourse/controllers/object'; +import { extractError } from 'discourse/lib/ajax-error'; +import { movePosts } from 'discourse/models/topic'; // Modal related to auto closing of topics -export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, Presence, { +export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, Presence, { needs: ['topic'], + topicName: null, + saving: false, + categoryId: 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'), buttonDisabled: function() { if (this.get('saving')) return true; @@ -21,7 +26,7 @@ export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, P return I18n.t('topic.split_topic.action'); }.property('saving'), - onShow: function() { + onShow() { this.setProperties({ 'controllers.modal.modalClass': 'split-modal', saving: false, @@ -31,39 +36,29 @@ export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, P }, actions: { - movePostsToNewTopic: function() { + movePostsToNewTopic() { this.set('saving', true); - var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }), - replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }), - self = this, - categoryId = this.get('categoryId'), - saveOpts = { - title: this.get('topicName'), - post_ids: postIds, - reply_post_ids: replyPostIds - }; + const postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }), + replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }), + self = this, + categoryId = this.get('categoryId'), + saveOpts = { + title: this.get('topicName'), + post_ids: postIds, + reply_post_ids: replyPostIds + }; if (!Ember.isNone(categoryId)) { saveOpts.category_id = categoryId; } - Discourse.Topic.movePosts(this.get('id'), saveOpts).then(function(result) { + movePosts(this.get('model.id'), saveOpts).then(function(result) { // Posts moved self.send('closeModal'); self.get('topicController').send('toggleMultiSelect'); - Em.run.next(function() { Discourse.URL.routeTo(result.url); }); + Ember.run.next(function() { Discourse.URL.routeTo(result.url); }); }).catch(function(xhr) { - - var error = I18n.t('topic.split_topic.error'); - - if (xhr) { - var json = xhr.responseJSON; - if (json && json.errors) { - error = json.errors[0]; - } - } - - // Error moving posts - self.flash(error); + self.flash(extractError(xhr, I18n.t('topic.split_topic.error'))); + }).finally(function() { self.set('saving', false); }); return false; diff --git a/app/assets/javascripts/discourse/controllers/static.js.es6 b/app/assets/javascripts/discourse/controllers/static.js.es6 index 2e9050b2d5..c22ce3c26d 100644 --- a/app/assets/javascripts/discourse/controllers/static.js.es6 +++ b/app/assets/javascripts/discourse/controllers/static.js.es6 @@ -1,8 +1,8 @@ export default Ember.Controller.extend({ - showLoginButton: Em.computed.equal('model.path', 'login'), + showLoginButton: Em.computed.equal("model.path", "login"), actions: { - markFaqRead: function() { + markFaqRead() { if (this.currentUser) { Discourse.ajax("/users/read-faq", { method: "POST" }); } diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index aace6f8e0f..7dbce6dbb4 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -725,7 +725,8 @@ export default ObjectController.extend(SelectedPostsCount, BufferedContent, { }, _showFooter: function() { - this.set("controllers.application.showFooter", this.get("model.postStream.loadedAllPosts")); - }.observes("model.postStream.loadedAllPosts") + const showFooter = this.get("model.postStream.loaded") && this.get("model.postStream.loadedAllPosts"); + this.set("controllers.application.showFooter", showFooter); + }.observes("model.postStream.{loaded,loadedAllPosts}") }); diff --git a/app/assets/javascripts/discourse/controllers/user-activity.js.es6 b/app/assets/javascripts/discourse/controllers/user-activity.js.es6 index 6113cedff3..7e4ec2db92 100644 --- a/app/assets/javascripts/discourse/controllers/user-activity.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-activity.js.es6 @@ -5,7 +5,7 @@ export default Ember.ObjectController.extend({ _showFooter: function() { var showFooter; if (this.get("userActionType")) { - var stat = _.find(this.get("model.stats"), { action_type: this.get("userActionType") }); + const stat = _.find(this.get("model.stats"), { action_type: this.get("userActionType") }); showFooter = stat && stat.count <= this.get("model.stream.itemsLoaded"); } else { showFooter = this.get("model.statsCountNonPM") <= this.get("model.stream.itemsLoaded"); diff --git a/app/assets/javascripts/discourse/controllers/users.js.es6 b/app/assets/javascripts/discourse/controllers/users.js.es6 index 8ff6e6e498..8705fb850b 100644 --- a/app/assets/javascripts/discourse/controllers/users.js.es6 +++ b/app/assets/javascripts/discourse/controllers/users.js.es6 @@ -1,19 +1,24 @@ export default Ember.Controller.extend({ - queryParams: ['period', 'order', 'asc', 'name'], - period: 'weekly', - order: 'likes_received', + needs: ["application"], + queryParams: ["period", "order", "asc", "name"], + period: "weekly", + order: "likes_received", asc: null, - name: '', + name: "", - showTimeRead: Ember.computed.equal('period', 'all'), + showTimeRead: Ember.computed.equal("period", "all"), _setName: Discourse.debounce(function() { - this.set('name', this.get('nameInput')); - }, 500).observes('nameInput'), + this.set("name", this.get("nameInput")); + }, 500).observes("nameInput"), + + _showFooter: function() { + this.set("controllers.application.showFooter", !this.get("model.canLoadMore")); + }.observes("model.canLoadMore"), actions: { loadMore() { - this.get('model').loadMore(); + this.get("model").loadMore(); } } }); diff --git a/app/assets/javascripts/discourse/dialects/dialect.js b/app/assets/javascripts/discourse/dialects/dialect.js index 62febca1a7..e80e5e9671 100644 --- a/app/assets/javascripts/discourse/dialects/dialect.js +++ b/app/assets/javascripts/discourse/dialects/dialect.js @@ -188,15 +188,8 @@ function hoistCodeBlocksAndSpans(text) { // /!\ the order is important /!\ - //...code blocks - text = text.replace(/(^\n*|\n\n)
([\s\S]*?)<\/pre>/ig, function(_, before, content) {
- var hash = md5(content);
- hoisted[hash] = escape(showBackslashEscapedCharacters(removeEmptyLines(content)));
- return before + "" + hash + "
";
- });
-
// fenced code blocks (AKA GitHub code blocks)
- text = text.replace(/(^\n*|\n\n)```([a-z0-9\-]*)\n([\s\S]*?)\n```/g, function(_, before, language, content) {
+ text = text.replace(/(^\n*|\n)```([a-z0-9\-]*)\n([\s\S]*?)\n```/g, function(_, before, language, content) {
var hash = md5(content);
hoisted[hash] = escape(showBackslashEscapedCharacters(removeEmptyLines(content)));
return before + "```" + language + "\n" + hash + "\n```";
@@ -218,6 +211,13 @@ function hoistCodeBlocksAndSpans(text) {
return before + " " + hash + "\n";
});
+ // ...
code blocks
+ text = text.replace(/(\s|^)([\s\S]*?)<\/pre>/ig, function(_, before, content) {
+ var hash = md5(content);
+ hoisted[hash] = escape(showBackslashEscapedCharacters(removeEmptyLines(content)));
+ return before + "" + hash + "
";
+ });
+
// code spans (double & single `)
["``", "`"].forEach(function(delimiter) {
var regexp = new RegExp("(^|[^`])" + delimiter + "([^`\\n]+?)" + delimiter + "([^`]|$)", "g");
@@ -277,11 +277,19 @@ Discourse.Dialect = {
// If we hoisted out anything, put it back
var keys = Object.keys(hoisted);
if (keys.length) {
- keys.forEach(function(key) {
+ var found = true;
+
+ var unhoist = function(key) {
result = result.replace(new RegExp(key, "g"), function() {
+ found = true;
return hoisted[key];
});
- });
+ };
+
+ while(found) {
+ found = false;
+ keys.forEach(unhoist);
+ }
}
return result.trim();
diff --git a/app/assets/javascripts/discourse/dialects/quote_dialect.js b/app/assets/javascripts/discourse/dialects/quote_dialect.js
index 3c50598cfc..28f8de131c 100644
--- a/app/assets/javascripts/discourse/dialects/quote_dialect.js
+++ b/app/assets/javascripts/discourse/dialects/quote_dialect.js
@@ -26,7 +26,9 @@ Discourse.BBCode.register('quote', {noWrap: true, singlePara: true}, function(co
if (options.lookupAvatarByPostNumber) {
// client-side, we can retrieve the avatar from the post
var postNumber = parseInt(params['data-post'], 10);
- avatarImg = options.lookupAvatarByPostNumber(postNumber);
+ var topicId = parseInt(params['data-topic'], 10);
+
+ avatarImg = options.lookupAvatarByPostNumber(postNumber, topicId);
} else if (options.lookupAvatar) {
// server-side, we need to lookup the avatar from the username
avatarImg = options.lookupAvatar(username);
diff --git a/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6 b/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6
index 1492a11bea..13acb784e9 100644
--- a/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6
+++ b/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6
@@ -47,7 +47,7 @@
**/
-let _connectorCache;
+let _connectorCache, _rawCache;
function findOutlets(collection, callback) {
@@ -73,6 +73,7 @@ function findOutlets(collection, callback) {
function buildConnectorCache() {
_connectorCache = {};
+ _rawCache = {};
const uniqueViews = {};
findOutlets(requirejs._eak_seen, function(outletName, resource, uniqueName) {
@@ -93,10 +94,23 @@ function buildConnectorCache() {
// We are going to add it back with the proper template
_connectorCache[outletName].removeObject(viewClass);
} else {
- viewClass = Em.View.extend({ classNames: [outletName + '-outlet', uniqueName] });
+ if (!/\.raw$/.test(uniqueName)) {
+ viewClass = Em.View.extend({ classNames: [outletName + '-outlet', uniqueName] });
+ }
+ }
+
+ if (viewClass) {
+ _connectorCache[outletName].pushObject(viewClass.extend(mixin));
+ } else {
+ // we have a raw template
+ if (!_rawCache[outletName]) {
+ _rawCache[outletName] = [];
+ }
+
+ _rawCache[outletName].push(Ember.TEMPLATES[resource]);
}
- _connectorCache[outletName].pushObject(viewClass.extend(mixin));
});
+
}
var _viewInjections;
@@ -113,6 +127,24 @@ function viewInjections(container) {
return _viewInjections;
}
+// unbound version of outlets, only has a template
+Handlebars.registerHelper('plugin-outlet', function(name){
+
+ if (!_rawCache) { buildConnectorCache(); }
+
+ const functions = _rawCache[name];
+ if (functions) {
+ var output = [];
+
+ for(var i=0; i" + title + "");
+ var string = "" + title + "";
+
+ return new Handlebars.SafeString(string);
});
diff --git a/app/assets/javascripts/discourse/initializers/show-footer.js.es6 b/app/assets/javascripts/discourse/initializers/show-footer.js.es6
new file mode 100644
index 0000000000..ce58457774
--- /dev/null
+++ b/app/assets/javascripts/discourse/initializers/show-footer.js.es6
@@ -0,0 +1,15 @@
+export default {
+ name: "show-footer",
+
+ initialize(container) {
+ const router = container.lookup("router:main");
+ const application = container.lookup("controller:application");
+
+ // only take care of hiding the footer here
+ // controllers MUST take care of displaying it
+ router.on("willTransition", () => {
+ application.set("showFooter", false);
+ return true;
+ });
+ }
+};
diff --git a/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 b/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6
index a45a5a3585..f833aa1c09 100644
--- a/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6
+++ b/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6
@@ -35,6 +35,9 @@ export default {
});
bus.subscribe('/queue_counts', (data) => {
user.set('post_queue_new_count', data.post_queue_new_count);
+ if (data.post_queue_new_count > 0) {
+ user.set('show_queued_posts', 1);
+ }
});
}
diff --git a/app/assets/javascripts/discourse/lib/ajax-error.js.es6 b/app/assets/javascripts/discourse/lib/ajax-error.js.es6
index 04d6d0dbc7..bb2a915727 100644
--- a/app/assets/javascripts/discourse/lib/ajax-error.js.es6
+++ b/app/assets/javascripts/discourse/lib/ajax-error.js.es6
@@ -1,4 +1,4 @@
-function extractError(error) {
+export function extractError(error, defaultMessage) {
if (error instanceof Error) {
Ember.Logger.error(error.stack);
}
@@ -42,7 +42,7 @@ function extractError(error) {
}
}
- return parsedError || I18n.t('generic_error');
+ return parsedError || defaultMessage || I18n.t('generic_error');
}
export function throwAjaxError(undoCallback) {
diff --git a/app/assets/javascripts/discourse/lib/desktop-notifications.js.es6 b/app/assets/javascripts/discourse/lib/desktop-notifications.js.es6
index 5d7b18db0f..ce67ff9dfd 100644
--- a/app/assets/javascripts/discourse/lib/desktop-notifications.js.es6
+++ b/app/assets/javascripts/discourse/lib/desktop-notifications.js.es6
@@ -94,6 +94,7 @@ function onNotification(data) {
if (!liveEnabled) { return; }
if (!primaryTab) { return; }
if (!isIdle()) { return; }
+ if (localStorage.getItem('notifications-disabled')) { return; }
const notificationTitle = I18n.t(i18nKey(data.notification_type), {
site_title: Discourse.SiteSettings.title,
diff --git a/app/assets/javascripts/discourse/lib/emoji/emoji-toolbar.js.es6 b/app/assets/javascripts/discourse/lib/emoji/emoji-toolbar.js.es6
index 00287b21a5..c5b731da09 100644
--- a/app/assets/javascripts/discourse/lib/emoji/emoji-toolbar.js.es6
+++ b/app/assets/javascripts/discourse/lib/emoji/emoji-toolbar.js.es6
@@ -11,7 +11,7 @@ var groups = [
{
name: "nature",
fullname: "Nature",
- tabicon: "leaves",
+ tabicon: "evergreen_tree",
icons: ["seedling", "evergreen_tree", "deciduous_tree", "palm_tree", "cactus", "tulip", "cherry_blossom", "rose", "hibiscus", "sunflower", "blossom", "bouquet", "ear_of_rice", "herb", "four_leaf_clover", "maple_leaf", "fallen_leaf", "leaves", "mushroom", "chestnut", "rat", "mouse2", "mouse", "hamster", "ox", "water_buffalo", "cow2", "cow", "tiger2", "leopard", "tiger", "rabbit2", "rabbit", "cat2", "cat", "racehorse", "horse", "ram", "sheep", "goat", "rooster", "chicken", "baby_chick", "hatching_chick", "hatched_chick", "bird", "penguin", "elephant", "dromedary_camel", "camel", "boar", "pig2", "pig", "pig_nose", "dog2", "poodle", "dog", "wolf", "bear", "koala", "panda_face", "monkey_face", "see_no_evil", "hear_no_evil", "speak_no_evil", "monkey", "dragon", "dragon_face", "crocodile", "snake", "turtle", "frog", "whale2", "whale", "dolphin", "octopus", "fish", "tropical_fish", "blowfish", "shell", "snail", "bug", "ant", "bee", "beetle", "feet", "zap", "fire", "crescent_moon", "sunny", "partly_sunny", "cloud", "droplet", "sweat_drops", "umbrella", "dash", "snowflake", "star2", "star", "stars", "sunrise_over_mountains", "sunrise", "rainbow", "ocean", "volcano", "milky_way", "mount_fuji", "japan", "globe_with_meridians", "earth_africa", "earth_americas", "earth_asia", "new_moon", "waxing_crescent_moon", "first_quarter_moon", "moon", "full_moon", "waning_gibbous_moon", "last_quarter_moon", "waning_crescent_moon", "new_moon_with_face", "full_moon_with_face", "first_quarter_moon_with_face", "last_quarter_moon_with_face", "sun_with_face"]
},
{
@@ -144,7 +144,7 @@ var toolbar = function(selected){
var icon = g.tabicon;
var title = g.fullname;
if (g.name === "recent") {
- icon = "star2";
+ icon = "star";
title = "Recent";
} else if (g.name === "ungrouped") {
icon = g.icons[0];
diff --git a/app/assets/javascripts/discourse/lib/static-route-builder.js.es6 b/app/assets/javascripts/discourse/lib/static-route-builder.js.es6
index 79365f4655..09ef6736c2 100644
--- a/app/assets/javascripts/discourse/lib/static-route-builder.js.es6
+++ b/app/assets/javascripts/discourse/lib/static-route-builder.js.es6
@@ -1,39 +1,42 @@
-import ShowFooter from "discourse/mixins/show-footer";
-
-var configs = {
- 'faq': 'faq_url',
- 'tos': 'tos_url',
- 'privacy': 'privacy_policy_url'
+const configs = {
+ "faq": "faq_url",
+ "tos": "tos_url",
+ "privacy": "privacy_policy_url"
};
-export default function(page) {
- return Discourse.Route.extend(ShowFooter, {
- renderTemplate: function() {
- this.render('static');
+export default (page) => {
+ return Discourse.Route.extend({
+ renderTemplate() {
+ this.render("static");
},
- beforeModel: function(transition) {
- var configKey = configs[page];
+ beforeModel(transition) {
+ const configKey = configs[page];
if (configKey && Discourse.SiteSettings[configKey].length > 0) {
transition.abort();
Discourse.URL.redirectTo(Discourse.SiteSettings[configKey]);
}
},
- activate: function() {
+ activate() {
this._super();
-
// Scroll to an element if exists
Discourse.URL.scrollToId(document.location.hash);
},
- model: function() {
+ model() {
return Discourse.StaticPage.find(page);
},
- setupController: function(controller, model) {
- this.controllerFor('static').set('model', model);
+ setupController(controller, model) {
+ this.controllerFor("static").set("model", model);
+ },
+
+ actions: {
+ didTransition() {
+ this.controllerFor("application").set("showFooter", true);
+ return true;
+ }
}
});
-}
-
+};
diff --git a/app/assets/javascripts/discourse/mixins/ajax.js b/app/assets/javascripts/discourse/mixins/ajax.js
index a659ed57be..6817150d51 100644
--- a/app/assets/javascripts/discourse/mixins/ajax.js
+++ b/app/assets/javascripts/discourse/mixins/ajax.js
@@ -47,7 +47,8 @@ Discourse.Ajax = Em.Mixin.create({
if (_trackView && (!args.type || args.type === "GET")) {
_trackView = false;
- args.headers['Discourse-Track-View'] = true;
+ // DON'T CHANGE: rack is prepending "HTTP_" in the header's name
+ args.headers['DISCOURSE_TRACK_VIEW'] = true;
}
args.success = function(data, textStatus, xhr) {
diff --git a/app/assets/javascripts/discourse/mixins/scrolling.js b/app/assets/javascripts/discourse/mixins/scrolling.js
index 6178e46a33..c9473c155e 100644
--- a/app/assets/javascripts/discourse/mixins/scrolling.js
+++ b/app/assets/javascripts/discourse/mixins/scrolling.js
@@ -33,6 +33,7 @@ Discourse.Scrolling = Em.Mixin.create({
}
Discourse.ScrollingDOMMethods.bindOnScroll(onScrollMethod, opts.name);
+ Em.run.scheduleOnce('afterRender', onScrollMethod);
},
/**
diff --git a/app/assets/javascripts/discourse/mixins/show-footer.js.es6 b/app/assets/javascripts/discourse/mixins/show-footer.js.es6
deleted file mode 100644
index b97014153a..0000000000
--- a/app/assets/javascripts/discourse/mixins/show-footer.js.es6
+++ /dev/null
@@ -1,15 +0,0 @@
-export default Em.Mixin.create({
- actions: {
- didTransition() {
- Em.run.schedule("afterRender", () => {
- this.controllerFor("application").set("showFooter", true);
- });
- return true;
- },
-
- willTransition() {
- this.controllerFor("application").set("showFooter", false);
- return true;
- }
- }
-});
diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6
index 49838fdf72..edde5df3c6 100644
--- a/app/assets/javascripts/discourse/models/composer.js.es6
+++ b/app/assets/javascripts/discourse/models/composer.js.es6
@@ -22,7 +22,9 @@ const CLOSED = 'closed',
topic_id: 'topic.id',
is_warning: 'isWarning',
archetype: 'archetypeId',
- target_usernames: 'targetUsernames'
+ target_usernames: 'targetUsernames',
+ typing_duration_msecs: 'typingTime',
+ composer_open_duration_msecs: 'composerTime'
},
_edit_topic_serializer = {
@@ -52,6 +54,31 @@ const Composer = RestModel.extend({
viewOpen: Em.computed.equal('composeState', OPEN),
viewDraft: Em.computed.equal('composeState', DRAFT),
+ composeStateChanged: function() {
+ var oldOpen = this.get('composerOpened');
+
+ if (this.get('composeState') === OPEN) {
+ this.set('composerOpened', oldOpen || new Date());
+ } else {
+ if (oldOpen) {
+ var oldTotal = this.get('composerTotalOpened') || 0;
+ this.set('composerTotalOpened', oldTotal + (new Date() - oldOpen));
+ }
+ this.set('composerOpened', null);
+ }
+ }.observes('composeState'),
+
+ composerTime: function() {
+ var total = this.get('composerTotalOpened') || 0;
+
+ var oldOpen = this.get('composerOpened');
+ if (oldOpen) {
+ total += (new Date() - oldOpen);
+ }
+
+ return total;
+ }.property().volatile(),
+
archetype: function() {
return this.get('archetypes').findProperty('id', this.get('archetypeId'));
}.property('archetypeId'),
@@ -60,6 +87,12 @@ const Composer = RestModel.extend({
return this.set('metaData', Em.Object.create());
}.observes('archetype'),
+ // view detected user is typing
+ typing: _.throttle(function(){
+ var typingTime = this.get("typingTime") || 0;
+ this.set("typingTime", typingTime + 100);
+ }, 100, {leading: false, trailing: true}),
+
editingFirstPost: Em.computed.and('editingPost', 'post.firstPost'),
canEditTitle: Em.computed.or('creatingTopic', 'creatingPrivateMessage', 'editingFirstPost'),
canCategorize: Em.computed.and('canEditTitle', 'notCreatingPrivateMessage'),
@@ -349,7 +382,9 @@ const Composer = RestModel.extend({
composeState: opts.composerState || OPEN,
action: opts.action,
topic: opts.topic,
- targetUsernames: opts.usernames
+ targetUsernames: opts.usernames,
+ composerTotalOpened: opts.composerTime,
+ typingTime: opts.typingTime
});
if (opts.post) {
@@ -420,7 +455,10 @@ const Composer = RestModel.extend({
post: null,
title: null,
editReason: null,
- stagedPost: false
+ stagedPost: false,
+ typingTime: 0,
+ composerOpened: null,
+ composerTotalOpened: 0
});
},
@@ -502,7 +540,9 @@ const Composer = RestModel.extend({
admin: user.get('admin'),
yours: true,
read: true,
- wiki: false
+ wiki: false,
+ typingTime: this.get('typingTime'),
+ composerTime: this.get('composerTime')
});
this.serialize(_create_serializer, createdPost);
@@ -603,13 +643,20 @@ const Composer = RestModel.extend({
postId: this.get('post.id'),
archetypeId: this.get('archetypeId'),
metaData: this.get('metaData'),
- usernames: this.get('targetUsernames')
+ usernames: this.get('targetUsernames'),
+ composerTime: this.get('composerTime'),
+ typingTime: this.get('typingTime')
};
this.set('draftStatus', I18n.t('composer.saving_draft_tip'));
const composer = this;
+ if (this._clearingStatus) {
+ Em.run.cancel(this._clearingStatus);
+ this._clearingStatus = null;
+ }
+
// try to save the draft
return Discourse.Draft.save(this.get('draftKey'), this.get('draftSequence'), data)
.then(function() {
@@ -617,7 +664,20 @@ const Composer = RestModel.extend({
}).catch(function() {
composer.set('draftStatus', I18n.t('composer.drafts_offline'));
});
- }
+ },
+
+ dataChanged: function(){
+ const draftStatus = this.get('draftStatus');
+ const self = this;
+
+ if (draftStatus && !this._clearingStatus) {
+
+ this._clearingStatus = Em.run.later(this, function(){
+ self.set('draftStatus', null);
+ self._clearingStatus = null;
+ }, 1000);
+ }
+ }.observes('title','reply')
});
@@ -657,7 +717,9 @@ Composer.reopenClass({
metaData: draft.metaData,
usernames: draft.usernames,
draft: true,
- composerState: DRAFT
+ composerState: DRAFT,
+ composerTime: draft.composerTime,
+ typingTime: draft.typingTime
});
}
},
diff --git a/app/assets/javascripts/discourse/models/nav_item.js b/app/assets/javascripts/discourse/models/nav-item.js.es6
similarity index 79%
rename from app/assets/javascripts/discourse/models/nav_item.js
rename to app/assets/javascripts/discourse/models/nav-item.js.es6
index 0ea27df11e..def6a3430a 100644
--- a/app/assets/javascripts/discourse/models/nav_item.js
+++ b/app/assets/javascripts/discourse/models/nav-item.js.es6
@@ -7,7 +7,7 @@
@module Discourse
**/
-Discourse.NavItem = Discourse.Model.extend({
+const NavItem = Discourse.Model.extend({
displayName: function() {
var categoryName = this.get('categoryName'),
@@ -25,7 +25,7 @@ Discourse.NavItem = Discourse.Model.extend({
extra.categoryName = Discourse.Formatter.toTitleCase(categoryName);
}
return I18n.t("filters." + name.replace("/", ".") + ".title", extra);
- }.property('categoryName,name,count'),
+ }.property('categoryName', 'name', 'count'),
topicTrackingState: function() {
return Discourse.TopicTrackingState.current();
@@ -45,8 +45,13 @@ Discourse.NavItem = Discourse.Model.extend({
return null;
}.property('name'),
- // href from this item
href: function() {
+ var customHref = null;
+ _.each(NavItem.customNavItemHrefs, function(cb) {
+ customHref = cb.call(this, this);
+ if (customHref) { return false; }
+ }, this);
+ if (customHref) { return customHref; }
return Discourse.getURL("/") + this.get('filterMode');
}.property('filterMode'),
@@ -79,10 +84,13 @@ Discourse.NavItem = Discourse.Model.extend({
});
-Discourse.NavItem.reopenClass({
+NavItem.reopenClass({
+
+ extraArgsCallbacks: [],
+ customNavItemHrefs: [],
// create a nav item from the text, will return null if there is not valid nav item for this particular text
- fromText: function(text, opts) {
+ fromText(text, opts) {
var split = text.split(","),
name = split[0],
testName = name.split("/")[0],
@@ -92,13 +100,17 @@ Discourse.NavItem.reopenClass({
if (!Discourse.Category.list() && testName === "categories") return null;
if (!Discourse.Site.currentProp('top_menu_items').contains(testName)) return null;
- var args = { name: name, hasIcon: name === "unread" };
+ var args = { name: name, hasIcon: name === "unread" }, extra = null, self = this;
if (opts.category) { args.category = opts.category; }
if (opts.noSubcategories) { args.noSubcategories = true; }
+ _.each(NavItem.extraArgsCallbacks, function(cb) {
+ extra = cb.call(self, text, opts);
+ _.merge(args, extra);
+ });
return Discourse.NavItem.create(args);
},
- buildList: function(category, args) {
+ buildList(category, args) {
args = args || {};
if (category) { args.category = category }
@@ -118,3 +130,11 @@ Discourse.NavItem.reopenClass({
}
});
+
+export default NavItem;
+export function extraNavItemProperties(cb) {
+ NavItem.extraArgsCallbacks.push(cb);
+}
+export function customNavItemHref(cb) {
+ NavItem.customNavItemHrefs.push(cb);
+}
diff --git a/app/assets/javascripts/discourse/models/topic-list.js.es6 b/app/assets/javascripts/discourse/models/topic-list.js.es6
index d685b2f60c..782cb9fd06 100644
--- a/app/assets/javascripts/discourse/models/topic-list.js.es6
+++ b/app/assets/javascripts/discourse/models/topic-list.js.es6
@@ -1,7 +1,6 @@
import RestModel from 'discourse/models/rest';
import Model from 'discourse/models/model';
-
function topicsFrom(result, store) {
if (!result) { return; }
diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6
index 0f06dc4847..2455087411 100644
--- a/app/assets/javascripts/discourse/models/topic.js.es6
+++ b/app/assets/javascripts/discourse/models/topic.js.es6
@@ -1,3 +1,4 @@
+import { flushMap } from 'discourse/models/store';
import RestModel from 'discourse/models/rest';
const Topic = RestModel.extend({
@@ -462,28 +463,6 @@ Topic.reopenClass({
return Discourse.ajax(url + ".json", {data: data});
},
- mergeTopic(topicId, destinationTopicId) {
- const promise = Discourse.ajax("/t/" + topicId + "/merge-topic", {
- type: 'POST',
- data: {destination_topic_id: destinationTopicId}
- }).then(function (result) {
- if (result.success) return result;
- promise.reject(new Error("error merging topic"));
- });
- return promise;
- },
-
- movePosts(topicId, opts) {
- const promise = Discourse.ajax("/t/" + topicId + "/move-posts", {
- type: 'POST',
- data: opts
- }).then(function (result) {
- if (result.success) return result;
- promise.reject(new Error("error moving posts topic"));
- });
- return promise;
- },
-
changeOwners(topicId, opts) {
const promise = Discourse.ajax("/t/" + topicId + "/change-owner", {
type: 'POST',
@@ -523,4 +502,24 @@ Topic.reopenClass({
}
});
+function moveResult(result) {
+ if (result.success) {
+ // We should be hesitant to flush the map but moving ids is one rare case
+ flushMap();
+ return result;
+ }
+ throw "error moving posts topic";
+}
+
+export function movePosts(topicId, data) {
+ return Discourse.ajax("/t/" + topicId + "/move-posts", { type: 'POST', data }).then(moveResult);
+}
+
+export function mergeTopic(topicId, destinationTopicId) {
+ return Discourse.ajax("/t/" + topicId + "/merge-topic", {
+ type: 'POST',
+ data: {destination_topic_id: destinationTopicId}
+ }).then(moveResult);
+}
+
export default Topic;
diff --git a/app/assets/javascripts/discourse/routes/about.js.es6 b/app/assets/javascripts/discourse/routes/about.js.es6
index 5258ea7fbd..f25d64387b 100644
--- a/app/assets/javascripts/discourse/routes/about.js.es6
+++ b/app/assets/javascripts/discourse/routes/about.js.es6
@@ -1,13 +1,16 @@
-import ShowFooter from "discourse/mixins/show-footer";
-
-export default Discourse.Route.extend(ShowFooter, {
- model: function() {
- return Discourse.ajax("/about.json").then(function(result) {
- return result.about;
- });
+export default Discourse.Route.extend({
+ model() {
+ return Discourse.ajax("/about.json").then(result => result.about);
},
- titleToken: function() {
+ titleToken() {
return I18n.t('about.simple_title');
+ },
+
+ actions: {
+ didTransition() {
+ this.controllerFor("application").set("showFooter", true);
+ return true;
+ }
}
});
diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6
index b2c58f4fc8..f0af569b02 100644
--- a/app/assets/javascripts/discourse/routes/application.js.es6
+++ b/app/assets/javascripts/discourse/routes/application.js.es6
@@ -53,7 +53,7 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
error(err, transition) {
if (err.status === 404) {
// 404
- this.intermediateTransitionTo('unknown');
+ this.transitionTo('unknown');
return;
}
@@ -74,7 +74,7 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
}
exceptionController.setProperties({ lastTransition: transition, thrown: err });
- this.intermediateTransitionTo('exception');
+ this.transitionTo('exception');
},
showLogin: unlessReadOnly('handleShowLogin'),
diff --git a/app/assets/javascripts/discourse/routes/badges-index.js.es6 b/app/assets/javascripts/discourse/routes/badges-index.js.es6
index 67af4625f2..dfb207391f 100644
--- a/app/assets/javascripts/discourse/routes/badges-index.js.es6
+++ b/app/assets/javascripts/discourse/routes/badges-index.js.es6
@@ -1,17 +1,20 @@
-import ShowFooter from "discourse/mixins/show-footer";
-
-export default Discourse.Route.extend(ShowFooter, {
- model: function() {
- if (PreloadStore.get('badges')) {
- return PreloadStore.getAndRemove('badges').then(function(json) {
- return Discourse.Badge.createFromJson(json);
- });
+export default Discourse.Route.extend({
+ model() {
+ if (PreloadStore.get("badges")) {
+ return PreloadStore.getAndRemove("badges").then(json => Discourse.Badge.createFromJson(json));
} else {
- return Discourse.Badge.findAll({onlyListable: true});
+ return Discourse.Badge.findAll({ onlyListable: true });
}
},
- titleToken: function() {
- return I18n.t('badges.title');
+ titleToken() {
+ return I18n.t("badges.title");
+ },
+
+ actions: {
+ didTransition() {
+ this.controllerFor("application").set("showFooter", true);
+ return true;
+ }
}
});
diff --git a/app/assets/javascripts/discourse/routes/badges-show.js.es6 b/app/assets/javascripts/discourse/routes/badges-show.js.es6
index 7b897f03bf..cc4cf0eaa9 100644
--- a/app/assets/javascripts/discourse/routes/badges-show.js.es6
+++ b/app/assets/javascripts/discourse/routes/badges-show.js.es6
@@ -1,43 +1,41 @@
-import ShowFooter from "discourse/mixins/show-footer";
-
-export default Discourse.Route.extend(ShowFooter, {
+export default Discourse.Route.extend({
actions: {
- didTransition: function() {
+ didTransition() {
this.controllerFor("badges/show")._showFooter();
return true;
}
},
- serialize: function(model) {
- return {id: model.get('id'), slug: model.get('name').replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase()};
+ serialize(model) {
+ return {
+ id: model.get("id"),
+ slug: model.get("name").replace(/[^A-Za-z0-9_]+/g, "-").toLowerCase()
+ };
},
- model: function(params) {
- if (PreloadStore.get('badge')) {
- return PreloadStore.getAndRemove('badge').then(function(json) {
- return Discourse.Badge.createFromJson(json);
- });
+ model(params) {
+ if (PreloadStore.get("badge")) {
+ return PreloadStore.getAndRemove("badge").then(json => Discourse.Badge.createFromJson(json));
} else {
return Discourse.Badge.findById(params.id);
}
},
- afterModel: function(model) {
- var self = this;
- return Discourse.UserBadge.findByBadgeId(model.get('id')).then(function(userBadges) {
- self.userBadges = userBadges;
+ afterModel(model) {
+ return Discourse.UserBadge.findByBadgeId(model.get("id")).then(userBadges => {
+ this.userBadges = userBadges;
});
},
- titleToken: function() {
- var model = this.modelFor('badges.show');
+ titleToken() {
+ const model = this.modelFor("badges.show");
if (model) {
- return model.get('displayName');
+ return model.get("displayName");
}
},
- setupController: function(controller, model) {
- controller.set('model', model);
- controller.set('userBadges', this.userBadges);
+ setupController(controller, model) {
+ controller.set("model", model);
+ controller.set("userBadges", this.userBadges);
}
});
diff --git a/app/assets/javascripts/discourse/routes/build-admin-user-posts-route.js.es6 b/app/assets/javascripts/discourse/routes/build-admin-user-posts-route.js.es6
index 6d79b3b487..1615cdaca8 100644
--- a/app/assets/javascripts/discourse/routes/build-admin-user-posts-route.js.es6
+++ b/app/assets/javascripts/discourse/routes/build-admin-user-posts-route.js.es6
@@ -1,31 +1,29 @@
-import ShowFooter from "discourse/mixins/show-footer";
-
export default function (filter) {
- return Discourse.Route.extend(ShowFooter, {
+ return Discourse.Route.extend({
actions: {
- didTransition: function() {
- this.controllerFor('user').set('indexStream', true);
+ didTransition() {
+ this.controllerFor("user").set("indexStream", true);
this.controllerFor("user-posts")._showFooter();
return true;
}
},
- model: function () {
+ model() {
return this.modelFor("user").get("postsStream");
},
- afterModel: function () {
+ afterModel() {
return this.modelFor("user").get("postsStream").filterBy(filter);
},
- setupController: function(controller, model) {
+ setupController(controller, model) {
// initialize "canLoadMore"
model.set("canLoadMore", model.get("itemsLoaded") === 60);
this.controllerFor("user-posts").set("model", model);
},
- renderTemplate: function() {
+ renderTemplate() {
this.render("user/posts", { into: "user" });
}
});
diff --git a/app/assets/javascripts/discourse/routes/build-user-topic-list-route.js.es6 b/app/assets/javascripts/discourse/routes/build-user-topic-list-route.js.es6
index b5a83808d1..c14174fae7 100644
--- a/app/assets/javascripts/discourse/routes/build-user-topic-list-route.js.es6
+++ b/app/assets/javascripts/discourse/routes/build-user-topic-list-route.js.es6
@@ -1,36 +1,35 @@
import UserTopicListRoute from "discourse/routes/user-topic-list";
-import ShowFooter from "discourse/mixins/show-footer";
// A helper to build a user topic list route
-export default function (viewName, path) {
- return UserTopicListRoute.extend(ShowFooter, {
+export default (viewName, path) => {
+ return UserTopicListRoute.extend({
userActionType: Discourse.UserAction.TYPES.messages_received,
actions: {
- didTransition: function() {
+ didTransition() {
this.controllerFor("user-topics-list")._showFooter();
return true;
}
},
- model: function() {
- return this.store.findFiltered('topicList', {filter: 'topics/' + path + '/' + this.modelFor('user').get('username_lower')});
+ model() {
+ return this.store.findFiltered("topicList", { filter: "topics/" + path + "/" + this.modelFor("user").get("username_lower") });
},
- setupController: function() {
+ setupController() {
this._super.apply(this, arguments);
- this.controllerFor('user-topics-list').setProperties({
+ this.controllerFor("user-topics-list").setProperties({
hideCategory: true,
showParticipants: true
});
- this.controllerFor('user').set('pmView', viewName);
- this.controllerFor('search').set('contextType', 'private_messages');
+ this.controllerFor("user").set("pmView", viewName);
+ this.controllerFor("search").set("contextType", "private_messages");
},
- deactivate: function(){
- this.controllerFor('search').set('contextType', 'user');
+ deactivate() {
+ this.controllerFor("search").set("contextType", "user");
}
});
-}
+};
diff --git a/app/assets/javascripts/discourse/routes/discourse.js.es6 b/app/assets/javascripts/discourse/routes/discourse.js.es6
index 2a26642805..a6bba2cb6a 100644
--- a/app/assets/javascripts/discourse/routes/discourse.js.es6
+++ b/app/assets/javascripts/discourse/routes/discourse.js.es6
@@ -4,7 +4,7 @@ const DiscourseRoute = Ember.Route.extend({
// changes
resfreshQueryWithoutTransition: false,
- refresh: function() {
+ refresh() {
if (!this.refreshQueryWithoutTransition) { return this._super(); }
if (!this.router.router.activeTransition) {
@@ -17,13 +17,13 @@ const DiscourseRoute = Ember.Route.extend({
}
},
- _refreshTitleOnce: function() {
+ _refreshTitleOnce() {
this.send('_collectTitleTokens', []);
},
actions: {
- _collectTitleTokens: function(tokens) {
+ _collectTitleTokens(tokens) {
// If there's a title token method, call it and get the token
if (this.titleToken) {
const t = this.titleToken();
@@ -40,19 +40,19 @@ const DiscourseRoute = Ember.Route.extend({
return true;
},
- refreshTitle: function() {
+ refreshTitle() {
Ember.run.once(this, this._refreshTitleOnce);
}
},
- redirectIfLoginRequired: function() {
+ redirectIfLoginRequired() {
const app = this.controllerFor('application');
if (app.get('loginRequired')) {
this.replaceWith('login');
}
},
- openTopicDraft: function(model){
+ openTopicDraft(model){
// If there's a draft, open the create topic composer
if (model.draft) {
const composer = this.controllerFor('composer');
@@ -67,7 +67,7 @@ const DiscourseRoute = Ember.Route.extend({
}
},
- isPoppedState: function(transition) {
+ isPoppedState(transition) {
return (!transition._discourse_intercepted) && (!!transition.intent.url);
}
});
diff --git a/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6 b/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6
index c46b9b8275..61fd853d10 100644
--- a/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6
+++ b/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6
@@ -1,15 +1,14 @@
-import ShowFooter from 'discourse/mixins/show-footer';
-import showModal from 'discourse/lib/show-modal';
+import showModal from "discourse/lib/show-modal";
import OpenComposer from "discourse/mixins/open-composer";
-Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, ShowFooter, {
+Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
renderTemplate() {
- this.render('navigation/categories', { outlet: 'navigation-bar' });
- this.render('discovery/categories', { outlet: 'list-container' });
+ this.render("navigation/categories", { outlet: "navigation-bar" });
+ this.render("discovery/categories", { outlet: "list-container" });
},
beforeModel() {
- this.controllerFor('navigation/categories').set('filterMode', 'categories');
+ this.controllerFor("navigation/categories").set("filterMode", "categories");
},
model() {
@@ -17,11 +16,11 @@ Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, ShowFo
// if default page is categories
PreloadStore.remove("topic_list");
- return Discourse.CategoryList.list('categories').then(function(list) {
+ return Discourse.CategoryList.list("categories").then(function(list) {
const tracking = Discourse.TopicTrackingState.current();
if (tracking) {
- tracking.sync(list, 'categories');
- tracking.trackIncoming('categories');
+ tracking.sync(list, "categories");
+ tracking.trackIncoming("categories");
}
return list;
});
@@ -29,15 +28,15 @@ Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, ShowFo
titleToken() {
if (Discourse.Utilities.defaultHomepage() === "categories") { return; }
- return I18n.t('filters.categories.title');
+ return I18n.t("filters.categories.title");
},
setupController(controller, model) {
- controller.set('model', model);
+ controller.set("model", model);
// Only show either the Create Category or Create Topic button
- this.controllerFor('navigation/categories').set('canCreateCategory', model.get('can_create_category'));
- this.controllerFor('navigation/categories').set('canCreateTopic', model.get('can_create_topic') && !model.get('can_create_category'));
+ this.controllerFor("navigation/categories").set("canCreateCategory", model.get("can_create_category"));
+ this.controllerFor("navigation/categories").set("canCreateTopic", model.get("can_create_topic") && !model.get("can_create_category"));
this.openTopicDraft(model);
},
@@ -45,20 +44,25 @@ Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, ShowFo
actions: {
createCategory() {
const groups = this.site.groups,
- everyoneName = groups.findBy('id', 0).name;
+ everyoneName = groups.findBy("id", 0).name;
const model = Discourse.Category.create({
- color: 'AB9364', text_color: 'FFFFFF', group_permissions: [{group_name: everyoneName, permission_type: 1}],
+ color: "AB9364", text_color: "FFFFFF", group_permissions: [{group_name: everyoneName, permission_type: 1}],
available_groups: groups.map(g => g.name),
allow_badges: true
});
- showModal('editCategory', { model });
- this.controllerFor('editCategory').set('selectedTab', 'general');
+ showModal("editCategory", { model });
+ this.controllerFor("editCategory").set("selectedTab", "general");
},
createTopic() {
- this.openComposer(this.controllerFor('discovery/categories'));
+ this.openComposer(this.controllerFor("discovery/categories"));
+ },
+
+ didTransition() {
+ this.controllerFor("application").set("showFooter", true);
+ return true;
}
}
});
diff --git a/app/assets/javascripts/discourse/routes/discovery.js.es6 b/app/assets/javascripts/discourse/routes/discovery.js.es6
index e5be7da1e3..98d182c42a 100644
--- a/app/assets/javascripts/discourse/routes/discovery.js.es6
+++ b/app/assets/javascripts/discourse/routes/discovery.js.es6
@@ -2,14 +2,15 @@
The parent route for all discovery routes.
Handles the logic for showing the loading spinners.
**/
-import ShowFooter from "discourse/mixins/show-footer";
import OpenComposer from "discourse/mixins/open-composer";
-import { scrollTop } from 'discourse/mixins/scroll-top';
+import { scrollTop } from "discourse/mixins/scroll-top";
-const DiscoveryRoute = Discourse.Route.extend(OpenComposer, ShowFooter, {
- redirect: function() { return this.redirectIfLoginRequired(); },
+const DiscoveryRoute = Discourse.Route.extend(OpenComposer, {
+ redirect() {
+ return this.redirectIfLoginRequired();
+ },
- beforeModel: function(transition) {
+ beforeModel(transition) {
if (transition.intent.url === "/" &&
transition.targetName.indexOf("discovery.top") === -1 &&
Discourse.User.currentProp("should_be_redirected_to_top")) {
@@ -19,31 +20,31 @@ const DiscoveryRoute = Discourse.Route.extend(OpenComposer, ShowFooter, {
},
actions: {
- loading: function() {
- this.controllerFor('discovery').set("loading", true);
+ loading() {
+ this.controllerFor("discovery").set("loading", true);
return true;
},
- loadingComplete: function() {
- this.controllerFor('discovery').set('loading', false);
- if (!this.session.get('topicListScrollPosition')) {
+ loadingComplete() {
+ this.controllerFor("discovery").set("loading", false);
+ if (!this.session.get("topicListScrollPosition")) {
scrollTop();
}
},
- didTransition: function() {
+ didTransition() {
this.controllerFor("discovery")._showFooter();
- this.send('loadingComplete');
+ this.send("loadingComplete");
return true;
},
// clear a pinned topic
- clearPin: function(topic) {
+ clearPin(topic) {
topic.clearPin();
},
- createTopic: function() {
- this.openComposer(this.controllerFor('discovery/topics'));
+ createTopic() {
+ this.openComposer(this.controllerFor("discovery/topics"));
}
}
diff --git a/app/assets/javascripts/discourse/routes/exception.js.es6 b/app/assets/javascripts/discourse/routes/exception.js.es6
index a5c5fab878..2c911a989d 100644
--- a/app/assets/javascripts/discourse/routes/exception.js.es6
+++ b/app/assets/javascripts/discourse/routes/exception.js.es6
@@ -1,7 +1,10 @@
-import ShowFooter from "discourse/mixins/show-footer";
+export default Discourse.Route.extend({
+ serialize() { return ""; },
-export default Discourse.Route.extend(ShowFooter, {
- serialize: function() {
- return "";
+ actions: {
+ didTransition() {
+ this.controllerFor("application").set("showFooter", true);
+ return true;
+ }
}
});
diff --git a/app/assets/javascripts/discourse/routes/full-page-search.js.es6 b/app/assets/javascripts/discourse/routes/full-page-search.js.es6
index b092136ee5..482ebf1fc5 100644
--- a/app/assets/javascripts/discourse/routes/full-page-search.js.es6
+++ b/app/assets/javascripts/discourse/routes/full-page-search.js.es6
@@ -1,18 +1,23 @@
-import { translateResults } from 'discourse/lib/search-for-term';
+import { translateResults } from "discourse/lib/search-for-term";
export default Discourse.Route.extend({
- queryParams: {
- q: {
- }
- },
- model: function(params) {
+ queryParams: { q: {} },
+
+ model(params) {
return PreloadStore.getAndRemove("search", function() {
- return Discourse.ajax('/search', {data: {q: params.q}});
- }).then(function(results){
- var model = translateResults(results) || {};
+ return Discourse.ajax("/search", { data: { q: params.q } });
+ }).then(results => {
+ const model = translateResults(results) || {};
model.q = params.q;
return model;
});
+ },
+
+ actions: {
+ didTransition() {
+ this.controllerFor("full-page-search")._showFooter();
+ return true;
+ }
}
});
diff --git a/app/assets/javascripts/discourse/routes/group-index.js.es6 b/app/assets/javascripts/discourse/routes/group-index.js.es6
index 63a1a23f76..89dec1edd2 100644
--- a/app/assets/javascripts/discourse/routes/group-index.js.es6
+++ b/app/assets/javascripts/discourse/routes/group-index.js.es6
@@ -1,18 +1,14 @@
-import ShowFooter from "discourse/mixins/show-footer";
-
-export default Discourse.Route.extend(ShowFooter, {
+export default Discourse.Route.extend({
actions: {
- didTransition: function() {
- return true;
- }
+ didTransition() { return true; }
},
- model: function() {
- return this.modelFor('group').findPosts();
+ model() {
+ return this.modelFor("group").findPosts();
},
- setupController: function(controller, model) {
- controller.set('model', model);
- this.controllerFor('group').set('showing', 'index');
+ setupController(controller, model) {
+ controller.set("model", model);
+ this.controllerFor("group").set("showing", "index");
}
});
diff --git a/app/assets/javascripts/discourse/routes/group-members.js.es6 b/app/assets/javascripts/discourse/routes/group-members.js.es6
index 4713495d8f..22e328cacf 100644
--- a/app/assets/javascripts/discourse/routes/group-members.js.es6
+++ b/app/assets/javascripts/discourse/routes/group-members.js.es6
@@ -1,12 +1,10 @@
-import ShowFooter from "discourse/mixins/show-footer";
-
-export default Discourse.Route.extend(ShowFooter, {
+export default Discourse.Route.extend({
model() {
- return this.modelFor('group');
+ return this.modelFor("group");
},
setupController(controller, model) {
- this.controllerFor('group').set('showing', 'members');
+ this.controllerFor("group").set("showing", "members");
controller.set("model", model);
model.findMembers();
}
diff --git a/app/assets/javascripts/discourse/routes/preferences.js.es6 b/app/assets/javascripts/discourse/routes/preferences.js.es6
index 67fd1b923e..d748689f40 100644
--- a/app/assets/javascripts/discourse/routes/preferences.js.es6
+++ b/app/assets/javascripts/discourse/routes/preferences.js.es6
@@ -1,8 +1,7 @@
-import ShowFooter from "discourse/mixins/show-footer";
import RestrictedUserRoute from "discourse/routes/restricted-user";
import showModal from 'discourse/lib/show-modal';
-export default RestrictedUserRoute.extend(ShowFooter, {
+export default RestrictedUserRoute.extend({
model() {
return this.modelFor('user');
},
diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6
index 63762c7b55..7d5f253341 100644
--- a/app/assets/javascripts/discourse/routes/topic.js.es6
+++ b/app/assets/javascripts/discourse/routes/topic.js.es6
@@ -4,10 +4,9 @@ let isTransitioning = false,
const SCROLL_DELAY = 500;
-import ShowFooter from "discourse/mixins/show-footer";
import showModal from 'discourse/lib/show-modal';
-const TopicRoute = Discourse.Route.extend(ShowFooter, {
+const TopicRoute = Discourse.Route.extend({
redirect() { return this.redirectIfLoginRequired(); },
queryParams: {
diff --git a/app/assets/javascripts/discourse/routes/user-activity-index.js.es6 b/app/assets/javascripts/discourse/routes/user-activity-index.js.es6
index 3f5ae1272a..926ba744e4 100644
--- a/app/assets/javascripts/discourse/routes/user-activity-index.js.es6
+++ b/app/assets/javascripts/discourse/routes/user-activity-index.js.es6
@@ -4,9 +4,9 @@ export default UserActivityStreamRoute.extend({
userActionType: undefined,
actions: {
- didTransition: function() {
+ didTransition() {
this._super();
- this.controllerFor('user').set('indexStream', true);
+ this.controllerFor("user").set("indexStream", true);
return true;
}
}
diff --git a/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6 b/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6
index bec825f849..7447d71217 100644
--- a/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6
+++ b/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6
@@ -1,39 +1,38 @@
-import ShowFooter from "discourse/mixins/show-footer";
import ViewingActionType from "discourse/mixins/viewing-action-type";
-export default Discourse.Route.extend(ShowFooter, ViewingActionType, {
- model: function() {
- return this.modelFor('user').get('stream');
+export default Discourse.Route.extend(ViewingActionType, {
+ model() {
+ return this.modelFor("user").get("stream");
},
- afterModel: function() {
- return this.modelFor('user').get('stream').filterBy(this.get('userActionType'));
+ afterModel() {
+ return this.modelFor("user").get("stream").filterBy(this.get("userActionType"));
},
- renderTemplate: function() {
- this.render('user_stream');
+ renderTemplate() {
+ this.render("user_stream");
},
- setupController: function(controller, model) {
- controller.set('model', model);
- this.viewingActionType(this.get('userActionType'));
+ setupController(controller, model) {
+ controller.set("model", model);
+ this.viewingActionType(this.get("userActionType"));
},
actions: {
- didTransition: function() {
+ didTransition() {
this.controllerFor("user-activity")._showFooter();
return true;
},
- removeBookmark: function(userAction) {
- var user = this.modelFor('user');
- Discourse.Post.updateBookmark(userAction.get('post_id'), false)
+ removeBookmark(userAction) {
+ var user = this.modelFor("user");
+ Discourse.Post.updateBookmark(userAction.get("post_id"), false)
.then(function() {
// remove the user action from the stream
- user.get('stream').remove(userAction);
+ user.get("stream").remove(userAction);
// update the counts
- user.get('stats').forEach(function (stat) {
+ user.get("stats").forEach(function (stat) {
if (stat.get("action_type") === userAction.action_type) {
stat.decrementProperty("count");
}
diff --git a/app/assets/javascripts/discourse/routes/user-activity.js.es6 b/app/assets/javascripts/discourse/routes/user-activity.js.es6
index ca4bd71feb..e654ac9b2c 100644
--- a/app/assets/javascripts/discourse/routes/user-activity.js.es6
+++ b/app/assets/javascripts/discourse/routes/user-activity.js.es6
@@ -1,20 +1,20 @@
export default Discourse.Route.extend({
- model: function() {
- return this.modelFor('user');
+ model() {
+ return this.modelFor("user");
},
- setupController: function(controller, user) {
- this.controllerFor('user-activity').set('model', user);
+ setupController(controller, user) {
+ this.controllerFor("user-activity").set("model", user);
// Bring up a draft
- const composerController = this.controllerFor('composer');
- controller.set('model', user);
+ const composerController = this.controllerFor("composer");
+ controller.set("model", user);
if (this.currentUser) {
- Discourse.Draft.get('new_private_message').then(function(data) {
+ Discourse.Draft.get("new_private_message").then(function(data) {
if (data.draft) {
composerController.open({
draft: data.draft,
- draftKey: 'new_private_message',
+ draftKey: "new_private_message",
ignoreIfChanged: true,
draftSequence: data.draft_sequence
});
diff --git a/app/assets/javascripts/discourse/routes/user-badges.js.es6 b/app/assets/javascripts/discourse/routes/user-badges.js.es6
index d3b39a3b93..fcd099d765 100644
--- a/app/assets/javascripts/discourse/routes/user-badges.js.es6
+++ b/app/assets/javascripts/discourse/routes/user-badges.js.es6
@@ -1,17 +1,23 @@
-import ShowFooter from "discourse/mixins/show-footer";
import ViewingActionType from "discourse/mixins/viewing-action-type";
-export default Discourse.Route.extend(ShowFooter, ViewingActionType, {
- model: function() {
- return Discourse.UserBadge.findByUsername(this.modelFor('user').get('username_lower'), {grouped: true});
+export default Discourse.Route.extend(ViewingActionType, {
+ model() {
+ return Discourse.UserBadge.findByUsername(this.modelFor("user").get("username_lower"), { grouped: true });
},
- setupController: function(controller, model) {
+ setupController(controller, model) {
this.viewingActionType(-1);
- controller.set('model', model);
+ controller.set("model", model);
},
- renderTemplate: function() {
- this.render('user/badges', {into: 'user'});
+ renderTemplate() {
+ this.render("user/badges", {into: "user"});
+ },
+
+ actions: {
+ didTransition() {
+ this.controllerFor("application").set("showFooter", true);
+ return true;
+ }
}
});
diff --git a/app/assets/javascripts/discourse/routes/user-invited-show.js.es6 b/app/assets/javascripts/discourse/routes/user-invited-show.js.es6
index 6c42105dd6..21317f3090 100644
--- a/app/assets/javascripts/discourse/routes/user-invited-show.js.es6
+++ b/app/assets/javascripts/discourse/routes/user-invited-show.js.es6
@@ -1,33 +1,32 @@
-import ShowFooter from 'discourse/mixins/show-footer';
-import showModal from 'discourse/lib/show-modal';
+import showModal from "discourse/lib/show-modal";
-export default Discourse.Route.extend(ShowFooter, {
+export default Discourse.Route.extend({
- model: function(params) {
+ model(params) {
this.inviteFilter = params.filter;
- return Discourse.Invite.findInvitedBy(this.modelFor('user'), params.filter);
+ return Discourse.Invite.findInvitedBy(this.modelFor("user"), params.filter);
},
- afterModel: function(model) {
+ afterModel(model) {
if (!model.can_see_invite_details) {
- this.replaceWith('userInvited.show', 'redeemed');
+ this.replaceWith("userInvited.show", "redeemed");
}
},
setupController(controller, model) {
controller.setProperties({
model: model,
- user: this.controllerFor('user').get('model'),
+ user: this.controllerFor("user").get("model"),
filter: this.inviteFilter,
- searchTerm: '',
+ searchTerm: "",
totalInvites: model.invites.length
});
},
actions: {
showInvite() {
- showModal('invite', { model: this.currentUser });
- this.controllerFor('invite').reset();
+ showModal("invite", { model: this.currentUser });
+ this.controllerFor("invite").reset();
},
uploadSuccess(filename) {
diff --git a/app/assets/javascripts/discourse/routes/user-notifications.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications.js.es6
index a90c131af2..7c2384db01 100644
--- a/app/assets/javascripts/discourse/routes/user-notifications.js.es6
+++ b/app/assets/javascripts/discourse/routes/user-notifications.js.es6
@@ -1,7 +1,6 @@
-import ShowFooter from "discourse/mixins/show-footer";
import ViewingActionType from "discourse/mixins/viewing-action-type";
-export default Discourse.Route.extend(ShowFooter, ViewingActionType, {
+export default Discourse.Route.extend(ViewingActionType, {
actions: {
didTransition() {
this.controllerFor("user-notifications")._showFooter();
@@ -10,13 +9,12 @@ export default Discourse.Route.extend(ShowFooter, ViewingActionType, {
},
model() {
- var user = this.modelFor('user');
- return this.store.find('notification', {username: user.get('username')});
+ return this.store.find("notification", { username: this.modelFor("user").get("username") });
},
setupController(controller, model) {
- controller.set('model', model);
- controller.set('user', this.modelFor('user'));
+ controller.set("model", model);
+ controller.set("user", this.modelFor("user"));
this.viewingActionType(-1);
}
});
diff --git a/app/assets/javascripts/discourse/routes/users.js.es6 b/app/assets/javascripts/discourse/routes/users.js.es6
index e9d516543f..beb25276fc 100644
--- a/app/assets/javascripts/discourse/routes/users.js.es6
+++ b/app/assets/javascripts/discourse/routes/users.js.es6
@@ -9,16 +9,16 @@ export default Discourse.Route.extend({
refreshQueryWithoutTransition: true,
titleToken() {
- return I18n.t('directory.title');
+ return I18n.t("directory.title");
},
resetController(controller, isExiting) {
if (isExiting) {
controller.setProperties({
- period: 'weekly',
- order: 'likes_received',
+ period: "weekly",
+ order: "likes_received",
asc: null,
- name: ''
+ name: ""
});
}
},
@@ -26,11 +26,18 @@ export default Discourse.Route.extend({
model(params) {
// If we refresh via `refreshModel` set the old model to loading
this._params = params;
- return this.store.find('directoryItem', params);
+ return this.store.find("directoryItem", params);
},
setupController(controller, model) {
const params = this._params;
controller.setProperties({ model, period: params.period, nameInput: params.name });
+ },
+
+ actions: {
+ didTransition() {
+ this.controllerFor("users")._showFooter();
+ return true;
+ }
}
});
diff --git a/app/assets/javascripts/discourse/templates/application.hbs b/app/assets/javascripts/discourse/templates/application.hbs
index 23822e0f40..7eb87f79e3 100644
--- a/app/assets/javascripts/discourse/templates/application.hbs
+++ b/app/assets/javascripts/discourse/templates/application.hbs
@@ -1,6 +1,10 @@
{{render "header"}}
-
+
+
+ {{custom-html "top"}}
+ {{global-notice}}
+
{{outlet}}
{{render "user-card"}}
diff --git a/app/assets/javascripts/discourse/templates/components/badge-button.hbs b/app/assets/javascripts/discourse/templates/components/badge-button.hbs
index 7c0469791e..4886147389 100644
--- a/app/assets/javascripts/discourse/templates/components/badge-button.hbs
+++ b/app/assets/javascripts/discourse/templates/components/badge-button.hbs
@@ -1,3 +1,3 @@
{{icon-or-image badge.icon}}
-{{badge.displayName}}
+{{badge.displayName}}
{{yield}}
diff --git a/app/assets/javascripts/discourse/templates/components/desktop-notification-config.hbs b/app/assets/javascripts/discourse/templates/components/desktop-notification-config.hbs
new file mode 100644
index 0000000000..3bc0db1c51
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/desktop-notification-config.hbs
@@ -0,0 +1,20 @@
+
+{{#if isNotSupported}}
+ {{d-button icon="bell-slash" label="user.desktop_notifications.not_supported" disabled="true"}}
+{{/if}}
+{{#if isDefaultPermission}}
+ {{d-button icon="bell-slash" label="user.desktop_notifications.perm_default" action="requestPermission"}}
+{{/if}}
+{{#if isDeniedPermission}}
+ {{d-button icon="bell-slash" label="user.desktop_notifications.perm_denied_btn" action="recheckPermission"}}
+ {{i18n "user.desktop_notifications.perm_denied_expl"}}
+{{/if}}
+{{#if isGrantedPermission}}
+ {{#if isEnabled}}
+ {{d-button icon="bell-slash-o" label="user.desktop_notifications.disable" action="turnoff"}}
+ {{i18n "user.desktop_notifications.currently_enabled"}}
+ {{else}}
+ {{d-button icon="bell-o" label="user.desktop_notifications.enable" action="turnon"}}
+ {{i18n "user.desktop_notifications.currently_disabled"}}
+ {{/if}}
+{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/search-result-topic.hbs b/app/assets/javascripts/discourse/templates/components/search-result-topic.hbs
index c092bcaa6e..01d100b718 100644
--- a/app/assets/javascripts/discourse/templates/components/search-result-topic.hbs
+++ b/app/assets/javascripts/discourse/templates/components/search-result-topic.hbs
@@ -2,7 +2,7 @@
- {{topic-status topic=result.topic disableActions=true}}{{unbound result.topic.title}}{{category-badge result.topic.category}}
+ {{topic-status topic=result.topic disableActions=true}}{{unbound result.topic.title}}{{category-badge result.topic.category}}{{plugin-outlet "search-category"}}
{{#unless site.mobileView}}
diff --git a/app/assets/javascripts/discourse/templates/components/small-action.hbs b/app/assets/javascripts/discourse/templates/components/small-action.hbs
index b05c658088..091f0e07df 100644
--- a/app/assets/javascripts/discourse/templates/components/small-action.hbs
+++ b/app/assets/javascripts/discourse/templates/components/small-action.hbs
@@ -11,5 +11,8 @@
{{avatar post imageSize="small"}}
{{/if}}
- {{{description}}}
+ {{description}}
+ {{#if post.cooked}}
+
+ {{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/stream-item.hbs b/app/assets/javascripts/discourse/templates/components/stream-item.hbs
new file mode 100644
index 0000000000..c84082519b
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/stream-item.hbs
@@ -0,0 +1,31 @@
+
+ {{avatar item imageSize="large" extraClasses="actor" ignoreTitle="true"}}
+ {{format-date item.created_at}}
+ {{topic-status topic=item disableActions=true}}
+
+ {{{item.title}}}
+
+ {{category-link item.category}}
+
+
+{{#if actionDescription}}
+ {{actionDescription}}
+{{/if}}
+
+{{{item.excerpt}}}
+
+{{#each item.children as |child|}}
+
+
+ {{#each child.items as |grandChild|}}
+ {{#if grandChild.removableBookmark}}
+
+ {{else}}
+ {{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}
+ {{#if grandChild.edit_reason}} — {{grandChild.edit_reason}}{{/if}}
+ {{/if}}
+ {{/each}}
+
+{{/each}}
diff --git a/app/assets/javascripts/discourse/templates/discovery.hbs b/app/assets/javascripts/discourse/templates/discovery.hbs
index 195db18b2e..1e4548bbe2 100644
--- a/app/assets/javascripts/discourse/templates/discovery.hbs
+++ b/app/assets/javascripts/discourse/templates/discovery.hbs
@@ -1,10 +1,8 @@
-
- {{custom-html "top"}}
- {{global-notice}}
+
{{discourse-banner user=currentUser banner=site.banner}}
-
+
{{outlet "navigation-bar"}}
@@ -12,17 +10,17 @@
{{conditional-loading-spinner condition=loading}}
-
+
-
+
{{outlet "header-list-container"}}
-
+
{{plugin-outlet "discovery-list-container-top"}}
{{outlet "list-container"}}
diff --git a/app/assets/javascripts/discourse/templates/full-page-search.hbs b/app/assets/javascripts/discourse/templates/full-page-search.hbs
index 848215c73e..b04d1e5937 100644
--- a/app/assets/javascripts/discourse/templates/full-page-search.hbs
+++ b/app/assets/javascripts/discourse/templates/full-page-search.hbs
@@ -1,45 +1,49 @@
{{input type="text" value=searchTerm class="input-xxlarge search no-blur" action="search"}}
-
+ {{d-button action="search" icon="search" class="btn-primary"}}
{{#conditional-loading-spinner condition=loading}}
-{{#unless model.posts}}
-{{i18n "search.no_results"}} {{i18n "search.search_help"}}
-
-{{/unless}}
+ {{#unless model.posts}}
+
+ {{i18n "search.no_results"}} {{i18n "search.search_help"}}
+
+ {{/unless}}
-{{#each model.posts as |result|}}
-
-
- {{avatar result imageSize="tiny"}}
-
- {{topic-status topic=result.topic disableActions=true}}{{unbound result.topic.title}}
- {{category-link result.topic.category}}
-
-
-
- {{format-age result.created_at}}
- {{#if result.blurb}}
- -
- {{/if}}
-
- {{#if result.blurb}}
- {{#highlight-text highlight=controller.q}}
- {{{unbound result.blurb}}}
- {{/highlight-text}}
- {{/if}}
-
-
-{{/each}}
+ {{#each model.posts as |result|}}
+
+
+ {{avatar result imageSize="tiny"}}
+
+ {{topic-status topic=result.topic disableActions=true}}{{unbound result.topic.title}}
+
+
+ {{category-link result.topic.category}}
+ {{plugin-outlet "full-page-search-category"}}
+
+
+
+
+ {{format-age result.created_at}}
+ {{#if result.blurb}}
+ -
+ {{/if}}
+
+ {{#if result.blurb}}
+ {{#highlight-text highlight=controller.q}}
+ {{{unbound result.blurb}}}
+ {{/highlight-text}}
+ {{/if}}
+
+
+ {{/each}}
-{{#if model.posts}}
-
- {{i18n "search.no_more_results"}}
- {{i18n "search.search_help"}}
-
-{{/if}}
+ {{#if model.posts}}
+
+ {{i18n "search.no_more_results"}}
+ {{i18n "search.search_help"}}
+
+ {{/if}}
{{/conditional-loading-spinner}}
-
diff --git a/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs b/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs
index 92f0bd68e9..26c958c4ec 100644
--- a/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs
+++ b/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs
@@ -10,6 +10,7 @@
{{#if controller.showTopicPostBadges}}
{{raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl}}
{{/if}}
+ {{plugin-outlet "topic-list-tags"}}
{{#if expandPinned}}
{{raw "list/topic-excerpt" topic=topic}}
{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/modal/merge-topic.hbs b/app/assets/javascripts/discourse/templates/modal/merge-topic.hbs
index a05ac14f22..e4bf364fc2 100644
--- a/app/assets/javascripts/discourse/templates/modal/merge-topic.hbs
+++ b/app/assets/javascripts/discourse/templates/modal/merge-topic.hbs
@@ -1,10 +1,4 @@
- {{#if error}}
-
-
-
- {{/if}}
-
{{{i18n 'topic.merge_topic.instructions' count=selectedPostsCount}}}
diff --git a/app/assets/javascripts/discourse/templates/modal/split_topic.hbs b/app/assets/javascripts/discourse/templates/modal/split-topic.hbs
similarity index 59%
rename from app/assets/javascripts/discourse/templates/modal/split_topic.hbs
rename to app/assets/javascripts/discourse/templates/modal/split-topic.hbs
index ff72aab89c..fe80f88174 100644
--- a/app/assets/javascripts/discourse/templates/modal/split_topic.hbs
+++ b/app/assets/javascripts/discourse/templates/modal/split-topic.hbs
@@ -1,10 +1,4 @@
- {{#if error}}
-
-
-
- {{/if}}
-
{{{i18n 'topic.split_topic.instructions' count=selectedPostsCount}}}
diff --git a/app/assets/javascripts/discourse/templates/queued-posts.hbs b/app/assets/javascripts/discourse/templates/queued-posts.hbs
index 400937caf5..5fc07e042b 100644
--- a/app/assets/javascripts/discourse/templates/queued-posts.hbs
+++ b/app/assets/javascripts/discourse/templates/queued-posts.hbs
@@ -6,7 +6,6 @@
{{#user-link user=ctrl.post.user}}
{{avatar ctrl.post.user imageSize="large"}}
{{/user-link}}
-
@@ -14,6 +13,9 @@
{{#user-link user=ctrl.post.user}}
{{ctrl.post.user.username}}
{{/user-link}}
+ {{#if ctrl.post.user.blocked}}
+
+ {{/if}}
diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs
index 5267a9febc..c3fd2fdc48 100644
--- a/app/assets/javascripts/discourse/templates/topic.hbs
+++ b/app/assets/javascripts/discourse/templates/topic.hbs
@@ -1,25 +1,23 @@
-
- {{custom-html "top"}}
- {{global-notice}}
- {{#if model}}
+{{#if model}}
+
{{discourse-banner user=currentUser banner=site.banner overlay=view.hasScrolled hide=model.errorLoading}}
- {{/if}}
-
+
+{{/if}}
{{plugin-outlet "topic-above-post-stream"}}
{{#if model.postStream.loaded}}
{{#if model.postStream.firstPostPresent}}
-
-
+
+
{{#if editingTopic}}
{{#if model.isPrivateMessage}}
- {{autofocus-text-field id='edit-title' value=buffered.title maxLength=maxTitleLength}}
+ {{autofocus-text-field id="edit-title" value=buffered.title maxLength=maxTitleLength}}
{{else}}
- {{autofocus-text-field id='edit-title' value=buffered.title maxLength=maxTitleLength}}
+ {{autofocus-text-field id="edit-title" value=buffered.title maxLength=maxTitleLength}}
{{category-chooser valueAttribute="id" value=buffered.category_id source=buffered.category_id}}
{{/if}}
@@ -36,13 +34,13 @@
{{#if model.details.loaded}}
{{topic-status topic=model}}
-
+
{{{model.fancyTitle}}}
{{/if}}
{{#if model.details.can_edit}}
- {{fa-icon "pencil"}}
+ {{fa-icon "pencil"}}
{{/if}}
@@ -61,10 +59,10 @@
{{view "selected-posts"}}
-
-
+
+
- {{render 'topic-progress'}}
+ {{render "topic-progress"}}
{{conditional-loading-spinner condition=model.postStream.loadingAbove}}
@@ -83,21 +81,21 @@
{{conditional-loading-spinner condition=model.postStream.loadingBelow}}
-
+
{{#conditional-loading-spinner condition=model.postStream.loadingFilter}}
{{#if loadedAllPosts}}
- {{view 'topic-closing' topic=model}}
- {{view 'topic-footer-buttons' topic=model}}
+ {{view "topic-closing" topic=model}}
+ {{view "topic-footer-buttons" topic=model}}
{{#if model.pending_posts_count}}
-
+
{{{i18n "queue.has_pending_posts" count=model.pending_posts_count}}}
- {{#link-to 'queued-posts'}}
- {{fa-icon 'check'}}
- {{i18n 'queue.view_pending'}}
+ {{#link-to "queued-posts"}}
+ {{fa-icon "check"}}
+ {{i18n "queue.view_pending"}}
{{/link-to}}
{{/if}}
@@ -105,9 +103,9 @@
{{plugin-outlet "topic-above-suggested"}}
{{#if model.details.suggested_topics.length}}
-
- {{i18n 'suggested_topics.title'}}
-
+
+ {{i18n "suggested_topics.title"}}
+
{{basic-topic-list topics=model.details.suggested_topics postsAction="showTopicEntrance"}}
{{{view.browseMoreMessage}}}
@@ -122,10 +120,10 @@
{{else}}
-
+
{{#conditional-loading-spinner condition=noErrorYet}}
{{#if model.notFoundHtml}}
- {{{model.notFoundHtml}}}
+ {{{model.notFoundHtml}}}
{{else}}
{{model.message}}
diff --git a/app/assets/javascripts/discourse/templates/user-invited-show.hbs b/app/assets/javascripts/discourse/templates/user-invited-show.hbs
index 29c5f62bf4..32ad817159 100644
--- a/app/assets/javascripts/discourse/templates/user-invited-show.hbs
+++ b/app/assets/javascripts/discourse/templates/user-invited-show.hbs
@@ -76,7 +76,7 @@
{{#if invite.reinvited}}
{{i18n 'user.invited.reinvited'}}
{{else}}
- {{d-button icon="user-plus" action="reinvite" actionParam=invite class="btn" label="user.invited.reinvite"}}
+ {{d-button icon="refresh" action="reinvite" actionParam=invite class="btn" label="user.invited.reinvite"}}
{{/if}}
{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs
index 9a29f36a87..44d59c94c7 100644
--- a/app/assets/javascripts/discourse/templates/user/preferences.hbs
+++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs
@@ -189,6 +189,12 @@
+
+
+ {{desktop-notification-config}}
+ {{i18n 'user.desktop_notifications.each_browser_note'}}
+
+
diff --git a/app/assets/javascripts/discourse/templates/user/stream.hbs b/app/assets/javascripts/discourse/templates/user/stream.hbs
index 96e96c8376..c7b3114470 100644
--- a/app/assets/javascripts/discourse/templates/user/stream.hbs
+++ b/app/assets/javascripts/discourse/templates/user/stream.hbs
@@ -1,29 +1,3 @@
-{{#each item in model.content}}
-
-
- {{avatar item imageSize="large" extraClasses="actor" ignoreTitle="true"}}
- {{format-date item.created_at}}
- {{topic-status topic=item disableActions=true}}
-
- {{{unbound item.title}}}
-
- {{category-link item.category}}
-
- {{{unbound item.excerpt}}}
- {{#each child in item.children}}
-
-
- {{#each grandChild in child.items}}
- {{#if grandChild.removableBookmark}}
-
- {{else}}
- {{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}
- {{#if grandChild.edit_reason}} — {{unbound grandChild.edit_reason}}{{/if}}
- {{/if}}
- {{/each}}
-
- {{/each}}
-
+{{#each model.content as |item|}}
+ {{stream-item item=item removeBookmark="removeBookmark"}}
{{/each}}
diff --git a/app/assets/javascripts/discourse/templates/user/user.hbs b/app/assets/javascripts/discourse/templates/user/user.hbs
index f042fa2635..a21b59dd92 100644
--- a/app/assets/javascripts/discourse/templates/user/user.hbs
+++ b/app/assets/javascripts/discourse/templates/user/user.hbs
@@ -1,8 +1,3 @@
-
- {{custom-html "top"}}
- {{global-notice}}
-
-
diff --git a/app/assets/javascripts/discourse/views/composer.js.es6 b/app/assets/javascripts/discourse/views/composer.js.es6
index 36a4777933..6c3047ba8f 100644
--- a/app/assets/javascripts/discourse/views/composer.js.es6
+++ b/app/assets/javascripts/discourse/views/composer.js.es6
@@ -85,6 +85,8 @@ const ComposerView = Discourse.View.extend(Ember.Evented, {
const controller = this.get('controller');
controller.checkReplyLength();
+ this.get('controller.model').typing();
+
const lastKeyUp = new Date();
this.set('lastKeyUp', lastKeyUp);
@@ -258,9 +260,9 @@ const ComposerView = Discourse.View.extend(Ember.Evented, {
this.editor = editor = Discourse.Markdown.createEditor({
containerElement: this.element,
- lookupAvatarByPostNumber(postNumber) {
+ lookupAvatarByPostNumber(postNumber, topicId) {
const posts = self.get('controller.controllers.topic.model.postStream.posts');
- if (posts) {
+ if (posts && topicId === self.get('controller.controllers.topic.model.id')) {
const quotedPost = posts.findProperty("post_number", postNumber);
if (quotedPost) {
const username = quotedPost.get('username'),
@@ -543,8 +545,11 @@ const ComposerView = Discourse.View.extend(Ember.Evented, {
this.$('.wmd-preview').off('click.preview');
+ const self = this;
+
Em.run.next(() => {
- $('#main-outlet').css('padding-bottom', 0);
+ const sizePx = self.get('composeState') === Discourse.Composer.CLOSED ? 0 : $('#reply-control').height();
+ $('#main-outlet').css('padding-bottom', sizePx);
// need to wait a bit for the "slide down" transition of the composer
Em.run.later(() => {
this.appEvents.trigger("composer:closed");
diff --git a/app/assets/javascripts/discourse/views/full-page-search.js.es6 b/app/assets/javascripts/discourse/views/full-page-search.js.es6
index b05aa16848..98225e4f79 100644
--- a/app/assets/javascripts/discourse/views/full-page-search.js.es6
+++ b/app/assets/javascripts/discourse/views/full-page-search.js.es6
@@ -1,5 +1,3 @@
-import ScrollTop from 'discourse/mixins/scroll-top';
+import ScrollTop from "discourse/mixins/scroll-top";
-export default Ember.View.extend(ScrollTop, {
-
-});
+export default Ember.View.extend(ScrollTop, {});
diff --git a/app/assets/javascripts/discourse/views/split-topic.js.es6 b/app/assets/javascripts/discourse/views/split-topic.js.es6
index 5ee0d76554..9291495adc 100644
--- a/app/assets/javascripts/discourse/views/split-topic.js.es6
+++ b/app/assets/javascripts/discourse/views/split-topic.js.es6
@@ -2,6 +2,6 @@ import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
import ModalBodyView from "discourse/views/modal-body";
export default ModalBodyView.extend(SelectedPostsCount, {
- templateName: 'modal/split_topic',
+ templateName: 'modal/split-topic',
title: I18n.t('topic.split_topic.title')
});
diff --git a/app/assets/javascripts/discourse/views/user-activity-stream.js.es6 b/app/assets/javascripts/discourse/views/user-activity-stream.js.es6
new file mode 100644
index 0000000000..86fbaefd8f
--- /dev/null
+++ b/app/assets/javascripts/discourse/views/user-activity-stream.js.es6
@@ -0,0 +1,27 @@
+import LoadMore from "discourse/mixins/load-more";
+
+export default Ember.View.extend(LoadMore, {
+ loading: false,
+ eyelineSelector: '.user-stream .item',
+ classNames: ['user-stream'],
+
+ _scrollTopOnModelChange: function() {
+ Em.run.schedule('afterRender', function() {
+ $(document).scrollTop(0);
+ });
+ }.observes('controller.model.user.id'),
+
+ actions: {
+ loadMore() {
+ const self = this;
+ if (this.get('loading')) { return; }
+
+ this.set('loading', true);
+ const stream = this.get('controller.model');
+ stream.findItems().then(function() {
+ self.set('loading', false);
+ self.get('eyeline').flushRest();
+ });
+ }
+ }
+});
diff --git a/app/assets/javascripts/discourse/views/user-stream.js.es6 b/app/assets/javascripts/discourse/views/user-stream.js.es6
index 367c089ed0..86fbaefd8f 100644
--- a/app/assets/javascripts/discourse/views/user-stream.js.es6
+++ b/app/assets/javascripts/discourse/views/user-stream.js.es6
@@ -12,12 +12,12 @@ export default Ember.View.extend(LoadMore, {
}.observes('controller.model.user.id'),
actions: {
- loadMore: function() {
- var self = this;
+ loadMore() {
+ const self = this;
if (this.get('loading')) { return; }
this.set('loading', true);
- var stream = this.get('controller.model');
+ const stream = this.get('controller.model');
stream.findItems().then(function() {
self.set('loading', false);
self.get('eyeline').flushRest();
diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js
index 668234d4fa..8338d7921f 100644
--- a/app/assets/javascripts/main_include.js
+++ b/app/assets/javascripts/main_include.js
@@ -28,6 +28,8 @@
//= require_tree ./discourse/adapters
//= require ./discourse/models/rest
//= require ./discourse/models/model
+//= require ./discourse/models/result-set
+//= require ./discourse/models/store
//= require ./discourse/models/post-action-type
//= require ./discourse/models/action-summary
//= require ./discourse/models/post
diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss
index 166829bb16..30a83703ca 100644
--- a/app/assets/stylesheets/common/admin/admin_base.scss
+++ b/app/assets/stylesheets/common/admin/admin_base.scss
@@ -3,6 +3,24 @@
@import "common/foundation/mixins";
@import "common/foundation/helpers";
+$mobile-breakpoint: 700px;
+
+// Change the box model for .admin-content
+@media (max-width: $mobile-breakpoint) {
+ .admin-content {
+ box-sizing: border-box;
+ *, *:before, *:after {
+ box-sizing: inherit;
+ }
+
+ input[type="text"] {
+ // Desktop/_discourse.scss sets a height on text-input elements. Using `box-sizing: border-box`
+ // this value either needs to be increased or set to auto. `mobile.css` seems to not set a height on text-inputs.
+ height: auto;
+ }
+ }
+}
+
.admin-contents table {
width: 100%;
tr {text-align: left;}
@@ -32,7 +50,7 @@ td.flaggers td {
.admin-content {
margin-bottom: 50px;
.admin-contents {
- padding: 8px;
+ padding: 8px 0;
@include clearfix();
}
@@ -96,6 +114,10 @@ td.flaggers td {
margin-top: 20px;
}
+.admin-container .controls {
+ @include clearfix;
+}
+
.admin-title {
height: 45px;
}
@@ -103,7 +125,7 @@ td.flaggers td {
.admin-controls {
background-color: dark-light-diff($primary, $secondary, 90%, -75%);
padding: 10px 10px 3px 0;
- height: 35px;
+ @include clearfix;
.nav.nav-pills {
li.active {
a {
@@ -147,6 +169,14 @@ td.flaggers td {
label {
margin-top: 5px;
}
+ .controls {
+ margin-left: 0;
+ }
+ // Hide the search checkbox for very small screens
+ // Todo: find somewhere to display it - probably requires switching its order in the html
+ @media (max-width: 450px) {
+ display: none;
+ }
}
.toggle {
margin-top: 8px;
@@ -184,6 +214,9 @@ td.flaggers td {
.admin-nav {
width: 18.018%;
+ @media (max-width: $mobile-breakpoint) {
+ width: 33%;
+ }
margin-top: 30px;
.nav-stacked {
border-right: none;
@@ -196,10 +229,16 @@ td.flaggers td {
.admin-detail {
width: 76.5765%;
+ @media (max-width: $mobile-breakpoint) {
+ width: 67%;
+ }
min-height: 800px;
margin-left: 0;
border-left: solid 1px dark-light-diff($primary, $secondary, 90%, -60%);
padding: 30px 0 30px 30px;
+ @media (max-width: $mobile-breakpoint) {
+ padding: 30px 0 30px 16px;
+ }
}
.settings {
@@ -210,13 +249,27 @@ td.flaggers td {
float: left;
width: 17.6576%;
margin-right: 12px;
+ @media (max-width: $mobile-breakpoint) {
+ float: none;
+ margin-right: 0;
+ width: 100%;
+ h3 {
+ margin-bottom: 6px;
+ }
+ }
}
.setting-value {
float: left;
width: 53%;
- .select2-container {
+ @media (max-width: $mobile-breakpoint) {
width: 100%;
}
+ .select2-container {
+ width: 100% !important; // Needs !important to override hard-coded value
+ @media (max-width: $mobile-breakpoint) {
+ width: 100% !important; // !important overrides hard-coded mobile width of 68px
+ }
+ }
.select2-container-multi .select2-choices {
border: none;
}
@@ -227,10 +280,15 @@ td.flaggers td {
.input-setting-string {
width: 404px;
@include medium-width { width: 314px; }
- @include small-width { width: 284px; }
+ @media (max-width: $mobile-breakpoint) {
+ width: 100%;
+ }
}
.input-setting-list {
width: 408px;
+ @media (max-width: $mobile-breakpoint) {
+ width: 100%;
+ }
padding: 1px;
background-color: $secondary;
border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
@@ -255,7 +313,7 @@ td.flaggers td {
border-radius: 3px;
background-clip: padding-box;
-moz-user-select: none;
- background-color: none;
+ background-color: transparent;
width: 3em;
height: 1em;
}
@@ -553,6 +611,8 @@ section.details {
.style-name {
width: 350px;
height: 25px;
+ // Remove height to for `box-sizing: border-box`
+ height: auto;
}
.ace-wrapper {
position: relative;
@@ -698,10 +758,13 @@ section.details {
.version-check {
+ th {
+ text-align: left !important;
+ }
+
.version-number {
font-size: 1.286em;
font-weight: bold;
- text-align: center;
}
.face {
@@ -1143,6 +1206,7 @@ table.api-keys {
.staff-actions {
width: 100%;
+ min-width: 990px;
.action {
width: 10.810%;
}
@@ -1532,3 +1596,19 @@ table#user-badges {
.permalink-title {
margin-bottom: 10px;
}
+
+// Mobile specific styles
+// Mobile view text-inputs need some padding
+.mobile-view .admin-contents {
+ input[type="text"] {
+ padding: 4px;
+ }
+}
+
+.mobile-view .admin-controls {
+ padding: 10px 10px 9px 0;
+}
+
+.mobile-view .full-width {
+ margin: 0;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/common/base/search.scss b/app/assets/stylesheets/common/base/search.scss
index 33b5263269..75de8a32a8 100644
--- a/app/assets/stylesheets/common/base/search.scss
+++ b/app/assets/stylesheets/common/base/search.scss
@@ -4,13 +4,14 @@
max-width: inherit;
}
+ .search-category {
+ margin-top: 3px;
+ }
+
margin-bottom: 28px;
max-width: 675px;
.topic {
- a {
- color: scale-color($primary, $lightness: 10%);
- }
- line-height: 20px;
+ padding-bottom: 2px;
}
.avatar {
position: relative;
@@ -19,15 +20,15 @@
}
.search-link {
.topic-statuses, .topic-title {
- font-size: 1.4em;
+ font-size: 1.25em;
}
}
.blurb {
font-size: 1.0em;
- line-height: 24px;
+ line-height: 20px;
word-wrap: break-word;
clear: both;
- color: scale-color($primary, $lightness: 20%);
+ color: scale-color($primary, $lightness: 40%);
.date {
color: scale-color($primary, $lightness: 40%);
}
diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss
index 24691c940e..74b87c8265 100644
--- a/app/assets/stylesheets/common/base/user-badges.scss
+++ b/app/assets/stylesheets/common/base/user-badges.scss
@@ -51,7 +51,9 @@
}
img {
- display: inline-block;
+ display: block;
+ margin: auto;
+ margin-bottom: 4px;
width: 55px;
height: 55px;
}
diff --git a/app/assets/stylesheets/common/components/buttons.css.scss b/app/assets/stylesheets/common/components/buttons.css.scss
index 0c05fd1982..2821356313 100644
--- a/app/assets/stylesheets/common/components/buttons.css.scss
+++ b/app/assets/stylesheets/common/components/buttons.css.scss
@@ -128,8 +128,7 @@
&:before {
margin-right: 9px;
font-family: FontAwesome;
- line-height: 1.6em;
- font-size: 1.3em;
+ font-size: 17px;
}
&.google, &.google_oauth2 {
background: $google;
diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss
index 4ccd4f4d1e..027beaa530 100644
--- a/app/assets/stylesheets/desktop/user.scss
+++ b/app/assets/stylesheets/desktop/user.scss
@@ -168,12 +168,14 @@
th {
text-align: left;
- border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
- padding: 5px;
+ border-bottom: 3px solid dark-light-diff($primary, $secondary, 90%, -60%);
+ padding: 0 0 10px 0;
+ color: scale-color($primary, $lightness: 50%);
+ font-weight: normal;
}
td {
- padding: 5px;
+ padding: 10px 0 10px 0;
border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
}
}
diff --git a/app/assets/stylesheets/embed.css.scss b/app/assets/stylesheets/embed.css.scss
index 5c02a289d6..8ada6da381 100644
--- a/app/assets/stylesheets/embed.css.scss
+++ b/app/assets/stylesheets/embed.css.scss
@@ -50,6 +50,7 @@ article.post {
img {
max-width: 45px;
+ border-radius: 50%;
}
}
diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss
index ae7b0ae823..77b634c92e 100644
--- a/app/assets/stylesheets/mobile/topic-post.scss
+++ b/app/assets/stylesheets/mobile/topic-post.scss
@@ -514,6 +514,9 @@ span.highlighted {
}
.small-action .small-action-desc {
+ p {
+ padding-top: 0;
+ }
.custom-message {
margin-left: -40px;
}
@@ -521,6 +524,7 @@ span.highlighted {
.small-action .topic-avatar {
padding: 0;
+ margin: 0;
}
.small-action.time-gap .topic-avatar {
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 0d301b1bbb..ea2c3a08f7 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -88,7 +88,18 @@ class PostsController < ApplicationController
end
def create
+
+ if !is_api? && current_user.blocked?
+
+ # error has parity with what user would get if they posted when blocked
+ # and it went through post creator
+ render json: {errors: [I18n.t("topic_not_found")]}, status: 422
+ return
+ end
+
@manager_params = create_params
+ @manager_params[:first_post_checks] = !is_api?
+
manager = NewPostManager.new(current_user, @manager_params)
if is_api?
@@ -353,7 +364,7 @@ class PostsController < ApplicationController
# If a param is present it uses that result structure.
def backwards_compatible_json(json_obj, success)
json_obj.symbolize_keys!
- if params[:nested_post].blank? && json_obj[:errors].blank?
+ if params[:nested_post].blank? && json_obj[:errors].blank? && json_obj[:action] != :enqueued
json_obj = json_obj[:post]
end
@@ -403,7 +414,6 @@ class PostsController < ApplicationController
# Awful hack, but you can't seem to remove the `default_scope` when joining
# So instead I grab the topics separately
topic_ids = posts.dup.pluck(:topic_id)
- secured_category_ids = guardian.secure_category_ids
topics = Topic.where(id: topic_ids).with_deleted.where.not(archetype: 'private_message')
topics = topics.secured(guardian)
@@ -422,7 +432,9 @@ class PostsController < ApplicationController
:category,
:target_usernames,
:reply_to_post_number,
- :auto_track
+ :auto_track,
+ :typing_duration_msecs,
+ :composer_open_duration_msecs
]
# param munging for WordPress
diff --git a/app/controllers/user_actions_controller.rb b/app/controllers/user_actions_controller.rb
index e4d4079fec..c20f9c8d23 100644
--- a/app/controllers/user_actions_controller.rb
+++ b/app/controllers/user_actions_controller.rb
@@ -24,7 +24,7 @@ class UserActionsController < ApplicationController
UserAction.stream(opts)
end
- render_serialized(stream, UserActionSerializer, root: "user_actions")
+ render_serialized(stream, UserActionSerializer, root: 'user_actions')
end
def show
diff --git a/app/jobs/scheduled/poll_mailbox.rb b/app/jobs/scheduled/poll_mailbox.rb
index 608559dff6..68a1f98632 100644
--- a/app/jobs/scheduled/poll_mailbox.rb
+++ b/app/jobs/scheduled/poll_mailbox.rb
@@ -31,6 +31,9 @@ module Jobs
end
def handle_failure(mail_string, e)
+
+ Rails.logger.warn("Email can not be processed: #{e}\n\n#{mail_string}") if SiteSetting.log_mail_processing_failures
+
template_args = {}
case e
when Email::Receiver::UserNotSufficientTrustLevelError
diff --git a/app/models/concerns/has_custom_fields.rb b/app/models/concerns/has_custom_fields.rb
index b97e6cf3fb..1e1f3869a1 100644
--- a/app/models/concerns/has_custom_fields.rb
+++ b/app/models/concerns/has_custom_fields.rb
@@ -45,6 +45,8 @@ module HasCustomFields
has_many :_custom_fields, dependent: :destroy, :class_name => "#{name}CustomField"
after_save :save_custom_fields
+ attr_accessor :preloaded_custom_fields
+
# To avoid n+1 queries, use this function to retrieve lots of custom fields in one go
# and create a "sideloaded" version for easy querying by id.
def self.custom_fields_for_ids(ids, whitelisted_fields)
@@ -73,6 +75,39 @@ module HasCustomFields
@custom_field_types[name] = type
end
+ def self.preload_custom_fields(objects, fields)
+ if objects.present?
+ map = {}
+
+ empty = {}
+ fields.each do |field|
+ empty[field] = nil
+ end
+
+ objects.each do |obj|
+ map[obj.id] = obj
+ obj.preloaded_custom_fields = empty.dup
+ end
+
+ fk = (name.underscore << "_id")
+
+ "#{name}CustomField".constantize
+ .where("#{fk} in (?)", map.keys)
+ .where("name in (?)", fields)
+ .pluck(fk, :name, :value).each do |id, name, value|
+
+ preloaded = map[id].preloaded_custom_fields
+
+ if preloaded[name].nil?
+ preloaded.delete(name)
+ end
+
+ HasCustomFields::Helpers.append_field(preloaded, name, value, @custom_field_types)
+ end
+
+ end
+ end
+
end
def reload(options = nil)
@@ -80,12 +115,36 @@ module HasCustomFields
super
end
+ def custom_field_preloaded?(name)
+ @preloaded_custom_fields && @preloaded_custom_fields.key?(name)
+ end
+
def clear_custom_fields
@custom_fields = nil
@custom_fields_orig = nil
end
+ class PreloadedProxy
+ def initialize(preloaded)
+ @preloaded = preloaded
+ end
+
+ def [](key)
+ if @preloaded.key?(key)
+ @preloaded[key]
+ else
+ # for now you can not mix preload an non preload, it better just to fail
+ raise StandardError, "Attempting to access a non preloaded custom field, this is disallowed to prevent N+1 queries."
+ end
+ end
+ end
+
def custom_fields
+
+ if @preloaded_custom_fields
+ return @preloaded_proxy ||= PreloadedProxy.new(@preloaded_custom_fields)
+ end
+
@custom_fields ||= refresh_custom_fields_from_db.dup
end
diff --git a/app/models/draft.rb b/app/models/draft.rb
index 2a209fd0f1..27378ea05e 100644
--- a/app/models/draft.rb
+++ b/app/models/draft.rb
@@ -7,7 +7,11 @@ class Draft < ActiveRecord::Base
d = find_draft(user,key)
if d
return if d.sequence > sequence
- d.update_columns(data: data, sequence: sequence)
+ exec_sql("UPDATE drafts
+ SET data = :data,
+ sequence = :sequence,
+ revisions = revisions + 1
+ WHERE id = :id", id: d.id, sequence: sequence, data: data)
else
Draft.create!(user_id: user.id, draft_key: key, data: data, sequence: sequence)
end
diff --git a/app/models/post.rb b/app/models/post.rb
index 7dfe6c3e57..00523e187d 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -37,6 +37,7 @@ class Post < ActiveRecord::Base
has_many :uploads, through: :post_uploads
has_one :post_search_data
+ has_one :post_stat
has_many :post_details
diff --git a/app/models/post_mover.rb b/app/models/post_mover.rb
index 77111f6151..272eb1c3f4 100644
--- a/app/models/post_mover.rb
+++ b/app/models/post_mover.rb
@@ -123,11 +123,15 @@ class PostMover
end
def create_moderator_post_in_original_topic
+ move_type_str = PostMover.move_types[@move_type].to_s
+
original_topic.add_moderator_post(
user,
- I18n.t("move_posts.#{PostMover.move_types[@move_type]}_moderator_post",
+ I18n.t("move_posts.#{move_type_str}_moderator_post",
count: post_ids.count,
- topic_link: "[#{destination_topic.title}](#{destination_topic.url})"),
+ topic_link: "[#{destination_topic.title}](#{destination_topic.relative_url})"),
+ post_type: Post.types[:small_action],
+ action_code: "split_topic",
post_number: @first_post_number_moved
)
end
diff --git a/app/models/post_stat.rb b/app/models/post_stat.rb
new file mode 100644
index 0000000000..b9b97acb20
--- /dev/null
+++ b/app/models/post_stat.rb
@@ -0,0 +1,3 @@
+class PostStat < ActiveRecord::Base
+ belongs_to :post
+end
diff --git a/app/models/queued_post.rb b/app/models/queued_post.rb
index 39c51a3544..6bbff2a053 100644
--- a/app/models/queued_post.rb
+++ b/app/models/queued_post.rb
@@ -64,8 +64,17 @@ class QueuedPost < ActiveRecord::Base
QueuedPost.transaction do
change_to!(:approved, approved_by)
+ if user.blocked?
+ user.update_columns(blocked: false)
+ end
+
creator = PostCreator.new(user, create_options.merge(skip_validations: true))
created_post = creator.create
+
+ unless created_post && creator.errors.blank?
+ raise StandardError, "Failed to create post #{raw[0..100]} #{creator.errors}"
+ end
+
end
DiscourseEvent.trigger(:approved_post, self)
diff --git a/app/models/topic_link_click.rb b/app/models/topic_link_click.rb
index 1f3302988c..4a51ca5200 100644
--- a/app/models/topic_link_click.rb
+++ b/app/models/topic_link_click.rb
@@ -29,6 +29,15 @@ class TopicLinkClick < ActiveRecord::Base
urls << uri.path if uri.try(:host) == Discourse.current_hostname
urls << url.sub(/\?.*$/, '') if url.include?('?')
+ # add a cdn link
+ if uri && Discourse.asset_host.present?
+ cdn_uri = URI.parse(Discourse.asset_host) rescue nil
+ if cdn_uri && cdn_uri.hostname == uri.hostname && uri.path.starts_with?(cdn_uri.path)
+ is_cdn_link = true
+ urls << uri.path[(cdn_uri.path.length)..-1]
+ end
+ end
+
link = TopicLink.select([:id, :user_id])
# test for all possible URLs
@@ -54,7 +63,9 @@ class TopicLinkClick < ActiveRecord::Base
return nil unless uri
# Only redirect to whitelisted hostnames
- return WHITELISTED_REDIRECT_HOSTNAMES.include?(uri.hostname) ? url : nil
+ return url if WHITELISTED_REDIRECT_HOSTNAMES.include?(uri.hostname) || is_cdn_link
+
+ return nil
end
return url if args[:user_id] && link.user_id == args[:user_id]
diff --git a/app/models/topic_list.rb b/app/models/topic_list.rb
index d58aa67be3..cce332a6d0 100644
--- a/app/models/topic_list.rb
+++ b/app/models/topic_list.rb
@@ -3,6 +3,9 @@ require_dependency 'avatar_lookup'
class TopicList
include ActiveModel::Serialization
+ cattr_accessor :preloaded_custom_fields
+ self.preloaded_custom_fields = []
+
attr_accessor :more_topics_url,
:prev_topics_url,
:draft,
@@ -78,6 +81,10 @@ class TopicList
ft.topic_list = self
end
+ if TopicList.preloaded_custom_fields.present?
+ Topic.preload_custom_fields(@topics, TopicList.preloaded_custom_fields)
+ end
+
@topics
end
diff --git a/app/models/user_action.rb b/app/models/user_action.rb
index 0d4c661d10..9b72a755de 100644
--- a/app/models/user_action.rb
+++ b/app/models/user_action.rb
@@ -154,6 +154,7 @@ SQL
CASE WHEN coalesce(p.deleted_at, p2.deleted_at, t.deleted_at) IS NULL THEN false ELSE true END deleted,
p.hidden,
p.post_type,
+ p.action_code,
p.edit_reason,
t.category_id
FROM user_actions as a
diff --git a/app/models/user_action_observer.rb b/app/models/user_action_observer.rb
index 665a1efdfc..34e6fcabed 100644
--- a/app/models/user_action_observer.rb
+++ b/app/models/user_action_observer.rb
@@ -29,11 +29,11 @@ class UserActionObserver < ActiveRecord::Observer
return unless action && post && user && post.id
row = {
- action_type: action,
- user_id: user.id,
- acting_user_id: acting_user_id || post.user_id,
- target_topic_id: post.topic_id,
- target_post_id: post.id
+ action_type: action,
+ user_id: user.id,
+ acting_user_id: acting_user_id || post.user_id,
+ target_topic_id: post.topic_id,
+ target_post_id: post.id
}
if post.deleted_at.nil?
@@ -48,12 +48,12 @@ class UserActionObserver < ActiveRecord::Observer
return if model.is_first_post?
row = {
- action_type: UserAction::REPLY,
- user_id: model.user_id,
- acting_user_id: model.user_id,
- target_post_id: model.id,
- target_topic_id: model.topic_id,
- created_at: model.created_at
+ action_type: UserAction::REPLY,
+ user_id: model.user_id,
+ acting_user_id: model.user_id,
+ target_post_id: model.id,
+ target_topic_id: model.topic_id,
+ created_at: model.created_at
}
rows = [row]
@@ -79,12 +79,12 @@ class UserActionObserver < ActiveRecord::Observer
def log_topic(model)
row = {
- action_type: model.archetype == Archetype.private_message ? UserAction::NEW_PRIVATE_MESSAGE : UserAction::NEW_TOPIC,
- user_id: model.user_id,
- acting_user_id: model.user_id,
- target_topic_id: model.id,
- target_post_id: -1,
- created_at: model.created_at
+ action_type: model.archetype == Archetype.private_message ? UserAction::NEW_PRIVATE_MESSAGE : UserAction::NEW_TOPIC,
+ user_id: model.user_id,
+ acting_user_id: model.user_id,
+ target_topic_id: model.id,
+ target_post_id: -1,
+ created_at: model.created_at
}
rows = [row]
diff --git a/app/serializers/queued_post_serializer.rb b/app/serializers/queued_post_serializer.rb
index 86b36bbda1..43892fa292 100644
--- a/app/serializers/queued_post_serializer.rb
+++ b/app/serializers/queued_post_serializer.rb
@@ -13,7 +13,7 @@ class QueuedPostSerializer < ApplicationSerializer
:category_id,
:can_delete_user
- has_one :user, serializer: BasicUserSerializer
+ has_one :user, serializer: AdminUserListSerializer
has_one :topic, serializer: BasicTopicSerializer
def category_id
diff --git a/app/serializers/user_action_serializer.rb b/app/serializers/user_action_serializer.rb
index f6dcf2b9fb..8b39399639 100644
--- a/app/serializers/user_action_serializer.rb
+++ b/app/serializers/user_action_serializer.rb
@@ -22,7 +22,8 @@ class UserActionSerializer < ApplicationSerializer
:title,
:deleted,
:hidden,
- :moderator_action,
+ :post_type,
+ :action_code,
:edit_reason,
:category_id,
:uploaded_avatar_id,
@@ -32,7 +33,7 @@ class UserActionSerializer < ApplicationSerializer
def excerpt
cooked = object.cooked || PrettyText.cook(object.raw)
- PrettyText.excerpt(cooked, 300, { keep_emojis: true }) if cooked
+ PrettyText.excerpt(cooked, 300, keep_emojis: true) if cooked
end
def avatar_template
@@ -67,10 +68,6 @@ class UserActionSerializer < ApplicationSerializer
object.title.present?
end
- def moderator_action
- object.post_type == Post.types[:moderator_action] || object.post_type == Post.types[:small_action]
- end
-
def include_reply_to_post_number?
object.action_type == UserAction::REPLY
end
diff --git a/app/views/common/_discourse_javascript.html.erb b/app/views/common/_discourse_javascript.html.erb
index 012592f0df..df1977566e 100644
--- a/app/views/common/_discourse_javascript.html.erb
+++ b/app/views/common/_discourse_javascript.html.erb
@@ -24,6 +24,12 @@
<% end %>
window.onerror(e && e.message, null,null,null,e);
});
+
+<% if Rails.env.development? || Rails.env.test? %>
+ Ember.ENV.RAISE_ON_DEPRECATION = true
+ Ember.LOG_STACKTRACE_ON_DEPRECATION = true
+<% end %>
+