diff --git a/app/assets/javascripts/discourse/controllers/list_controller.js b/app/assets/javascripts/discourse/controllers/list_controller.js
index 3a052f72c..761696d5d 100644
--- a/app/assets/javascripts/discourse/controllers/list_controller.js
+++ b/app/assets/javascripts/discourse/controllers/list_controller.js
@@ -36,6 +36,8 @@ Discourse.ListController = Discourse.Controller.extend({
var listController = this;
this.set('loading', true);
+ var trackingState = Discourse.get('currentUser.userTrackingState');
+
if (filterMode === 'categories') {
return Discourse.CategoryList.list(filterMode).then(function(items) {
listController.setProperties({
@@ -46,6 +48,10 @@ Discourse.ListController = Discourse.Controller.extend({
draft_key: items.draft_key,
draft_sequence: items.draft_sequence
});
+ if(trackingState) {
+ trackingState.sync(items, filterMode);
+ trackingState.trackIncoming(filterMode);
+ }
return items;
});
}
@@ -63,7 +69,11 @@ Discourse.ListController = Discourse.Controller.extend({
draft: items.draft,
draft_key: items.draft_key,
draft_sequence: items.draft_sequence
- })
+ });
+ if(trackingState) {
+ trackingState.sync(items, filterMode);
+ trackingState.trackIncoming(filterMode);
+ }
return items;
});
},
diff --git a/app/assets/javascripts/discourse/controllers/list_topics_controller.js b/app/assets/javascripts/discourse/controllers/list_topics_controller.js
index 36ec590c0..3cf53a7de 100644
--- a/app/assets/javascripts/discourse/controllers/list_topics_controller.js
+++ b/app/assets/javascripts/discourse/controllers/list_topics_controller.js
@@ -8,7 +8,6 @@
**/
Discourse.ListTopicsController = Discourse.ObjectController.extend({
needs: ['list', 'composer', 'modal'],
-
rankDetailsVisible: false,
// If we're changing our channel
@@ -16,25 +15,6 @@ Discourse.ListTopicsController = Discourse.ObjectController.extend({
latest: Ember.computed.equal('filter', 'latest'),
- filterModeChanged: function() {
- // Unsubscribe from a previous channel if necessary
- var previousChannel = this.get('previousChannel');
- if (previousChannel) {
- Discourse.MessageBus.unsubscribe("/" + previousChannel);
- this.set('previousChannel', null);
- }
-
- var filterMode = this.get('controllers.list.filterMode');
- if (!filterMode) return;
-
- var listTopicsController = this;
- Discourse.MessageBus.subscribe("/" + filterMode, function(data) {
- return listTopicsController.get('content').insert(data);
- });
- this.set('previousChannel', filterMode);
-
- }.observes('controllers.list.filterMode'),
-
draftLoaded: function() {
var draft = this.get('content.draft');
if (draft) {
@@ -75,11 +55,11 @@ Discourse.ListTopicsController = Discourse.ObjectController.extend({
// Show newly inserted topics
showInserted: function(e) {
- // Move inserted into topics
- this.get('topics').unshiftObjects(this.get('inserted'));
+ var tracker = Discourse.get('currentUser.userTrackingState');
- // Clear inserted
- this.set('inserted', Em.A());
+ // Move inserted into topics
+ this.get('content').loadBefore(tracker.get('newIncoming'));
+ tracker.resetTracking();
return false;
},
diff --git a/app/assets/javascripts/discourse/models/topic_list.js b/app/assets/javascripts/discourse/models/topic_list.js
index c9901fd7c..222db1c82 100644
--- a/app/assets/javascripts/discourse/models/topic_list.js
+++ b/app/assets/javascripts/discourse/models/topic_list.js
@@ -9,31 +9,36 @@
Discourse.TopicList = Discourse.Model.extend({
+ forEachNew: function(topics, callback) {
+ var topicIds = [];
+ this.get('topics').each(function(t) {
+ topicIds[t.get('id')] = true;
+ });
+
+ topics.each(function(t) {
+ if(!topicIds[t.id]) {
+ callback(t);
+ }
+ });
+ },
+
loadMoreTopics: function() {
var moreUrl, _this = this;
if (moreUrl = this.get('more_topics_url')) {
Discourse.URL.replaceState(Discourse.getURL("/") + (this.get('filter')) + "/more");
return Discourse.ajax({url: moreUrl}).then(function (result) {
- var newTopics, topicIds, topics, topicsAdded = 0;
+ var newTopics, topics, topicsAdded = 0;
if (result) {
// the new topics loaded from the server
newTopics = Discourse.TopicList.topicsFrom(result);
- // the current topics
- topics = _this.get('topics');
- // keeps track of the ids of the current topics
- topicIds = [];
- topics.each(function(t) {
- topicIds[t.get('id')] = true;
- });
- // add new topics to the list of current topics if not already present
- newTopics.each(function(t) {
- if (!topicIds[t.get('id')]) {
- // highlight the first of the new topics so we can get a visual feedback
- t.set('highlight', topicsAdded++ === 0);
- return topics.pushObject(t);
- }
+ topics = _this.get("topics");
+
+ _this.forEachNew(newTopics, function(t) {
+ t.set('highlight', topicsAdded++ === 0);
+ topics.pushObject(t);
});
+
_this.set('more_topics_url', result.topic_list.more_topics_url);
Discourse.set('transient.topicsList', _this);
}
@@ -47,15 +52,35 @@ Discourse.TopicList = Discourse.Model.extend({
}
},
- insert: function(json) {
- var newTopic = Discourse.TopicList.decodeTopic(json);
- newTopic.setProperties({
- unseen: true,
- highlight: true
- });
- this.get('inserted').unshiftObject(newTopic);
- }
+ // loads topics with these ids "before" the current topics
+ loadBefore: function(topic_ids){
+ // filter out any existing topics
+
+ var _this = this;
+ var url = Discourse.getURL("/") + (this.get('filter')) + "?topic_ids=" + topic_ids.join(",");
+ return Discourse.ajax({url: url}).then(function (result) {
+ if (result) {
+ // the new topics loaded from the server
+ var newTopics = Discourse.TopicList.topicsFrom(result);
+
+ var mapped = topic_ids.map(function(id){
+ return newTopics.find(function(t){ return t.id === id; });
+ });
+
+ var topicsAdded = 0;
+ var topics = _this.get("topics");
+
+ // add new topics to the list of current topics if not already present
+ _this.forEachNew(mapped, function(t) {
+ // highlight the first of the new topics so we can get a visual feedback
+ t.set('highlight', topicsAdded++ === 0);
+ topics.insertAt(0,t);
+ });
+ Discourse.set('transient.topicsList', _this);
+ }
+ });
+ }
});
Discourse.TopicList.reopenClass({
diff --git a/app/assets/javascripts/discourse/models/user_tracking_state.js b/app/assets/javascripts/discourse/models/user_tracking_state.js
index db6cbd413..a0297ad20 100644
--- a/app/assets/javascripts/discourse/models/user_tracking_state.js
+++ b/app/assets/javascripts/discourse/models/user_tracking_state.js
@@ -1,22 +1,110 @@
Discourse.UserTrackingState = Discourse.Model.extend({
+ messageCount: 0,
+
init: function(){
this._super();
- this.states = {};
+ this.unreadSequence = [];
+ this.newSequence = [];
- var _this = this;
- setTimeout(function(){
- console.log("YYYYYYYYYYY");
- _this.loadStates([{
- topic_id: 100,
- last_read_post_number: null
- }]);
- _this.set('messageCount', 100);
- }, 2000);
+ this.states = {};
},
establishChannels: function() {
+ var tracker = this;
+ var process = function(data){
+ if (data.message_type === "delete") {
+ tracker.removeTopic(data.topic_id);
+ }
+ if (data.message_type === "new_topic") {
+ tracker.states["t" + data.topic_id] = data.payload;
+ tracker.notify(data);
+ }
+
+ tracker.incrementMessageCount();
+ };
+
+ Discourse.MessageBus.subscribe("/new", process);
+ Discourse.MessageBus.subscribe("/unread/" + Discourse.currentUser.id, process);
+ },
+
+ notify: function(data){
+ if (!this.newIncoming) { return; }
+
+ if ((this.filter === "latest" || this.filter === "new") && data.message_type === "new_topic" ) {
+ this.newIncoming.push(data.topic_id);
+ }
+ this.set("incomingCount", this.newIncoming.length);
+ },
+
+ resetTracking: function(){
+ this.newIncoming = [];
+ this.set("incomingCount", 0);
+ },
+
+ // track how many new topics came for this filter
+ trackIncoming: function(filter) {
+ this.newIncoming = [];
+ this.filter = filter;
+ this.set("incomingCount", 0);
+ },
+
+ hasIncoming: function(){
+ var count = this.get('incomingCount');
+ return count && count > 0;
+ }.property('incomingCount'),
+
+ removeTopic: function(topic_id) {
+ delete this.states["t" + topic_id];
+ },
+
+ sync: function(list, filter){
+ var tracker = this;
+
+ if(filter === "new" && !list.more_topics_url){
+ // scrub all new rows and reload from list
+ $.each(this.states, function(){
+ if(this.last_read_post_number === null) {
+ tracker.removeTopic(this.topic_id);
+ }
+ });
+ }
+
+ if(filter === "unread" && !list.more_topics_url){
+ // scrub all new rows and reload from list
+ $.each(this.states, function(){
+ if(this.last_read_post_number !== null) {
+ tracker.removeTopic(this.topic_id);
+ }
+ });
+ }
+
+ $.each(list.topics, function(){
+ var row = {};
+ var topic = this;
+
+ row.topic_id = topic.id;
+ if(topic.unseen) {
+ row.last_read_post_number = null;
+ } else {
+ row.last_read_post_number = topic.last_read_post_number;
+ }
+ row.highest_post_number = topic.highest_post_number;
+ if (topic.category) {
+ row.category_name = topic.category.name;
+ }
+
+ if (row.last_read_post_number === null || row.highest_post_number > row.last_read_post_number) {
+ tracker.states["t" + topic.id] = row;
+ }
+ });
+
+ this.incrementMessageCount();
+ },
+
+ incrementMessageCount: function() {
+ this.set("messageCount", this.get("messageCount") + 1);
},
countNew: function(){
diff --git a/app/assets/javascripts/discourse/templates/list/topics.js.handlebars b/app/assets/javascripts/discourse/templates/list/topics.js.handlebars
index 8d0bd897f..7ad5eaa80 100644
--- a/app/assets/javascripts/discourse/templates/list/topics.js.handlebars
+++ b/app/assets/javascripts/discourse/templates/list/topics.js.handlebars
@@ -1,7 +1,7 @@
{{#unless loading}}
{{#if loaded}}
- {{#if topics.length}}
+ {{#if view.showTable}}
{{#if canViewRankDetails}}