From 33683715a9cce3c7618efe8f052569f670d9250c Mon Sep 17 00:00:00 2001
From: Sam <sam.saffron@gmail.com>
Date: Tue, 28 May 2013 08:43:17 +1000
Subject: [PATCH] work in progress live unread / new counts

---
 .../discourse/controllers/list_controller.js  |  4 +-
 .../javascripts/discourse/models/nav_item.js  | 12 ++-
 .../discourse/models/topic_list.js            |  1 -
 .../javascripts/discourse/models/user.js      |  1 +
 .../discourse/models/user_tracking_state.js   | 80 +++++++++++++++++--
 .../discourse/routes/application_route.js     | 24 ++++++
 .../discourse/views/nav_item_view.js          | 21 +++--
 app/serializers/topic_list_serializer.rb      |  2 +-
 8 files changed, 124 insertions(+), 21 deletions(-)
 create mode 100644 app/assets/javascripts/discourse/routes/application_route.js

diff --git a/app/assets/javascripts/discourse/controllers/list_controller.js b/app/assets/javascripts/discourse/controllers/list_controller.js
index aa22cb6c8..3a052f72c 100644
--- a/app/assets/javascripts/discourse/controllers/list_controller.js
+++ b/app/assets/javascripts/discourse/controllers/list_controller.js
@@ -18,12 +18,12 @@ Discourse.ListController = Discourse.Controller.extend({
     return Discourse.SiteSettings.top_menu.split("|").map(function(i) {
       return Discourse.NavItem.fromText(i, {
         loggedOn: loggedOn,
-        countSummary: summary
+        hasCategories: hasCategories
       });
     }).filter(function(i) {
       return i !== null;
     });
-  }.property('filterSummary'),
+  }.property(),
 
   /**
     Load a list based on a filter
diff --git a/app/assets/javascripts/discourse/models/nav_item.js b/app/assets/javascripts/discourse/models/nav_item.js
index 7d268d634..fa9278608 100644
--- a/app/assets/javascripts/discourse/models/nav_item.js
+++ b/app/assets/javascripts/discourse/models/nav_item.js
@@ -10,6 +10,7 @@ var validNavNames = ['latest', 'hot', 'categories', 'category', 'favorited', 'un
 var validAnon     = ['latest', 'hot', 'categories', 'category'];
 
 Discourse.NavItem = Discourse.Model.extend({
+  userTrackingStateBinding: Ember.Binding.oneWay('Discourse.currentUser.userTrackingState.messageCount'),
   categoryName: function() {
     var split = this.get('name').split('/');
     return split[0] === 'category' ? split[1] : null;
@@ -21,7 +22,14 @@ Discourse.NavItem = Discourse.Model.extend({
         href = Discourse.getURL("/") + name.replace(' ', '-');
     if (name === 'category') href += "/" + this.get('categoryName');
     return href;
-  }.property('name')
+  }.property('name'),
+
+  count: function() {
+    var state = Discourse.get('currentUser.userTrackingState');
+    if (state) {
+      return state.lookupCount(this.get('name'));
+    }
+  }.property('userTrackingState')
 });
 
 Discourse.NavItem.reopenClass({
@@ -43,7 +51,7 @@ Discourse.NavItem.reopenClass({
       filters: split.splice(1)
     };
 
-    if (countSummary && countSummary[name]) opts.count = countSummary[name];
+    // if (countSummary && countSummary[name]) opts.count = countSummary[name];
 
     return Discourse.NavItem.create(opts);
   }
diff --git a/app/assets/javascripts/discourse/models/topic_list.js b/app/assets/javascripts/discourse/models/topic_list.js
index e5bc0f4ee..c9901fd7c 100644
--- a/app/assets/javascripts/discourse/models/topic_list.js
+++ b/app/assets/javascripts/discourse/models/topic_list.js
@@ -118,7 +118,6 @@ Discourse.TopicList.reopenClass({
         topics: Discourse.TopicList.topicsFrom(result),
         can_create_topic: result.topic_list.can_create_topic,
         more_topics_url: result.topic_list.more_topics_url,
-        filter_summary: result.topic_list.filter_summary,
         draft_key: result.topic_list.draft_key,
         draft_sequence: result.topic_list.draft_sequence,
         draft: result.topic_list.draft,
diff --git a/app/assets/javascripts/discourse/models/user.js b/app/assets/javascripts/discourse/models/user.js
index 68850c912..3ba11f68b 100644
--- a/app/assets/javascripts/discourse/models/user.js
+++ b/app/assets/javascripts/discourse/models/user.js
@@ -314,6 +314,7 @@ Discourse.User.reopenClass({
     });
   },
 
+
   /**
     Checks if given username is valid for this email address
 
diff --git a/app/assets/javascripts/discourse/models/user_tracking_state.js b/app/assets/javascripts/discourse/models/user_tracking_state.js
index 5843d1250..db6cbd413 100644
--- a/app/assets/javascripts/discourse/models/user_tracking_state.js
+++ b/app/assets/javascripts/discourse/models/user_tracking_state.js
@@ -1,16 +1,80 @@
 Discourse.UserTrackingState = Discourse.Model.extend({
-  unreadPosts: function(){
-    return 10;
-  }.property(),
+  init: function(){
+    this._super();
+    this.states = {};
 
-  newPosts: function() {
-    return 10;
-  }.property()
+    var _this = this;
+    setTimeout(function(){
+      console.log("YYYYYYYYYYY");
+      _this.loadStates([{
+        topic_id: 100,
+        last_read_post_number: null
+      }]);
+      _this.set('messageCount', 100);
+    }, 2000);
+  },
+
+  establishChannels: function() {
+
+
+  },
+
+  countNew: function(){
+    var count = 0;
+    $.each(this.states, function(){
+      count += this.last_read_post_number === null ? 1 : 0;
+    });
+    return count;
+  },
+
+  countUnread: function(){
+    var count = 0;
+    $.each(this.states, function(){
+      count += (this.last_read_post_number !== null &&
+                this.last_read_post_number < this.highest_post_number) ? 1 : 0;
+    });
+    return count;
+  },
+
+  countCategory: function(category) {
+    var count = 0;
+    $.each(this.states, function(){
+      if (this.category_name === category) {
+        count += (this.last_read_post_number === null ||
+                  this.last_read_post_number < this.highest_post_number) ? 1 : 0;
+      }
+    });
+    return count;
+  },
+
+  lookupCount: function(name){
+    if(name==="new") {
+      return this.countNew();
+    } else if(name==="unread") {
+      return this.countUnread();
+    } else {
+      var category = name.split("/")[1];
+      if(category) {
+        return this.countCategory(category);
+      }
+    }
+  },
+  loadStates: function (data) {
+    // not exposed
+    var states = this.states;
+
+    data.each(function(row){
+      states["t" + row.topic_id] = row;
+    });
+  }
 });
 
 
 Discourse.UserTrackingState.reopenClass({
-  init: function(data){
-
+  createFromStates: function(data){
+    var instance = Discourse.UserTrackingState.create();
+    instance.loadStates(data);
+    instance.establishChannels();
+    return instance;
   }
 });
diff --git a/app/assets/javascripts/discourse/routes/application_route.js b/app/assets/javascripts/discourse/routes/application_route.js
new file mode 100644
index 000000000..337f3df6e
--- /dev/null
+++ b/app/assets/javascripts/discourse/routes/application_route.js
@@ -0,0 +1,24 @@
+/**
+  The base Application route
+
+  @class ApplicationRoute
+  @extends Discourse.Route
+  @namespace Discourse
+  @module Discourse
+**/
+Discourse.ApplicationRoute = Discourse.Route.extend({
+  setupController: function(controller) {
+    Discourse.set('site', Discourse.Site.create(PreloadStore.get('site')));
+    var currentUser = PreloadStore.get('currentUser');
+    if (currentUser) {
+      var states = currentUser.user_tracking_states;
+      currentUser.user_tracking_states = null;
+
+      Discourse.set('currentUser', Discourse.User.create(currentUser));
+      Discourse.set('currentUser.userTrackingState', Discourse.UserTrackingState.createFromStates(states));
+    }
+    // make sure we delete preloaded data
+    PreloadStore.remove('site');
+    PreloadStore.remove('currentUser');
+  }
+});
diff --git a/app/assets/javascripts/discourse/views/nav_item_view.js b/app/assets/javascripts/discourse/views/nav_item_view.js
index bf54870ad..d4adab7b3 100644
--- a/app/assets/javascripts/discourse/views/nav_item_view.js
+++ b/app/assets/javascripts/discourse/views/nav_item_view.js
@@ -10,12 +10,12 @@ Discourse.NavItemView = Discourse.View.extend({
   tagName: 'li',
   classNameBindings: ['isActive', 'content.hasIcon:has-icon'],
   attributeBindings: ['title'],
+  countBinding: Ember.Binding.oneWay('content.count'),
 
   title: function() {
-    var name = this.get('content.name');
-    var categoryName = this.get('content.categoryName');
-
-    var extra;
+    var categoryName, extra, name;
+    name = this.get('content.name');
+    categoryName = this.get('content.categoryName');
     if (categoryName) {
       extra = { categoryName: categoryName };
       name = "category";
@@ -30,10 +30,17 @@ Discourse.NavItemView = Discourse.View.extend({
 
   hidden: Em.computed.not('content.visible'),
 
+  countChanged: function(){
+    this.rerender();
+  }.observes('count'),
+
   name: function() {
-    var name = this.get('content.name');
-    var categoryName = this.get('content.categoryName');
-    var extra = { count: this.get('content.count') || 0 };
+    var categoryName, extra, name;
+    name = this.get('content.name');
+    categoryName = this.get('content.categoryName');
+    extra = {
+      count: this.get('content.count') || 0
+    };
     if (categoryName) {
       name = 'category';
       extra.categoryName = categoryName.titleize();
diff --git a/app/serializers/topic_list_serializer.rb b/app/serializers/topic_list_serializer.rb
index c6d609cd2..f3bf96cf4 100644
--- a/app/serializers/topic_list_serializer.rb
+++ b/app/serializers/topic_list_serializer.rb
@@ -2,7 +2,7 @@ class TopicListSerializer < ApplicationSerializer
 
   attributes :can_create_topic,
              :more_topics_url,
-             :filter_summary,
+             # :filter_summary,
              :draft,
              :draft_key,
              :draft_sequence,