diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index 010b60707dc..ce14d2903ae 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -707,6 +707,12 @@ export default Ember.Controller.extend(bufferedProperty("model"), { }); }, + jumpEnd() { + DiscourseURL.routeTo(this.get("model.lastPostUrl"), { + jumpEnd: true + }); + }, + jumpUnread() { this._jumpToPostId(this.get("model.last_read_post_id")); }, diff --git a/app/assets/javascripts/discourse/lib/url.js.es6 b/app/assets/javascripts/discourse/lib/url.js.es6 index e25f0a77fe2..34bb600e07a 100644 --- a/app/assets/javascripts/discourse/lib/url.js.es6 +++ b/app/assets/javascripts/discourse/lib/url.js.es6 @@ -93,6 +93,12 @@ const DiscourseURL = Ember.Object.extend({ let elementId; let holder; + if (opts.jumpEnd) { + $(window).scrollTop($(document).height() - $(window).height()); + _transitioning = false; + return; + } + if (postNumber === 1 && !opts.anchor) { $(window).scrollTop(0); _transitioning = false; @@ -347,7 +353,8 @@ const DiscourseURL = Ember.Object.extend({ this.appEvents.trigger("post:highlight", closest); const jumpOpts = { - skipIfOnScreen: routeOpts.skipIfOnScreen + skipIfOnScreen: routeOpts.skipIfOnScreen, + jumpEnd: routeOpts.jumpEnd }; const m = /#.+$/.exec(path); diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs index c4122b52fb3..07691dfa0f5 100644 --- a/app/assets/javascripts/discourse/templates/topic.hbs +++ b/app/assets/javascripts/discourse/templates/topic.hbs @@ -124,6 +124,7 @@ jumpToPost=(action "jumpToPost") jumpTop=(action "jumpTop") jumpBottom=(action "jumpBottom") + jumpEnd=(action "jumpEnd") jumpToPostPrompt=(action "jumpToPostPrompt") jumpToIndex=(action "jumpToIndex") replyToPost=(action "replyToPost") diff --git a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 index ef8bfed2e3f..6fa55bcb607 100644 --- a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 @@ -148,7 +148,8 @@ createWidget("timeline-scrollarea", { const postStream = topic.get("postStream"); const total = postStream.get("filteredPostsCount"); - const current = clamp(Math.floor(total * percentage) + 1, 1, total); + const scrollPosition = clamp(Math.floor(total * percentage), 0, total) + 1; + const current = clamp(scrollPosition, 1, total); const daysAgo = postStream.closestDaysAgoFor(current); let date; @@ -168,6 +169,7 @@ createWidget("timeline-scrollarea", { const result = { current, + scrollPosition, total, date, lastRead: null, @@ -183,9 +185,9 @@ createWidget("timeline-scrollarea", { result.lastReadPercentage = this._percentFor(topic, idx); } - if (this.state.position !== result.current) { - this.state.position = result.current; - this.sendWidgetAction("updatePosition", result.current); + if (this.state.position !== result.scrollPosition) { + this.state.position = result.scrollPosition; + this.sendWidgetAction("updatePosition", result.position, result.scrollPosition); } return result; @@ -259,7 +261,11 @@ createWidget("timeline-scrollarea", { const position = this.position(); this.state.scrolledPost = position.current; - this.sendWidgetAction("jumpToIndex", position.current); + if (position.current === position.scrollPosition) { + this.sendWidgetAction("jumpToIndex", position.current); + } else { + this.sendWidgetAction("jumpEnd"); + } }, topicCurrentPostScrolled(event) { @@ -380,25 +386,25 @@ export default createWidget("topic-timeline", { return { position: null, excerpt: null }; }, - updatePosition(pos) { + updatePosition(postIdx, scrollPosition) { if (!this.attrs.fullScreen) { return; } - this.state.position = pos; + this.state.position = scrollPosition; this.state.excerpt = ""; const stream = this.attrs.topic.get("postStream"); // a little debounce to avoid flashing Ember.run.later(() => { - if (!this.state.position === pos) { + if (!this.state.position === scrollPosition) { return; } // we have an off by one, stream is zero based, - // pos is 1 based - stream.excerpt(pos - 1).then(info => { - if (info && this.state.position === pos) { + // postIdx is 1 based + stream.excerpt(postIdx - 1).then(info => { + if (info && this.state.position === scrollPosition) { let excerpt = ""; if (info.username) {