mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-07-05 11:43:16 +00:00
![Jermolene](/assets/img/avatar_default.png)
The previous fix changed the scrolling behaviour such that it only scrolled to the top of a tiddler if the tiddler was entirely offscreen. It wasn’t entirely satisfactory because scrolling was prevented even if only a few pixels of a tiddler are in view. This commit ensures that the scroll does occur if less than 50 pixels of the target is in view
119 lines
3.8 KiB
JavaScript
119 lines
3.8 KiB
JavaScript
/*\
|
|
title: $:/core/modules/utils/dom/scroller.js
|
|
type: application/javascript
|
|
module-type: utils
|
|
|
|
Module that creates a $tw.utils.Scroller object prototype that manages scrolling in the browser
|
|
|
|
\*/
|
|
(function(){
|
|
|
|
/*jslint node: true, browser: true */
|
|
/*global $tw: false */
|
|
"use strict";
|
|
|
|
/*
|
|
Event handler for when the `tm-scroll` event hits the document body
|
|
*/
|
|
var PageScroller = function() {
|
|
this.idRequestFrame = null;
|
|
this.requestAnimationFrame = window.requestAnimationFrame ||
|
|
window.webkitRequestAnimationFrame ||
|
|
window.mozRequestAnimationFrame ||
|
|
function(callback) {
|
|
return window.setTimeout(callback, 1000/60);
|
|
};
|
|
this.cancelAnimationFrame = window.cancelAnimationFrame ||
|
|
window.webkitCancelAnimationFrame ||
|
|
window.webkitCancelRequestAnimationFrame ||
|
|
window.mozCancelAnimationFrame ||
|
|
window.mozCancelRequestAnimationFrame ||
|
|
function(id) {
|
|
window.clearTimeout(id);
|
|
};
|
|
};
|
|
|
|
PageScroller.prototype.cancelScroll = function() {
|
|
if(this.idRequestFrame) {
|
|
this.cancelAnimationFrame.call(window,this.idRequestFrame);
|
|
this.idRequestFrame = null;
|
|
}
|
|
};
|
|
|
|
/*
|
|
Handle an event
|
|
*/
|
|
PageScroller.prototype.handleEvent = function(event) {
|
|
if(event.type === "tm-scroll") {
|
|
return this.scrollIntoView(event.target);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
/*
|
|
Handle a scroll event hitting the page document
|
|
*/
|
|
PageScroller.prototype.scrollIntoView = function(element) {
|
|
var duration = $tw.utils.getAnimationDuration();
|
|
// Now get ready to scroll the body
|
|
this.cancelScroll();
|
|
this.startTime = Date.now();
|
|
var scrollPosition = $tw.utils.getScrollPosition();
|
|
// Get the client bounds of the element and adjust by the scroll position
|
|
var clientBounds = element.getBoundingClientRect(),
|
|
bounds = {
|
|
left: clientBounds.left + scrollPosition.x,
|
|
top: clientBounds.top + scrollPosition.y,
|
|
width: clientBounds.width,
|
|
height: clientBounds.height
|
|
};
|
|
// We'll consider the horizontal and vertical scroll directions separately via this function
|
|
// targetPos/targetSize - position and size of the target element
|
|
// currentPos/currentSize - position and size of the current scroll viewport
|
|
// returns: new position of the scroll viewport
|
|
var getEndPos = function(targetPos,targetSize,currentPos,currentSize) {
|
|
// If the target is entirely above/left of the current view, then scroll to its top/left
|
|
if((targetPos + targetSize) <= (currentPos + 50)) {
|
|
return targetPos;
|
|
// If the target is smaller than the window and the scroll position is too far up, then scroll till the target is at the bottom of the window
|
|
} else if(targetSize < currentSize && currentPos < (targetPos + targetSize - currentSize)) {
|
|
return targetPos + targetSize - currentSize;
|
|
// If the target is out of view below/right, then just scroll to the top/left
|
|
} else if(targetPos > (currentPos + currentSize - 50)) {
|
|
return targetPos;
|
|
// Otherwise, stay where we are
|
|
} else {
|
|
return currentPos;
|
|
}
|
|
},
|
|
endX = getEndPos(bounds.left,bounds.width,scrollPosition.x,window.innerWidth),
|
|
endY = getEndPos(bounds.top,bounds.height,scrollPosition.y,window.innerHeight);
|
|
// Only scroll if the position has changed, plus a special case that we won't scroll less than 50 pixels from the top of the window
|
|
if((endX !== scrollPosition.x || endY !== scrollPosition.y) && (scrollPosition.y !== 0 || endY > 50)) {
|
|
var self = this,
|
|
drawFrame;
|
|
drawFrame = function () {
|
|
var t;
|
|
if(duration <= 0) {
|
|
t = 1;
|
|
} else {
|
|
t = ((Date.now()) - self.startTime) / duration;
|
|
}
|
|
if(t >= 1) {
|
|
self.cancelScroll();
|
|
t = 1;
|
|
}
|
|
t = $tw.utils.slowInSlowOut(t);
|
|
window.scrollTo(scrollPosition.x + (endX - scrollPosition.x) * t,scrollPosition.y + (endY - scrollPosition.y) * t);
|
|
if(t < 1) {
|
|
self.idRequestFrame = self.requestAnimationFrame.call(window,drawFrame);
|
|
}
|
|
};
|
|
drawFrame();
|
|
}
|
|
};
|
|
|
|
exports.PageScroller = PageScroller;
|
|
|
|
})();
|