FEATURE: Show time gap between posts if more than a few days

This commit is contained in:
Robin Ward 2015-06-18 17:06:25 -04:00
parent 4e898c604e
commit 42bd9b6199
10 changed files with 125 additions and 5 deletions

View File

@ -0,0 +1,20 @@
export default Ember.Component.extend({
classNameBindings: [':time-gap'],
render(buffer) {
const gapDays = this.get('gapDays');
let timeGapWords;
if (gapDays < 30) {
timeGapWords = I18n.t('dates.later.x_days', {count: gapDays});
} else if (gapDays < 365) {
const gapMonths = Math.floor(gapDays / 30);
timeGapWords = I18n.t('dates.later.x_months', {count: gapMonths});
} else {
const gapYears = Math.floor(gapDays / 365);
timeGapWords = I18n.t('dates.later.x_years', {count: gapYears});
}
buffer.push("<div class='time-gap-words'>" + timeGapWords + "</div>");
}
});

View File

@ -1,5 +1,21 @@
import RestModel from 'discourse/models/rest';
function calcDayDiff(p1, p2) {
if (!p1) { return; }
const date = p1.get('created_at');
if (date) {
if (p2) {
const lastDate = p2.get('created_at');
if (lastDate) {
const delta = new Date(date).getTime() - new Date(lastDate).getTime();
const days = Math.round(delta / (1000 * 60 * 60 * 24));
p1.set('daysSincePrevious', days);
}
}
}
}
const PostStream = RestModel.extend({
loading: Em.computed.or('loadingAbove', 'loadingBelow', 'loadingFilter', 'stagingPost'),
notLoading: Em.computed.not('loading'),
@ -367,14 +383,22 @@ const PostStream = RestModel.extend({
},
prependPost(post) {
this.get('posts').unshiftObject(this.storePost(post));
const stored = this.storePost(post);
if (stored) {
const posts = this.get('posts');
calcDayDiff(posts.get('firstObject'), stored);
posts.unshiftObject(stored);
}
return post;
},
appendPost(post) {
const stored = this.storePost(post);
if (stored) {
this.get('posts').addObject(stored);
const posts = this.get('posts');
calcDayDiff(stored, posts.get('lastObject'));
posts.addObject(stored);
}
return post;
},
@ -627,7 +651,7 @@ const PostStream = RestModel.extend({
const postId = Em.get(post, 'id');
if (postId) {
const postIdentityMap = this.get('postIdentityMap'),
existing = postIdentityMap.get(post.get('id'));
existing = postIdentityMap.get(post.get('id'));
if (existing) {
// If the post is in the identity map, update it and return the old reference.

View File

@ -27,6 +27,10 @@ const Post = RestModel.extend({
notDeleted: Em.computed.not('deleted'),
userDeleted: Em.computed.empty('user_id'),
hasTimeGap: function() {
return (this.get('daysSincePrevious') || 0) > Discourse.SiteSettings.show_time_gap_days;
}.property('daysSincePrevious'),
showName: function() {
const name = this.get('name');
return name && (name !== this.get('username')) && Discourse.SiteSettings.display_name_on_posts;

View File

@ -0,0 +1,5 @@
<div class='time-gap'>
<div class='time-gap-days'>
{{gapInWords}}
</div>
</div>

View File

@ -1,5 +1,9 @@
{{post-gap post=this postStream=controller.model.postStream before="true"}}
{{#if hasTimeGap}}
{{time-gap gapDays=daysSincePrevious}}
{{/if}}
<div class='row'>
{{view 'reply-history' content=replyHistory}}
</div>

View File

@ -717,6 +717,21 @@ $topic-avatar-width: 45px;
width: calc(#{$topic-avatar-width} + #{$topic-body-width} + 2 * #{$topic-body-width-padding});
}
.time-gap {
width: 755px;
border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
}
.time-gap-words {
display: inline-block;
padding: 0.5em 1em;
margin: 0.5em 0 0.5em 56px;
text-transform: uppercase;
font-weight: bold;
font-size: 0.8em;
background-color: dark-light-diff($primary, $secondary, 90%, -60%);
color: lighten($primary, 30%);
}
.posts-wrapper {
position: relative;
-webkit-font-smoothing: subpixel-antialiased;

View File

@ -92,6 +92,16 @@ en:
x_days:
one: "1 day ago"
other: "%{count} days ago"
later:
x_days:
one: "1 day layer"
other: "%{count} days later"
x_months:
one: "1 month layer"
other: "%{count} months later"
x_years:
one: "1 year layer"
other: "%{count} years later"
share:
topic: 'share a link to this topic'
post: 'post #%{postNumber}'

View File

@ -1120,6 +1120,7 @@ en:
full_name_required: "Full name is a required field of a user's profile."
enable_names: "Show the user's full name on their profile, user card, and emails. Disable to hide full name everywhere."
display_name_on_posts: "Show a user's full name on their posts in addition to their @username."
show_time_gap_days: "If two posts are made this many days apart, display the time gap in the topic."
invites_per_page: "Default invites shown on the user page."
short_progress_text_threshold: "After the number of posts in a topic goes above this number, the progress bar will only show the current post number. If you change the progress bar's width, you may need to change this value."
default_code_lang: "Default programming language syntax highlighting applied to GitHub code blocks (lang-auto, ruby, python etc.)"

View File

@ -415,6 +415,9 @@ posting:
display_name_on_posts:
client: true
default: false
show_time_gap_days:
default: 4
client: true
short_progress_text_threshold:
client: true
default: 10000

View File

@ -26,6 +26,40 @@ test('defaults', function() {
present(postStream.get('topic'));
});
test('daysSincePrevious when appending', function(assert) {
const postStream = buildStream(10000001, [1,2,3]);
const store = postStream.store;
const p1 = store.createRecord('post', {id: 1, post_number: 1, created_at: "2015-05-29T18:17:35.868Z"}),
p2 = store.createRecord('post', {id: 2, post_number: 2, created_at: "2015-06-01T01:07:25.761Z"}),
p3 = store.createRecord('post', {id: 3, post_number: 3, created_at: "2015-06-02T01:07:25.761Z"});
postStream.appendPost(p1);
postStream.appendPost(p2);
postStream.appendPost(p3);
assert.ok(!p1.get('daysSincePrevious'));
assert.equal(p2.get('daysSincePrevious'), 2);
assert.equal(p3.get('daysSincePrevious'), 1);
});
test('daysSincePrevious when prepending', function(assert) {
const postStream = buildStream(10000001, [1,2,3]);
const store = postStream.store;
const p1 = store.createRecord('post', {id: 1, post_number: 1, created_at: "2015-05-29T18:17:35.868Z"}),
p2 = store.createRecord('post', {id: 2, post_number: 2, created_at: "2015-06-01T01:07:25.761Z"}),
p3 = store.createRecord('post', {id: 3, post_number: 3, created_at: "2015-06-02T01:07:25.761Z"});
postStream.prependPost(p3);
postStream.prependPost(p2);
postStream.prependPost(p1);
assert.ok(!p1.get('daysSincePrevious'));
assert.equal(p2.get('daysSincePrevious'), 2);
assert.equal(p3.get('daysSincePrevious'), 1);
});
test('appending posts', function() {
const postStream = buildStream(4567, [1, 3, 4]);
const store = postStream.store;
@ -96,8 +130,8 @@ test("removePosts", function() {
const store = postStream.store;
const p1 = store.createRecord('post', {id: 1, post_number: 2}),
p2 = store.createRecord('post', {id: 2, post_number: 3}),
p3 = store.createRecord('post', {id: 3, post_number: 4});
p2 = store.createRecord('post', {id: 2, post_number: 3}),
p3 = store.createRecord('post', {id: 3, post_number: 4});
postStream.appendPost(p1);
postStream.appendPost(p2);