diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js
index fd6ad4e26da..965f68434a2 100644
--- a/app/assets/javascripts/discourse/models/category.js
+++ b/app/assets/javascripts/discourse/models/category.js
@@ -34,6 +34,7 @@ Discourse.Category = Discourse.Model.extend({
return Discourse.getURL("/category/") + (this.get('slug'));
}.property('name'),
+
style: function() {
return "background-color: #" + (this.get('category.color')) + "; color: #" + (this.get('category.text_color')) + ";";
}.property('color', 'text_color'),
@@ -101,7 +102,15 @@ Discourse.Category = Discourse.Model.extend({
latestTopic: function(){
return this.get("topics")[0];
- }.property("topics")
+ }.property("topics"),
+
+ unreadTopics: function(){
+ return Discourse.TopicTrackingState.current().countUnread(this.get('name'));
+ }.property('Discourse.TopicTrackingState.current.messageCount'),
+
+ newTopics: function(){
+ return Discourse.TopicTrackingState.current().countNew(this.get('name'));
+ }.property('Discourse.TopicTrackingState.current.messageCount')
});
diff --git a/app/assets/javascripts/discourse/models/topic.js b/app/assets/javascripts/discourse/models/topic.js
index af80f678cd5..cfe6afc1bef 100644
--- a/app/assets/javascripts/discourse/models/topic.js
+++ b/app/assets/javascripts/discourse/models/topic.js
@@ -87,6 +87,10 @@ Discourse.Topic = Discourse.Model.extend({
return this.urlForPostNumber(this.get('highest_post_number'));
}.property('url', 'highest_post_number'),
+ lastPosterUrl: function() {
+ return Discourse.getURL("/users/") + this.get("last_poster.username");
+ }.property('last_poster'),
+
// The amount of new posts to display. It might be different than what the server
// tells us if we are still asynchronously flushing our "recently read" data.
// So take what the browser has seen into consideration.
diff --git a/app/assets/javascripts/discourse/models/topic_tracking_state.js b/app/assets/javascripts/discourse/models/topic_tracking_state.js
index 80c85b95313..882d0dd6af3 100644
--- a/app/assets/javascripts/discourse/models/topic_tracking_state.js
+++ b/app/assets/javascripts/discourse/models/topic_tracking_state.js
@@ -129,20 +129,23 @@ Discourse.TopicTrackingState = Discourse.Model.extend({
this.set("messageCount", this.get("messageCount") + 1);
},
- countNew: function(){
+ countNew: function(category_name){
return _.chain(this.states)
.where({last_read_post_number: null})
+ .where(function(topic){ return topic.category_name === category_name || !category_name;})
.value()
.length;
},
- countUnread: function(){
- var count = 0;
- _.each(this.states, function(topic){
- count += (topic.last_read_post_number !== null &&
- topic.last_read_post_number < topic.highest_post_number) ? 1 : 0;
- });
- return count;
+ countUnread: function(category_name){
+ return _.chain(this.states)
+ .where(function(topic){
+ return topic.last_read_post_number !== null &&
+ topic.last_read_post_number < topic.highest_post_number;
+ })
+ .where(function(topic){ return topic.category_name === category_name || !category_name;})
+ .value()
+ .length;
},
countCategory: function(category) {
diff --git a/app/assets/javascripts/discourse/templates/list/basic_topic_list.js.handlebars b/app/assets/javascripts/discourse/templates/list/basic_topic_list.js.handlebars
index 2e488e3ef0d..2cf0896d154 100644
--- a/app/assets/javascripts/discourse/templates/list/basic_topic_list.js.handlebars
+++ b/app/assets/javascripts/discourse/templates/list/basic_topic_list.js.handlebars
@@ -46,7 +46,7 @@
{{unboundAge created_at}}
- {{unboundAge bumped_at}}
+ {{unboundAge bumped_at}}
|
{{else}}
@@ -62,4 +62,4 @@
{{i18n choose_topic.none_found}}
-{{/if}}
\ No newline at end of file
+{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/list/wide_categories.js.handlebars b/app/assets/javascripts/discourse/templates/list/wide_categories.js.handlebars
index c2e4e5bf760..6bb88dfb71a 100644
--- a/app/assets/javascripts/discourse/templates/list/wide_categories.js.handlebars
+++ b/app/assets/javascripts/discourse/templates/list/wide_categories.js.handlebars
@@ -14,6 +14,12 @@
{{#each model.categories}}
|
{{categoryLink this}}
+ {{#if unreadTopics}}
+ {{unbound unreadTopics}}
+ {{/if}}
+ {{#if newTopics}}
+ {{unbound newTopics}}
+ {{/if}}
{{#if description_excerpt}}
{{{description_excerpt}}}
@@ -25,12 +31,15 @@
{{/each}}
|
{{number topic_count}} |
- {{number posts_total}} |
+ {{number post_count}} |
{{#with latestTopic}}
{{topicStatus topic=this}}
{{{topicLink this}}}
-
+
|
{{/with}}
diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb
index c7487f13d11..1fe45e8b627 100644
--- a/app/controllers/categories_controller.rb
+++ b/app/controllers/categories_controller.rb
@@ -9,7 +9,14 @@ class CategoriesController < ApplicationController
def index
@description = SiteSetting.site_description
- @list = CategoryList.new(guardian)
+ wide_mode = SiteSetting.enable_wide_category_list
+
+ options = {}
+ options[:latest_post_only] = params[:latest_post_only] || wide_mode
+
+ @list = CategoryList.new(guardian,options)
+
+
@list.draft_key = Draft::NEW_TOPIC
@list.draft_sequence = DraftSequence.current(current_user, Draft::NEW_TOPIC)
diff --git a/app/models/category.rb b/app/models/category.rb
index df86fe8d036..c2ba4456988 100644
--- a/app/models/category.rb
+++ b/app/models/category.rb
@@ -13,6 +13,7 @@ class Category < ActiveRecord::Base
end
belongs_to :user
+ belongs_to :latest_post, class_name: "Post"
has_many :topics
has_many :category_featured_topics
@@ -227,6 +228,26 @@ SQL
end
end
+ def update_latest
+ latest_post_id = Post
+ .order("posts.created_at desc")
+ .where("NOT hidden")
+ .joins("join topics on topics.id = topic_id")
+ .where("topics.category_id = :id", id: self.id)
+ .limit(1)
+ .pluck("posts.id")
+ .first
+
+ latest_topic_id = Topic
+ .order("topics.created_at desc")
+ .where("visible")
+ .where("topics.category_id = :id", id: self.id)
+ .limit(1)
+ .pluck("topics.id")
+ .first
+
+ self.update_attributes(latest_topic_id: latest_topic_id, latest_post_id: latest_post_id)
+ end
def self.resolve_permissions(permissions)
read_restricted = true
diff --git a/app/models/category_list.rb b/app/models/category_list.rb
index 94dd860a093..a3df31e9f87 100644
--- a/app/models/category_list.rb
+++ b/app/models/category_list.rb
@@ -8,10 +8,11 @@ class CategoryList
:draft_key,
:draft_sequence
- def initialize(guardian=nil)
+ def initialize(guardian=nil, options = {})
@guardian = guardian || Guardian.new
+ @options = options
- find_relevant_topics
+ find_relevant_topics unless latest_post_only?
find_categories
prune_empty
@@ -21,6 +22,10 @@ class CategoryList
private
+ def latest_post_only?
+ @options[:latest_post_only]
+ end
+
# Retrieve a list of all the topics we'll need
def find_relevant_topics
@topics_by_category_id = {}
@@ -47,16 +52,35 @@ class CategoryList
.order('COALESCE(categories.topics_month, 0) DESC')
.order('COALESCE(categories.topics_year, 0) DESC')
+ if latest_post_only?
+ @categories = @categories.includes(:latest_post => :topic )
+ end
+
@categories = @categories.to_a
- @categories.each do |c|
- topics_in_cat = @topics_by_category_id[c.id]
- if topics_in_cat.present?
- c.displayable_topics = []
- topics_in_cat.each do |topic_id|
- topic = @topics_by_id[topic_id]
- if topic.present?
- topic.category = c
- c.displayable_topics << topic
+
+ if latest_post_only?
+ @all_topics = []
+ @categories.each do |c|
+ if c.latest_post && c.latest_post.topic
+ c.displayable_topics = [c.latest_post.topic]
+ topic = c.latest_post.topic
+ topic.include_last_poster = true # hint for serialization
+ @all_topics << topic
+ end
+ end
+ end
+
+ if @topics_by_category_id
+ @categories.each do |c|
+ topics_in_cat = @topics_by_category_id[c.id]
+ if topics_in_cat.present?
+ c.displayable_topics = []
+ topics_in_cat.each do |topic_id|
+ topic = @topics_by_id[topic_id]
+ if topic.present?
+ topic.category = c
+ c.displayable_topics << topic
+ end
end
end
end
diff --git a/app/models/post.rb b/app/models/post.rb
index d12279e0c59..d1bfd3e6fc2 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -84,6 +84,9 @@ class Post < ActiveRecord::Base
super
update_flagged_posts_count
TopicLink.extract_from(self)
+ if topic && topic.category_id
+ topic.category.update_latest
+ end
end
# The key we use in redis to ensure unique posts
diff --git a/app/models/topic.rb b/app/models/topic.rb
index 6a7e3504872..0df39d989b5 100644
--- a/app/models/topic.rb
+++ b/app/models/topic.rb
@@ -98,6 +98,7 @@ class Topic < ActiveRecord::Base
attr_accessor :user_data
attr_accessor :posters # TODO: can replace with posters_summary once we remove old list code
attr_accessor :topic_list
+ attr_accessor :include_last_poster
# The regular order
scope :topic_list_order, lambda { order('topics.bumped_at desc') }
diff --git a/app/serializers/category_detailed_serializer.rb b/app/serializers/category_detailed_serializer.rb
index 2d8841f4723..0971b5840ad 100644
--- a/app/serializers/category_detailed_serializer.rb
+++ b/app/serializers/category_detailed_serializer.rb
@@ -6,6 +6,7 @@ class CategoryDetailedSerializer < ApplicationSerializer
:text_color,
:slug,
:topic_count,
+ :post_count,
:topics_week,
:topics_month,
:topics_year,
diff --git a/app/serializers/listable_topic_serializer.rb b/app/serializers/listable_topic_serializer.rb
index b0b0bbfe6e9..9a304e0163b 100644
--- a/app/serializers/listable_topic_serializer.rb
+++ b/app/serializers/listable_topic_serializer.rb
@@ -19,6 +19,12 @@ class ListableTopicSerializer < BasicTopicSerializer
:closed,
:archived
+ has_one :last_poster, serializer: BasicUserSerializer, embed: :objects
+
+ def include_associations!
+ include! :last_poster if object.include_last_poster
+ end
+
def bumped
object.created_at < object.bumped_at
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 146eb7d626e..99bde17a7c7 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -189,6 +189,7 @@ en:
posts: "Posts"
topics: "Topics"
latest: "Latest"
+ by: "by"
user:
said: "{{username}} said:"
@@ -591,6 +592,12 @@ en:
private_message: 'Start a private message'
list: 'Topics'
new: 'new topic'
+ new_topics:
+ one: '1 new topic'
+ other: '{{count}} new topics'
+ unread_topics:
+ one: '1 unread topic'
+ other: '{{count}} unread topics'
title: 'Topic'
loading_more: "Loading more Topics..."
loading: 'Loading topic...'
diff --git a/db/migrate/20131017030605_add_latest_to_categories.rb b/db/migrate/20131017030605_add_latest_to_categories.rb
new file mode 100644
index 00000000000..305aa6c4e10
--- /dev/null
+++ b/db/migrate/20131017030605_add_latest_to_categories.rb
@@ -0,0 +1,33 @@
+class AddLatestToCategories < ActiveRecord::Migration
+ def up
+ add_column :categories, :latest_post_id, :integer
+ add_column :categories, :latest_topic_id, :integer
+
+ execute <