mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
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:
parent
d7f62f7148
commit
3405253405
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -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"}}>
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 }
|
||||||
|
Loading…
Reference in New Issue
Block a user