diff --git a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 index 83b493076..9f9b26876 100644 --- a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 +++ b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 @@ -1,3 +1,4 @@ +import computed from 'ember-addons/ember-computed-decorators'; import DiscoveryController from 'discourse/controllers/discovery'; export default DiscoveryController.extend({ @@ -9,36 +10,14 @@ export default DiscoveryController.extend({ // this makes sure the composer isn't scoping to a specific category category: null, - actions: { - - refresh() { - // Don't refresh if we're still loading - if (this.get('controllers.discovery.loading')) { return; } - - // If we `send('loading')` here, due to returning true it bubbles up to the - // router and ember throws an error due to missing `handlerInfos`. - // Lesson learned: Don't call `loading` yourself. - this.set('controllers.discovery.loading', true); - - const CategoryList = require('discourse/models/category-list').default; - const parentCategory = this.get('model.parentCategory'); - const promise = parentCategory ? CategoryList.listForParent(this.store, parentCategory) : - CategoryList.list(this.store); - - const self = this; - promise.then(function(list) { - self.set('model', list); - self.send('loadingComplete'); - }); - } + @computed + canEdit() { + return Discourse.User.currentProp('staff'); }, - canEdit: function() { - return Discourse.User.currentProp('staff'); - }.property(), - - latestTopicOnly: function() { - return this.get('model.categories').find(c => c.get('featuredTopics.length') > 1) === undefined; - }.property('model.categories.@each.featuredTopics.length') + @computed("model.categories.@each.featuredTopics.length") + latestTopicOnly() { + return this.get("model.categories").find(c => c.get('featuredTopics.length') > 1) === undefined; + } }); diff --git a/app/assets/javascripts/discourse/lib/url.js.es6 b/app/assets/javascripts/discourse/lib/url.js.es6 index 4b72cc26e..a645022f1 100644 --- a/app/assets/javascripts/discourse/lib/url.js.es6 +++ b/app/assets/javascripts/discourse/lib/url.js.es6 @@ -154,15 +154,15 @@ const DiscourseURL = Ember.Object.extend({ // Schedule a DOM cleanup event Em.run.scheduleOnce('afterRender', Discourse.Route, 'cleanDOM'); - // TODO: Extract into rules we can inject into the URL handler - if (this.navigatedToHome(oldPath, path, opts)) { return; } - if (oldPath === path) { // If navigating to the same path send an app event. Views can watch it // and tell their controllers to refresh this.appEvents.trigger('url:refresh'); } + // TODO: Extract into rules we can inject into the URL handler + if (this.navigatedToHome(oldPath, path, opts)) { return; } + return this.handleURL(path, opts); }, diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6 index a6184e368..712a1b369 100644 --- a/app/assets/javascripts/discourse/models/topic.js.es6 +++ b/app/assets/javascripts/discourse/models/topic.js.es6 @@ -71,11 +71,6 @@ const Topic = RestModel.extend({ I18n.t('last_post') + ": " + longDate(this.get('bumpedAt')); }.property('bumpedAt'), - @computed('replyCount') - replyTitle(count) { - return I18n.t("posts_likes", { count }); - }, - createdAt: function() { return new Date(this.get('created_at')); }.property('created_at'), diff --git a/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 index d33919cbb..37be18bc3 100644 --- a/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 +++ b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 @@ -31,7 +31,11 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, { }, setupController(controller, model) { - TopicList.find("latest").then(result => model.set("topicList", result)); + model.set("loadingTopics", true); + + TopicList.find("latest") + .then(result => model.set("topicList", result)) + .finally(() => model.set("loadingTopics", false)); controller.set("model", model); @@ -44,6 +48,28 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, { }, actions: { + + refresh() { + const controller = this.controllerFor("discovery/categories"); + + // Don't refresh if we're still loading + if (!controller || controller.get("loading")) { return; } + + // If we `send('loading')` here, due to returning true it bubbles up to the + // router and ember throws an error due to missing `handlerInfos`. + // Lesson learned: Don't call `loading` yourself. + controller.set("loading", true); + + const parentCategory = this.get("model.parentCategory"); + const promise = parentCategory ? CategoryList.listForParent(this.store, parentCategory) : + CategoryList.list(this.store); + + promise.then(list => { + this.setupController(controller, list); + controller.send("loadingComplete"); + }); + }, + createCategory() { const groups = this.site.groups, everyoneName = groups.findBy("id", 0).name; diff --git a/app/assets/javascripts/discourse/templates/discovery/categories.hbs b/app/assets/javascripts/discourse/templates/discovery/categories.hbs index 00dcd4973..60297813e 100644 --- a/app/assets/javascripts/discourse/templates/discovery/categories.hbs +++ b/app/assets/javascripts/discourse/templates/discovery/categories.hbs @@ -47,50 +47,61 @@ - {{#each model.topicList.topics as |t|}} - - - - - - - {{topic-status topic=t}} - {{topic-link t}} - {{#if t.unseen}} - - {{/if}} - - - {{category-link t.category}} - {{#if t.tags}} - {{#each t.visibleListTags as |tag|}} - {{discourse-tag tag}} - {{/each}} - {{/if}} - - - + {{#if model.loadingTopics}} + {{loading-spinner}} + {{else}} + {{#if model.topicList.topics}} + {{#each model.topicList.topics as |t|}} + +
- {{#with t.posters.lastObject.user as |lastPoster|}} - {{#user-link user=lastPoster}} - {{avatar lastPoster imageSize="large"}} - {{/user-link}} - {{/with}} -
- - -
+ + + + + {{topic-status topic=t}} + {{topic-link t}} + {{topic-post-badges newPosts=t.totalUnread unseen=t.unseen url=t.lastUnreadUrl}} + + + {{category-link t.category}} + {{#if t.tags}} + {{#each t.visibleListTags as |tag|}} + {{discourse-tag tag}} + {{/each}} + {{/if}} + + + + + +
+ {{#with t.posters.firstObject.user as |originalPoster|}} + {{#user-link user=originalPoster}} + {{avatar originalPoster imageSize="large"}} + {{/user-link}} + {{/with}} +
+ {{raw "list/posts-count-column" topic=t tagName="div"}} + +
- - - - {{else}} - {{loading-spinner}} - {{/each}} + {{/each}} + + + {{i18n "more"}} + + + {{else}} + + +

{{i18n "topics.none.latest"}}

+ + + {{/if}} + {{/if}}
diff --git a/app/assets/javascripts/discourse/templates/list/posts-count-column.raw.hbs b/app/assets/javascripts/discourse/templates/list/posts-count-column.raw.hbs index 052bb4777..599d695ab 100644 --- a/app/assets/javascripts/discourse/templates/list/posts-count-column.raw.hbs +++ b/app/assets/javascripts/discourse/templates/list/posts-count-column.raw.hbs @@ -1,3 +1,3 @@ <{{view.tagName}} class='num posts-map posts {{view.likesHeat}}' title='{{view.title}}'> - {{number topic.replyCount}} + {{number topic.replyCount noTitle="true"}} diff --git a/app/assets/javascripts/discourse/views/list/posts-count-column.js.es6 b/app/assets/javascripts/discourse/views/list/posts-count-column.js.es6 index d60263667..e61e1b9c0 100644 --- a/app/assets/javascripts/discourse/views/list/posts-count-column.js.es6 +++ b/app/assets/javascripts/discourse/views/list/posts-count-column.js.es6 @@ -1,32 +1,32 @@ +import computed from 'ember-addons/ember-computed-decorators'; import { fmt } from 'discourse/lib/computed'; export default Ember.Object.extend({ tagName: "td", - ratio: function() { - var likes = parseFloat(this.get('topic.like_count')), - posts = parseFloat(this.get('topic.posts_count')); + + @computed("topic.like_count", "topic.posts_count") + ratio(likeCount, postCount) { + const likes = parseFloat(likeCount); + const posts = parseFloat(postCount); if (posts < 10) { return 0; } return (likes || 0) / posts; - }.property(), + }, - title: function() { - return I18n.messageFormat('posts_likes_MF', { - count: this.get('topic.replyCount'), - ratio: this.get('ratioText') - }).trim(); - }.property(), + @computed("topic.replyCount", "ratioText") + title(count, ratio) { + return I18n.messageFormat('posts_likes_MF', { count, ratio }).trim(); + }, - ratioText: function() { - var ratio = this.get('ratio'); - - var settings = Discourse.SiteSettings; - if (ratio > settings.topic_post_like_heat_high) { return 'high'; } + @computed("ratio") + ratioText(ratio) { + const settings = this.siteSettings; + if (ratio > settings.topic_post_like_heat_high) { return 'high'; } if (ratio > settings.topic_post_like_heat_medium) { return 'med'; } - if (ratio > settings.topic_post_like_heat_low) { return 'low'; } + if (ratio > settings.topic_post_like_heat_low) { return 'low'; } return ''; - }.property(), + }, likesHeat: fmt('ratioText', 'heatmap-%@'), }); diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss index 20d6a8d16..0dec7467d 100644 --- a/app/assets/stylesheets/common/base/_topic-list.scss +++ b/app/assets/stylesheets/common/base/_topic-list.scss @@ -124,12 +124,24 @@ html.anon .topic-list a.title:visited:not(.badge-notification) {color: dark-ligh color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 40%)); } } - .topic-replies { - font-weight: bold; + .num.posts { + text-align: right; + a { + padding: 0; + } + } + .posts-map.posts { margin-bottom: 10px; + width: 100%; + .badge-posts { + font-weight: bold; + } } .topic-list-latest { margin-left: 4%; + .new-posts { + margin-left: 5px; + } } .topic-list.categories { th.stats { @@ -138,6 +150,16 @@ html.anon .topic-list a.title:visited:not(.badge-notification) {color: dark-ligh .stats { vertical-align: top; text-align: center; + .value { + font-size: 1.2em; + } + } + } + .no-topics, .more-topics { + border-bottom: none; + td { + padding-right: 0 !important; + color: $primary; } } } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 32904cd8c..dfbf39005 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1936,10 +1936,6 @@ en: posts: "Posts" posts_long: "there are {{number}} posts in this topic" - posts_likes: - one: "This topic has 1 reply." - other: "This topic has {{count}} replies." - # keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details posts_likes_MF: | This topic has {count, plural, one {1 reply} other {# replies}} {ratio, select,