mirror of
https://github.com/discourse/discourse.git
synced 2024-12-01 21:19:41 -06:00
FIX: Much less jankiness on the scroller
This commit is contained in:
parent
717999b302
commit
5fc47e6942
@ -1,3 +1,5 @@
|
||||
import { scrollTopFor } from 'discourse/lib/offset-calculator';
|
||||
|
||||
// Dear traveller, you are entering a zone where we are at war with the browser
|
||||
// the browser is insisting on positioning scrollTop per the location it was in
|
||||
// the past, we are insisting on it being where we want it to be
|
||||
@ -30,14 +32,10 @@ export default class LockOn {
|
||||
}
|
||||
|
||||
elementTop() {
|
||||
const offsetCalculator = this.options.offsetCalculator;
|
||||
if (this.offsetTop === null) {
|
||||
this.offsetTop = offsetCalculator ? offsetCalculator() : 0;
|
||||
}
|
||||
|
||||
const selected = $(this.selector);
|
||||
if (selected && selected.offset && selected.offset()) {
|
||||
return selected.offset().top - this.offsetTop;
|
||||
const result = selected.offset().top;
|
||||
return result - Math.round(scrollTopFor(result));
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,10 +51,11 @@ export default class LockOn {
|
||||
$(window).scrollTop(previousTop);
|
||||
|
||||
let i = 0;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
i = i + 1;
|
||||
|
||||
const top = this.elementTop();
|
||||
let top = this.elementTop();
|
||||
const scrollTop = $(window).scrollTop();
|
||||
|
||||
if (typeof(top) === "undefined" || isNaN(top)) {
|
||||
|
@ -1,4 +1,14 @@
|
||||
export default function offsetCalculator() {
|
||||
// TODO: This is quite ugly but seems reasonably fast? Maybe refactor
|
||||
// this out before we merge into stable.
|
||||
export function scrollTopFor(y) {
|
||||
let off = 0;
|
||||
for (let i=0; i<3; i++) {
|
||||
off = offsetCalculator(y - off);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
export default function offsetCalculator(y) {
|
||||
const $header = $('header');
|
||||
const $title = $('#topic-title');
|
||||
const rawWinHeight = $(window).height();
|
||||
@ -9,7 +19,7 @@ export default function offsetCalculator() {
|
||||
const $container = $('.posts-wrapper');
|
||||
const topPos = $container.offset().top;
|
||||
|
||||
const scrollTop = $(window).scrollTop();
|
||||
const scrollTop = y || $(window).scrollTop();
|
||||
const docHeight = $(document).height();
|
||||
const scrollPercent = (scrollTop / (docHeight-rawWinHeight));
|
||||
|
||||
@ -17,7 +27,11 @@ export default function offsetCalculator() {
|
||||
|
||||
if (inter > ideal) {
|
||||
const bottom = $('#topic-bottom').offset().top;
|
||||
if (bottom > (scrollTop + rawWinHeight)) {
|
||||
const switchPos = bottom - rawWinHeight;
|
||||
if (scrollTop > switchPos) {
|
||||
const p = Math.max(Math.min((scrollTop + inter - switchPos) / rawWinHeight, 1.0), 0.0);
|
||||
return ((1 - p) * ideal) + (p * inter);
|
||||
} else {
|
||||
return ideal;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ const DiscourseURL = Ember.Object.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
const lockon = new LockOn(holderId, { offsetCalculator });
|
||||
const lockon = new LockOn(holderId);
|
||||
const holder = $(holderId);
|
||||
|
||||
if (holder.length > 0 && opts && opts.skipIfOnScreen){
|
||||
|
@ -7,6 +7,10 @@ const SCROLLAREA_HEIGHT = 300;
|
||||
const SCROLLER_HEIGHT = 50;
|
||||
const SCROLLAREA_REMAINING = SCROLLAREA_HEIGHT - SCROLLER_HEIGHT;
|
||||
|
||||
function clamp(p, min=0.0, max=1.0) {
|
||||
return Math.max(Math.min(p, max), min);
|
||||
}
|
||||
|
||||
createWidget('timeline-last-read', {
|
||||
tagName: 'div.timeline-last-read',
|
||||
|
||||
@ -96,10 +100,8 @@ createWidget('timeline-scrollarea', {
|
||||
const topic = attrs.topic;
|
||||
const postStream = topic.get('postStream');
|
||||
const total = postStream.get('filteredPostsCount');
|
||||
let current = Math.floor(total * percentage) + 1;
|
||||
|
||||
if (current < 1) { current = 1; }
|
||||
if (current > total) { current = total; }
|
||||
const current = clamp(Math.floor(total * percentage) + 1, 1, total);
|
||||
|
||||
const daysAgo = postStream.closestDaysAgoFor(current);
|
||||
const date = new Date();
|
||||
@ -155,15 +157,24 @@ createWidget('timeline-scrollarea', {
|
||||
const $area = $('.timeline-scrollarea');
|
||||
const areaTop = $area.offset().top;
|
||||
|
||||
let percentage = parseFloat(y - areaTop) / $area.height();
|
||||
if (percentage > 1.0) { percentage = 1.0; };
|
||||
if (percentage < 0.0) { percentage = 0.0; };
|
||||
const topic = this.attrs.topic;
|
||||
const postStream = topic.get('postStream');
|
||||
const total = postStream.get('filteredPostsCount');
|
||||
const percentage = clamp(parseFloat(y - areaTop) / $area.height());
|
||||
const current = clamp(Math.floor(total * percentage) + 1, 1, total);
|
||||
|
||||
this.state.percentage = percentage;
|
||||
// If viewing the last post consider it 100%
|
||||
if (current === total) {
|
||||
this.state.percentage = 1.0;
|
||||
} else {
|
||||
this.state.percentage = this._percentFor(topic, parseFloat(current));
|
||||
}
|
||||
},
|
||||
|
||||
commit() {
|
||||
const position = this.position();
|
||||
this.state.scrolledPost = position.current;
|
||||
|
||||
this.sendWidgetAction('jumpToIndex', position.current);
|
||||
},
|
||||
|
||||
@ -171,16 +182,14 @@ createWidget('timeline-scrollarea', {
|
||||
const { postIndex, percent } = event;
|
||||
|
||||
// If the post number didn't change keep our scroll position
|
||||
this.state.percentage = this._percentFor(this.attrs.topic, parseFloat(postIndex) + percent);
|
||||
if (this.state.scrolledPost !== postIndex) {
|
||||
this.state.percentage = this._percentFor(this.attrs.topic, parseFloat(postIndex) + percent);
|
||||
}
|
||||
},
|
||||
|
||||
_percentFor(topic, postIndex) {
|
||||
const total = topic.get('postStream.filteredPostsCount');
|
||||
let result = parseFloat(postIndex - 1.0) / total;
|
||||
|
||||
if (result < 0) { return 0.0; }
|
||||
if (result > 1.0) { return 1.0; }
|
||||
return result;
|
||||
return clamp(parseFloat(postIndex - 1.0) / total);
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user