From 0b8a3ff5da9bdb4ee0fe9f95923fd9eede3b0fcd Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 27 May 2016 12:35:16 -0400 Subject: [PATCH] FIX: Better handling of position when near the top or bottom --- .../components/scrolling-post-stream.js.es6 | 21 +++++++++--------- .../discourse/controllers/topic.js.es6 | 2 +- .../discourse/lib/offset-calculator.js.es6 | 22 +++++++++++++++++-- .../discourse/mixins/docking.js.es6 | 7 +++++- .../discourse/widgets/topic-timeline.js.es6 | 10 ++++----- 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/discourse/components/scrolling-post-stream.js.es6 b/app/assets/javascripts/discourse/components/scrolling-post-stream.js.es6 index a684fea4b5b..5a46a83a40e 100644 --- a/app/assets/javascripts/discourse/components/scrolling-post-stream.js.es6 +++ b/app/assets/javascripts/discourse/components/scrolling-post-stream.js.es6 @@ -88,11 +88,6 @@ export default MountWidget.extend({ const offset = offsetCalculator(); const topCheck = Math.ceil(windowTop + offset); - if (windowTop < offset) { - currentPost = 0; - const $post = $($posts[0]); - percent = windowTop > 0 ? (topCheck - $post.offset().top) / $post.height() : 0; - } // uncomment to debug the eyeline // $('.debug-eyeline').css({ height: '1px', width: '100%', backgroundColor: 'blue', position: 'absolute', top: `${topCheck}px` }); @@ -106,15 +101,15 @@ export default MountWidget.extend({ const viewTop = $post.offset().top; const postHeight = $post.height(); - const viewBottom = viewTop + postHeight; + const viewBottom = Math.ceil(viewTop + postHeight); if (viewTop > viewportBottom) { break; } - if (viewBottom > windowTop && viewTop <= windowBottom) { + if (viewBottom >= windowTop && viewTop <= windowBottom) { onscreen.push(bottomView); } - if (currentPost === null && (viewTop <= topCheck) && (viewBottom > topCheck)) { + if (currentPost === null && (viewTop <= topCheck) && (viewBottom >= topCheck)) { percent = (topCheck - viewTop) / postHeight; currentPost = bottomView; } @@ -163,9 +158,13 @@ export default MountWidget.extend({ this.sendAction('currentPostChanged', { post }); } - if (percent !== null && this._currentPercent !== percent) { - this._currentPercent = percent; - this.sendAction('currentPostScrolled', { percent }); + if (percent !== null) { + if (percent > 1.0) { percent = 1.0; } + + if (this._currentPercent !== percent) { + this._currentPercent = percent; + this.sendAction('currentPostScrolled', { percent }); + } } } else { diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index 102ef91a0ba..147a508b1a3 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -211,7 +211,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { currentPostScrolled(event) { this.appEvents.trigger('topic:current-post-scrolled', { - postNumber: this._progressIndex, + postIndex: this._progressIndex, percent: event.percent }); }, diff --git a/app/assets/javascripts/discourse/lib/offset-calculator.js.es6 b/app/assets/javascripts/discourse/lib/offset-calculator.js.es6 index 9d8e59f96c9..069a9a16521 100644 --- a/app/assets/javascripts/discourse/lib/offset-calculator.js.es6 +++ b/app/assets/javascripts/discourse/lib/offset-calculator.js.es6 @@ -1,8 +1,26 @@ export default function offsetCalculator() { const $header = $('header'); const $title = $('#topic-title'); - const windowHeight = $(window).height() - $title.height(); + const rawWinHeight = $(window).height(); + const windowHeight = rawWinHeight - $title.height(); const expectedOffset = $title.height() - $header.find('.contents').height() + (windowHeight / 5); + const ideal = $header.outerHeight(true) + ((expectedOffset < 0) ? 0 : expectedOffset); - return $header.outerHeight(true) + ((expectedOffset < 0) ? 0 : expectedOffset); + const $container = $('.posts-wrapper'); + const topPos = $container.offset().top; + + const scrollTop = $(window).scrollTop(); + const docHeight = $(document).height(); + const scrollPercent = (scrollTop / (docHeight-rawWinHeight)); + + const inter = topPos - scrollTop + ($container.height() * scrollPercent); + + if (inter > ideal) { + const bottom = $('#topic-bottom').offset().top; + if (bottom > (scrollTop + rawWinHeight)) { + return ideal; + } + } + + return inter; } diff --git a/app/assets/javascripts/discourse/mixins/docking.js.es6 b/app/assets/javascripts/discourse/mixins/docking.js.es6 index 6d897ac1999..7be90d40581 100644 --- a/app/assets/javascripts/discourse/mixins/docking.js.es6 +++ b/app/assets/javascripts/discourse/mixins/docking.js.es6 @@ -8,10 +8,15 @@ export default Ember.Mixin.create({ init() { this._super(); this.queueDockCheck = () => { - Ember.run.debounce(this, this.dockCheck, helper, 5); + Ember.run.debounce(this, this.safeDockCheck, 5); }; }, + safeDockCheck() { + if (this.isDestroyed || this.isDestroying) { return; } + this.dockCheck(helper); + }, + didInsertElement() { this._super(); diff --git a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 index c32db721f88..38d2ccdc705 100644 --- a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 @@ -96,7 +96,7 @@ createWidget('timeline-scrollarea', { const topic = attrs.topic; const postStream = topic.get('postStream'); const total = postStream.get('filteredPostsCount'); - let current = Math.floor(total * percentage); + let current = Math.floor(total * percentage) + 1; if (current < 1) { current = 1; } if (current > total) { current = total; } @@ -168,15 +168,15 @@ createWidget('timeline-scrollarea', { }, topicCurrentPostScrolled(event) { - const { postNumber, percent } = event; + const { postIndex, percent } = event; // If the post number didn't change keep our scroll position - this.state.percentage = this._percentFor(this.attrs.topic, parseFloat(postNumber) + percent); + this.state.percentage = this._percentFor(this.attrs.topic, parseFloat(postIndex) + percent); }, - _percentFor(topic, postNumber) { + _percentFor(topic, postIndex) { const total = topic.get('postStream.filteredPostsCount'); - let result = (postNumber === 1) ? 0.0 : parseFloat(postNumber) / total; + let result = parseFloat(postIndex - 1.0) / total; if (result < 0) { return 0.0; } if (result > 1.0) { return 1.0; }