FEATURE: rush posting read times for newly read posts

FEATURE: "read" indicator on posts
CHANGE: anon is now assumed to have read everything
This commit is contained in:
Sam 2014-06-03 11:48:52 +10:00
parent d7f62f7148
commit 3405253405
9 changed files with 57 additions and 18 deletions

View File

@ -550,20 +550,22 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
} }
}.observes('currentPost'), }.observes('currentPost'),
sawObjects: function(posts) { readPosts: function(topicId, postNumbers) {
if (posts) { var postStream = this.get('postStream');
var self = this,
lastReadPostNumber = this.get('last_read_post_number');
posts.forEach(function(post) { if(this.get('postStream.topic.id') === topicId){
var postNumber = post.get('post_number'); _.each(postStream.get('posts'), function(post){
if (postNumber > lastReadPostNumber) { // optimise heavy loop
lastReadPostNumber = postNumber; // TODO identity map for postNumber
if(_.include(postNumbers,post.post_number) && !post.read){
post.set("read", true);
} }
post.set('read', true);
}); });
self.set('last_read_post_number', lastReadPostNumber);
var max = _.max(postNumbers);
if(max > this.get('last_read_post_number')){
this.set('last_read_post_number', max);
}
} }
}, },

View File

@ -16,7 +16,7 @@ Discourse.ScreenTrack = Ember.Object.extend({
this.reset(); this.reset();
}, },
start: function(topicId) { start: function(topicId, topicController) {
var currentTopicId = this.get('topicId'); var currentTopicId = this.get('topicId');
if (currentTopicId && (currentTopicId !== topicId)) { if (currentTopicId && (currentTopicId !== topicId)) {
this.tick(); this.tick();
@ -34,6 +34,7 @@ Discourse.ScreenTrack = Ember.Object.extend({
} }
this.set('topicId', topicId); this.set('topicId', topicId);
this.set('topicController', topicController);
}, },
stop: function() { stop: function() {
@ -46,6 +47,7 @@ Discourse.ScreenTrack = Ember.Object.extend({
this.flush(); this.flush();
this.reset(); this.reset();
this.set('topicId', null); this.set('topicId', null);
this.set('topicController', null);
if (this.get('interval')) { if (this.get('interval')) {
clearInterval(this.get('interval')); clearInterval(this.get('interval'));
this.set('interval', null); this.set('interval', null);
@ -87,7 +89,8 @@ Discourse.ScreenTrack = Ember.Object.extend({
if (!Discourse.User.current()) return; if (!Discourse.User.current()) return;
var newTimings = {}, var newTimings = {},
totalTimings = this.get('totalTimings'); totalTimings = this.get('totalTimings'),
self = this;
_.each(this.get('timings'), function(timing) { _.each(this.get('timings'), function(timing) {
if (!totalTimings[timing.postNumber]) if (!totalTimings[timing.postNumber])
@ -126,6 +129,14 @@ Discourse.ScreenTrack = Ember.Object.extend({
headers: { headers: {
'X-SILENCE-LOGGER': 'true' 'X-SILENCE-LOGGER': 'true'
} }
}).then(function(){
var controller = self.get('topicController');
if(controller){
var postNumbers = Object.keys(newTimings).map(function(v){
return parseInt(v,10);
});
controller.readPosts(topicId, postNumbers);
}
}); });
this.set('topicTime', 0); this.set('topicTime', 0);
@ -145,7 +156,16 @@ Discourse.ScreenTrack = Ember.Object.extend({
var diff = new Date().getTime() - this.get('lastTick'); var diff = new Date().getTime() - this.get('lastTick');
this.set('lastFlush', this.get('lastFlush') + diff); this.set('lastFlush', this.get('lastFlush') + diff);
this.set('lastTick', new Date().getTime()); this.set('lastTick', new Date().getTime());
if (this.get('lastFlush') > (Discourse.SiteSettings.flush_timings_secs * 1000)) {
var totalTimings = this.get('totalTimings'), timings = this.get('timings');
var nextFlush = Discourse.SiteSettings.flush_timings_secs * 1000;
// rush new post numbers
var rush = _.any(_.filter(timings, function(t){return t.time>0;}), function(t){
return !totalTimings[t.postNumber];
});
if (this.get('lastFlush') > nextFlush || rush) {
this.flush(); this.flush();
} }

View File

@ -180,7 +180,7 @@ Discourse.TopicRoute = Discourse.Route.extend({
controller.subscribe(); controller.subscribe();
// We reset screen tracking every time a topic is entered // We reset screen tracking every time a topic is entered
Discourse.ScreenTrack.current().start(model.get('id')); Discourse.ScreenTrack.current().start(model.get('id'), controller);
} }
}); });

View File

@ -57,6 +57,7 @@
{{/if}} {{/if}}
</div> </div>
{{/if}} {{/if}}
<div {{bind-attr class=":read-state read"}} title="{{i18n post.unread}}"><i class='fa fa-circle'></i></div>
</div> </div>
<div {{bind-attr class=":select-posts controller.multiSelect::hidden"}}> <div {{bind-attr class=":select-posts controller.multiSelect::hidden"}}>

View File

@ -51,7 +51,7 @@ h1 .topic-statuses .topic-status i {
.reply-to-tab { .reply-to-tab {
position: absolute; position: absolute;
right: 350px; right: 375px;
z-index: 400; z-index: 400;
padding: 13px 6px 5px; padding: 13px 6px 5px;
border-top: 1px solid scale-color-diff(); border-top: 1px solid scale-color-diff();
@ -1080,3 +1080,17 @@ span.highlighted {
.username.new-user a { .username.new-user a {
color: scale-color($primary, $lightness: 70%); color: scale-color($primary, $lightness: 70%);
} }
.read-state {
color: scale-color($tertiary, $lightness: 50%);
float: right;
margin-right: 10px;
margin-top: 1px;
font-size: 10px;
}
.read-state.read {
opacity: 0;
-webkit-transition: opacity 1s ease-out;
transition: opacity 1s ease-out;
}

View File

@ -940,6 +940,7 @@ en:
other: "{{count}} posts hidden" other: "{{count}} posts hidden"
more_links: "{{count}} more..." more_links: "{{count}} more..."
unread: "Post is unread"
has_replies: has_replies:
one: "Reply" one: "Reply"
other: "Replies" other: "Replies"

View File

@ -183,6 +183,7 @@ class TopicView
end end
def read?(post_number) def read?(post_number)
return true unless @user
read_posts_set.include?(post_number) read_posts_set.include?(post_number)
end end

View File

@ -169,8 +169,8 @@ describe TopicView do
context '.read?' do context '.read?' do
it 'tracks correctly' do it 'tracks correctly' do
# anon has nothing # anon is assumed to have read everything
TopicView.new(topic.id).read?(1).should be_false TopicView.new(topic.id).read?(1).should be_true
# random user has nothing # random user has nothing
topic_view.read?(1).should be_false topic_view.read?(1).should be_false

View File

@ -88,7 +88,7 @@ describe SiteSetting do
end end
describe "top_menu" do describe "top_menu" do
before(:each) { SiteSetting.stubs(:top_menu).returns('one,-nope|two|three,-not|four,ignored|category/xyz') } before(:each) { SiteSetting.top_menu = 'one,-nope|two|three,-not|four,ignored|category/xyz' }
describe "items" do describe "items" do
let(:items) { SiteSetting.top_menu_items } let(:items) { SiteSetting.top_menu_items }